-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stats: refactor to enable non-hot-restart stats to have distinct representation from hot-restart stats. #3606
stats: refactor to enable non-hot-restart stats to have distinct representation from hot-restart stats. #3606
Conversation
…network issues when running under docker. Signed-off-by: Joshua Marantz <jmarantz@google.com>
…istinct representations ot be created for non-hot-restart case. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
…-alloc case. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Ready for a look I think. |
…alStore::counter() and gauge(). Signed-off-by: Joshua Marantz <jmarantz@google.com>
@ggreenway do you have time to take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good on first pass! A few comments.
include/envoy/stats/stats.h
Outdated
*/ | ||
virtual RawStatData* alloc(const std::string& name) PURE; | ||
virtual Counter* makeCounter(const std::string& name, std::string& tag_extracted_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we removed the free()
, but we're still returning raw pointers. Can you document the ownership model? How is the StatDataAllocator
informed of when the stat is no longer needed by the caller? Is the user allowed to just delete the raw pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point here, and I think my design here needs a bit of rethinking in the context of how a caller would free stuff. The other comments I'll address later, and I'm flipping back to WIP-mode while I think about this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this was easy to deal with by just returning a shared_ptr at this level.
include/envoy/stats/stats.h
Outdated
*/ | ||
class RawStatDataAllocator { | ||
class StatDataAllocator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this is a general stat factory class that determines the impl
for each type of stat (and how it is allocated). If it is able to choose the representation for gauges and counters, why not also allow it to make histograms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added TODO -- making a parallel path for histograms would require moving the histogram impl out of thread_local_store and into stats_impl, which seems OK to me, but not in this PR. @ramaraochavali @mattklein123 WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmarantz originally I have added it to Stats_impl only. But later moved to thread_local_store based on @mattklein123 suggestion. I think it is ok to bring it back to stats impl.
// result, creating it with the heap allocator. | ||
template <class StatType> | ||
StatType& | ||
safeMakeStat(const std::string& name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add more documentation here about each argument. I'm only asking because the signature is reasonably complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I left some. I'm not sure it's super-illuminating as the semantics around tls_are rather complex :)
|
||
// If we have a valid cache entry, return it. | ||
if (tls_ref && *tls_ref) { | ||
return **tls_ref; | ||
} | ||
|
||
// We must now look in the central store so we must be locked. We grab a reference to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we remove this comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch; replaced.
include/envoy/stats/stats.h
Outdated
@@ -408,25 +408,33 @@ typedef std::unique_ptr<StoreRoot> StoreRootPtr; | |||
struct RawStatData; | |||
|
|||
/** | |||
* Abstract interface for allocating a RawStatData. | |||
* Abstract interface for allocating statistics. Alternate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove Alternate
since the interface doesn't impose a default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Signed-off-by: Joshua Marantz <jmarantz@google.com>
I am swamped right now; not sure that I'll have time to review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM other than one minor comment about the interface.
include/envoy/stats/stats.h
Outdated
*/ | ||
virtual RawStatData* alloc(const std::string& name) PURE; | ||
virtual CounterSharedPtr makeCounter(const std::string& name, std::string& tag_extracted_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tag_extracted_name
and tags
are passed as references not so they can be modified and read by the caller, but so that they can be moved. I think a better way to communicate this in the interface is by making them rvalue references (for example: std::string&& tag_extracted_name
), which will force all callers to wrap them in std::move()
or pass an actual rvalue.
Also, the interface should document that if the returned CounterSharedPtr is nullptr
, then these objects will not be moved/modified (we assume this at the callsite).
Similar comments for makeGauge()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Signed-off-by: Joshua Marantz <jmarantz@google.com>
include/envoy/stats/stats.h
Outdated
*/ | ||
virtual void free(RawStatData& data) PURE; | ||
virtual GaugeSharedPtr makeGauge(const std::string& name, std::string&& tag_extracted_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also document when these these rvalue references will be moved and when they will not (if allocation fails, they will not be moved, so that they may be used again by the caller).
Signed-off-by: Joshua Marantz <jmarantz@google.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One tiny nit. Sorry I thought I could power through this but this is a morning review. Will do first thing.
include/envoy/stats/stats.h
Outdated
* @param name the full name of the stat. | ||
* @param tag_extracted_name the name of the stat with tag-values stripped out. | ||
* @param tags the extracted tag values. | ||
* @return Counter* a counter, or nullptr if allocation failed, in which case tag_extracted_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: doc comment out of date, same below
Signed-off-by: Joshua Marantz <jmarantz@google.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet! LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. Nice cleanup. One question on readability.
@@ -225,6 +225,27 @@ class ThreadLocalStoreImpl : Logger::Loggable<Logger::Id::stats>, public StoreRo | |||
Histogram& histogram(const std::string& name) override; | |||
Histogram& tlsHistogram(const std::string& name, ParentHistogramImpl& parent) override; | |||
|
|||
template <class StatType> | |||
using MakeStatFn = std::shared_ptr<StatType> (StatDataAllocator::*)( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This type of function pointer syntax took me by surprise and I suspect most people are not familiar with it. Is there any more readable way of doing this? Potentially a normal lambda that is passed an instance of StatDataAllocator? This is not a big deal, just throwing it out there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can use std::function but I would have to make static method intermediates which I think is less readable.
In the past I have added macros for defining and calling pointer to member functions, which helps a bit I think. That's my preferred option. WDYT?
There is also std::invoke, which I had never used before. But I wasn't about to get that to with and I didn't think it was all that readable either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can use std::function but I would have to make static method intermediates which I think is less readable.
In the past I have added macros for defining and calling pointer to member functions, which helps a bit I think. That's my preferred option. WDYT?
There is also std::invoke, which I had never used before. But I wasn't about to get that to with and I didn't think it was all that readable either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to use pointer to member function, I think macros are the preferred method for readability.
Why would you need static intermediates to use std::function? Can't you capture 'this' in the closure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right; I don't need a static intermediary, but I think the way the code is structured I do need an intermediate closure, because I'm not starting with 'this', I'm starting with two alternate allocators. I do have that working -- it's a little messy IMO -- and I'll push that for reference, and then I'll push the version where I use pointer to member functions, but via macros, and I'm fine with either of those.
…ction. Signed-off-by: Joshua Marantz <jmarantz@google.com>
…ros to aid readability. Signed-off-by: Joshua Marantz <jmarantz@google.com>
OK ptal at the two options: Use std::function (requires an inline intermediary): 3c75f26 Use pointer-to-member function, with macros to aid readability (current state of PR). I'm happy to go with either. |
I have a slight preference for the std::function version, but I think either is a big improvement. @ggreenway any preference? |
I also have a slight preference for the std::function version. I think fewer people will be confused by it; pointer to member function is an infrequently used language feature. |
…with macros to aid readability." This reverts commit b9eee85. Signed-off-by: Joshua Marantz <jmarantz@google.com>
std::function version is fine with me, that is now the state of this PR. |
Description:
This PR does some refactoring to make it easier to create an alternate stats representation for the non-hot-restart case. Note that it does not actually do that: just makes it easier by virtualizing makeCounter and makeGauge.
See #3585 for more discussion.
Risk Level: Medium
Testing: //test/...