-
Notifications
You must be signed in to change notification settings - Fork 0
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
[DRAFT] Refcount stats across scopes #1
Conversation
Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
…cyTests Signed-off-by: James Buckland <[email protected]>
HeapRawStatDataAllocator still does heap allocation without namespace resolution Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
source/common/stats/BUILD
Outdated
@@ -19,6 +19,7 @@ envoy_cc_library( | |||
"//source/common/common:assert_lib", | |||
"//source/common/common:hash_lib", | |||
"//source/common/common:perf_annotation_lib", | |||
"//source/common/common:shared_memory_hash_set_lib", |
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.
test 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.
Looks awesome - here are some comments to start!
source/common/stats/stats_impl.cc
Outdated
@@ -149,13 +149,48 @@ bool TagExtractorImpl::extractTag(const std::string& stat_name, std::vector<Tag> | |||
return false; | |||
} | |||
|
|||
RawStatData* BlockRawStatDataAllocator::alloc(const std::string& name) { | |||
absl::string_view key = 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.
Why not just use name
directly throughout?
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.
name
comes in as a std::string&
and we want to be able to call things like .remove_suffix()
on it, which are absl::string_view
features.
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.
ahhh, makes sense. I didn't realize you were substringing it.
source/common/stats/stats_impl.h
Outdated
|
||
RawStatData* alloc(const std::string& name); | ||
void free(RawStatData& data); | ||
std::unique_ptr<RawStatDataSet> stats_set_; |
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.
Is there a reason we can't make this variable private?
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 think we can! I thought it needed to be used in versionHelper
, but I was able to rework that to need only the std::string
version number instead of the whole RawStatDataSet
itself.
@@ -84,8 +85,8 @@ SharedMemory& SharedMemory::initialize(uint32_t stats_set_size, Options& options | |||
} | |||
|
|||
// Stats::RawStatData must be naturally aligned for atomics to work properly. | |||
RELEASE_ASSERT((reinterpret_cast<uintptr_t>(shmem->stats_set_data_) % alignof(RawStatDataSet)) == | |||
0); | |||
RELEASE_ASSERT( |
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.
What changed here?
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.
RawStatDataSet
-> Stats::RawStatDataSet
, which pushed it over some character limit and reflowed the formatting.
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.
Ah, feel free to disregard.
source/server/hot_restart_impl.cc
Outdated
shmem_(SharedMemory::initialize(RawStatDataSet::numBytes(stats_set_options_), options)), | ||
shmem_( | ||
SharedMemory::initialize(Stats::RawStatDataSet::numBytes(stats_set_options_), options)), | ||
allocator_(stats_set_options_, options.restartEpoch() == 0, shmem_.stats_set_data_), |
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 will probably need to initialize this below inside the scope where lock
is created, which is where the stats set used to be initialized. allocator_
will probably need to be a unique_ptr as a result. This is because the lock protects the initialization. If you move it above to the initializer list, the lock won't be held while it's being constructed. Side note: are you familiar with the idea of a scope lock (std::unique_lock<Thread::BasicLockable>
)?
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.
This is a good catch. I reworked allocator_
to be a unique pointer and constructed it not-inline, and changed all references to allocator_.foo
to allocator_->foo
.
source/server/hot_restart_nop_impl.h
Outdated
calloc(SharedMemoryHashSet<Stats::RawStatData>::numBytes(options), num_stats)); | ||
stats_allocator_ = std::make_unique<Stats::BlockRawStatDataAllocator>(options, true, ptr_); | ||
} | ||
~HotRestartNopImpl() { ::free(ptr_); } |
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.
Be careful, here. I'd be sure that that stats_allocator_
doesn't attempt to write to this memory as it's destructing. This is an artifact of the C++ order of destruction where the destructor runs first, and then the member variables are destroyed. If this is a problem, we can modify the destructor to look like this:
~HotRestartNopImpl() {
stats_allocator_ = nullptr;
::free(ptr_);
}
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'll do this -- is this the kind of bug I can write a test for? Or is this just intuition that this could fail?
test/common/stats/stats_impl_test.cc
Outdated
@@ -466,5 +468,35 @@ TEST(TagProducerTest, CheckConstructor) { | |||
"No regex specified for tag specifier and no default regex for name: 'test_extractor'"); | |||
} | |||
|
|||
TEST(SomeTest, HotAllocConsistencyTest) { | |||
int max_stats_ = 16384; // ENVOY_DEFAULT_MAX_STATS |
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 want this to match that number, you should probably use the macro directly.
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'll include server/options_impl.h
and get access to it.
test/common/stats/stats_impl_test.cc
Outdated
SharedMemoryHashSetOptions options_ = Server::sharedMemHashOptions(max_stats_); | ||
uint8_t* ptr = static_cast<uint8_t*>( | ||
calloc(SharedMemoryHashSet<Stats::RawStatData>::numBytes(options_), max_stats_)); | ||
std::unique_ptr<RawStatDataSet> stats_set_ = |
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.
Since you have your fancy new block allocator, why not use it here? :) . Otherwise the test is really testing a reimplementation of your allocator rather than the allocator itself.
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. Rewrote to look like
TEST(SomeTest, HotAllocConsistencyTest) {
int max_stats_ = 16384; // ENVOY_DEFAULT_MAX_STATS
SharedMemoryHashSetOptions options_ = Server::sharedMemHashOptions(max_stats_);
uint8_t* ptr = static_cast<uint8_t*>(
calloc(SharedMemoryHashSet<Stats::RawStatData>::numBytes(options_), max_stats_));
Stats::BlockRawStatDataAllocator allocator =
Stats::BlockRawStatDataAllocator(options_, true, ptr);
auto data_1 = allocator.alloc("foo");
auto data_2 = allocator.alloc("foo");
EXPECT_EQ(data_1, data_2);
::free(ptr);
}
Signed-off-by: James Buckland <[email protected]>
and rework versionHelper to expect a string of the RawStatDataSet version instead of the whole set itself Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
…nter, so that it can be initialized after the locks are held Signed-off-by: James Buckland <[email protected]>
test/common/stats/stats_impl_test.cc
Outdated
@@ -466,5 +469,23 @@ TEST(TagProducerTest, CheckConstructor) { | |||
"No regex specified for tag specifier and no default regex for name: 'test_extractor'"); | |||
} | |||
|
|||
TEST(SomeTest, HotAllocConsistencyTest) { |
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.
@mrice32 I think I don't have a great way to test this twice, once in the context of injecting shared memory, and once in the context of injecting non-shared memory. Is there a test we can write to prove this works in the original worry case in envoyproxy#2453 ?
Signed-off-by: James Buckland <[email protected]>
since it is no longer used in shared memory only Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
able to be passed in by reference or left null for allocators which don't need it Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
…matting fixes Signed-off-by: James Buckland <[email protected]>
source/server/hot_restart_nop_impl.h
Outdated
ptr_ = static_cast<uint8_t*>( | ||
calloc(MemoryHashSet<Stats::RawStatData>::numBytes(options), num_stats)); | ||
stats_allocator_ = | ||
std::make_unique<Stats::BlockRawStatDataAllocator>(options, true, ptr_, &stat_lock_); |
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.
@mrice32 when you see new statLock / stat_lock_ objects in HotRestart, HotRestartImpl, HotRestartNopImpl, and HotRestart mock objects, it's because of this line. I wanted to create and use a lock mechanism even when the restart isn't hot.
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.
But why does it need to have its own accessor method?
@@ -13,11 +13,6 @@ | |||
#include "spdlog/spdlog.h" | |||
#include "tclap/CmdLine.h" | |||
|
|||
// Can be overridden at compile time | |||
#ifndef ENVOY_DEFAULT_MAX_STATS |
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.
@mrice32 I moved this to options_impl.h for visibility.
@@ -179,8 +179,8 @@ envoy_cc_library( | |||
) | |||
|
|||
envoy_cc_library( | |||
name = "shared_memory_hash_set_lib", |
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.
@mrice32 This is one of a few commits which rename SharedMemoryHashSet
to MemoryHashSet
, or shared_memory_hash_set
to memory_hash_set
, or sharedMemOptions
to memOptions
. I wanted to indicate that the MemoryHashSet doesn't need to be run on shared memory.
@@ -149,13 +149,55 @@ bool TagExtractorImpl::extractTag(const std::string& stat_name, std::vector<Tag> | |||
return false; | |||
} | |||
|
|||
RawStatData* BlockRawStatDataAllocator::alloc(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.
I moved a lot of these tests from hot_restart_impl_test.cc
since they are really unit tests on the allocator itself. A few stayed in hot_restart_impl_test.cc
as they tested behavior across hot restart.
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.
What tests are you referring to? This is an implementation file...?
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.
Wow, I don't know how this ended up here. I think I meant to say I moved these ::alloc and ::free functions from hot_restart_impl.cc.
@@ -111,120 +111,5 @@ TEST_F(HotRestartImplTest, crossAlloc) { | |||
EXPECT_EQ(stat5, stat5_prime); | |||
} | |||
|
|||
TEST_F(HotRestartImplTest, truncateKey) { |
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 moved a lot of these to stats_impl.cc
. See the other comment here: https://github.com/ambuc/envoy/pull/1/files#r182548087
source/server/hot_restart_impl.cc
Outdated
@@ -140,36 +139,10 @@ HotRestartImpl::HotRestartImpl(Options& options) | |||
|
|||
Stats::RawStatData* HotRestartImpl::alloc(const std::string& name) { | |||
// Try to find the existing slot in shared memory, otherwise allocate a new one. | |||
std::unique_lock<Thread::BasicLockable> lock(stat_lock_); |
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.
The whole functionality of HotRestartImpl::alloc
, including the lock, got moved up into BlockRawStatDataAllocator::alloc
. Same for ::free()
.
@@ -472,23 +445,25 @@ void HotRestartImpl::terminateParent() { | |||
void HotRestartImpl::shutdown() { socket_event_.reset(); } | |||
|
|||
std::string HotRestartImpl::version() { | |||
return versionHelper(shmem_.maxStats(), Stats::RawStatData::maxNameLength(), *stats_set_); |
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.
@mrice32 I wanted BlockRawStatDataAllocator's stats_set_
member variable to be private, so I ended up writing a function here [1] to just fetch the version as a string.
[1] https://github.com/ambuc/envoy/pull/1/files#diff-fb83459430ccfd2f0d934dcfacdbd9d1R399
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.
Seems reasonable to me.
|
||
return versionHelper(max_num_stats, max_stat_name_len, stats_set); |
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.
See the comment here https://github.com/ambuc/envoy/pull/1/files#r182549180, we can now pass the string version instead of the whole set by reference.
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.
SGTM.
@@ -204,12 +205,12 @@ class HotRestartImpl : public HotRestart, | |||
RpcBase* receiveRpc(bool block); | |||
void sendMessage(sockaddr_un& address, RpcBase& rpc); | |||
static std::string versionHelper(uint64_t max_num_stats, uint64_t max_stat_name_len, | |||
RawStatDataSet& stats_set); |
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.
source/server/hot_restart_nop_impl.h
Outdated
@@ -14,7 +17,18 @@ namespace Server { | |||
*/ | |||
class HotRestartNopImpl : public Server::HotRestart { | |||
public: | |||
HotRestartNopImpl() {} | |||
HotRestartNopImpl() { | |||
int num_stats = 100; |
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.
@mrice32 TODO(jbuckland) find a less arbitrary number for this. I seem to recall setting this to ENVOY_DEFAULT_MAX_STATS
caused testing to hang. What should we do here?
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.
This is not a test, this is the real application, so this must be pulled from the supplied command line options/default just like the hot restart implementation does. I would suggest supplying it via the constructor just like HotRestartImpl:
HotRestartImpl(Options& options);
@@ -13,11 +13,6 @@ | |||
#include "spdlog/spdlog.h" | |||
#include "tclap/CmdLine.h" | |||
|
|||
// Can be overridden at compile time | |||
#ifndef ENVOY_DEFAULT_MAX_STATS |
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.
Moved to options_impl.h
for visibility.
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.
Makes sense.
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 so far - left a few comments.
source/common/stats/stats_impl.h
Outdated
* @return BlockRawStatDataAllocator newly constructed BlockRawStatDataAllocator. | ||
*/ | ||
BlockRawStatDataAllocator(const MemoryHashSetOptions& options, bool init, uint8_t* memory, | ||
Thread::BasicLockable* stat_lock) |
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.
Just a note: if we decide that we want this in all cases, we might consider making this a reference. Or if we want this class to own it, we could pass in a unique_ptr and check that it's not nullptr.
source/server/hot_restart_impl.cc
Outdated
std::unique_lock<Thread::BasicLockable> lock(stat_lock_); | ||
stats_set_.reset(new RawStatDataSet(stats_set_options_, options.restartEpoch() == 0, | ||
shmem_.stats_set_data_)); | ||
allocator_ = std::make_unique<Stats::BlockRawStatDataAllocator>( |
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 you get rid of the locking here?
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 moved the locking functionality inside the BlockRawStatDataAllocator itself, which is why it gets initialized with a reference to a lock.
source/server/hot_restart_impl.cc
Outdated
ASSERT(key_removed); | ||
memset(&data, 0, Stats::RawStatData::size()); | ||
} | ||
void HotRestartImpl::free(Stats::RawStatData& data) { allocator_->free(data); } |
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 are we still forwarding these calls?
source/server/hot_restart_nop_impl.h
Outdated
@@ -14,7 +17,18 @@ namespace Server { | |||
*/ | |||
class HotRestartNopImpl : public Server::HotRestart { | |||
public: | |||
HotRestartNopImpl() {} | |||
HotRestartNopImpl() { | |||
int num_stats = 100; |
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.
This is not a test, this is the real application, so this must be pulled from the supplied command line options/default just like the hot restart implementation does. I would suggest supplying it via the constructor just like HotRestartImpl:
HotRestartImpl(Options& options);
source/server/hot_restart_nop_impl.h
Outdated
ptr_ = static_cast<uint8_t*>( | ||
calloc(MemoryHashSet<Stats::RawStatData>::numBytes(options), num_stats)); | ||
stats_allocator_ = | ||
std::make_unique<Stats::BlockRawStatDataAllocator>(options, true, ptr_, &stat_lock_); |
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.
But why does it need to have its own accessor method?
test/common/stats/stats_impl_test.cc
Outdated
void setup(int num_stats) { | ||
Stats::RawStatData::configureForTestsOnly(options_); | ||
MemoryHashSetOptions memory_hash_set_options_ = Server::memHashOptions(num_stats); | ||
ptr_ = static_cast<uint8_t*>( |
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.
We should probably move to the way Josh allocates the memory in his tests - see here. Something like:
uint32_t num_bytes = MemoryHashSet<Stats::RawStatData>::numBytes(memory_hash_set_options_);
ptr_ = new uint8_t[num_bytes];
Side note: why are you multiplying the number of bytes times the number of stats? That may be the source of your issues - you're squaring the capacity.
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.
Great catch! I've updated 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.
Just kidding, I updated this for HotRestartNopImpl. I'll update it here too.
|
||
return versionHelper(max_num_stats, max_stat_name_len, stats_set); |
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.
SGTM.
…tics Signed-off-by: James Buckland <[email protected]>
…ly them with memory, have unit tests, and are not child classes of RawStatDataAllocator instead, they are called (in a few places) as restart_obj_.statsAllocator().alloc() or restart_obj.statsAllocator().free() Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
@@ -5,6 +5,9 @@ | |||
#include "envoy/server/hot_restart.h" | |||
|
|||
#include "common/common/thread.h" | |||
#include "common/stats/stats_impl.h" | |||
|
|||
#include "server/hot_restart_impl.h" |
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 does this include hot_restart_impl.h
?
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 needs blockMemHashOptions
from there.
@@ -13,11 +13,6 @@ | |||
#include "spdlog/spdlog.h" | |||
#include "tclap/CmdLine.h" | |||
|
|||
// Can be overridden at compile time | |||
#ifndef ENVOY_DEFAULT_MAX_STATS |
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.
Makes sense.
stat2 = nullptr; | ||
stat4 = nullptr; | ||
|
||
EXPECT_CALL(options_, restartEpoch()).WillRepeatedly(Return(1)); |
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 is this here and why would the nopimpl call this method?
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, this is leftover from the sameAlloc
function when it was being called on a more tightly coupled instance of HotRestart.
@@ -149,13 +149,55 @@ bool TagExtractorImpl::extractTag(const std::string& stat_name, std::vector<Tag> | |||
return false; | |||
} | |||
|
|||
RawStatData* BlockRawStatDataAllocator::alloc(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.
What tests are you referring to? This is an implementation file...?
@@ -472,23 +445,25 @@ void HotRestartImpl::terminateParent() { | |||
void HotRestartImpl::shutdown() { socket_event_.reset(); } | |||
|
|||
std::string HotRestartImpl::version() { | |||
return versionHelper(shmem_.maxStats(), Stats::RawStatData::maxNameLength(), *stats_set_); |
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.
Seems reasonable to me.
Signed-off-by: James Buckland <[email protected]>
…instead of taking pointer to it Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
… for proper scope testing Signed-off-by: James Buckland <[email protected]>
Signed-off-by: James Buckland <[email protected]>
* This is a heap test allocator that works similar to how the shared memory allocator works in | ||
* terms of reference counting, etc. | ||
*/ | ||
class TestAllocator : public RawStatDataAllocator { |
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.
@mrice32 I was able to completely swap in this TestAllocator for a real, functional BlockRawStatDataAllocator, which ends up running the below suite of namespace resolution tests.
Closed in favor of envoyproxy#3163. |
…ot restart (#3249) Simpler solution to issue #2453 than pull #3163, continuing draft work in ambuc#1 and ambuc#2. Summary of changes: adds an unordered_map named stats_set_ as a member variable of HeapRawStatDataAllocator, and implements reference counting / dedup on allocated stats. Risk Level: Low. Testing: Add a test to stats_impl_test. Passes bazel test test/.... Docs Changes: N/A Release Notes: This is user-facing in that non-hot restart stat allocation now resolves namespace properly, but no effect on user configs. Fixes: #2453 Signed-off-by: James Buckland <[email protected]>
…ardown. (envoyproxy#4940) server_fuzz_test indicated the below crash, where the DispatcherImpl teardown releases some upstream client SSL related objects that then needs SecretManagerImpl to unregister. Previously, this was already destructed by time we were in ~DispatcherImpl(), this PR reorders. #0 0xc1e826 in size /usr/local/include/c++/v1/__hash_table:809:55 #1 0xc1e826 in bucket_count /usr/local/include/c++/v1/__hash_table:1197 #2 0xc1e826 in std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, void*>*> std::__1::__hash_table<std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::__unordered_map_hasher<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::__unordered_map_equal<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::allocator<std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> > > >::find<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /usr/local/include/c++/v1/__hash_table:2334 #3 0xc1e278 in unsigned long std::__1::__hash_table<std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::__unordered_map_hasher<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::__unordered_map_equal<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::allocator<std::__1::__hash_value_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::weak_ptr<Envoy::Secret::TlsCertificateSdsApi> > > >::__erase_unique<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /usr/local/include/c++/v1/__hash_table:2510:20 #4 0xc1def6 in erase /usr/local/include/c++/v1/unordered_map:1156:59 #5 0xc1def6 in Envoy::Secret::SecretManagerImpl::DynamicSecretProviders<Envoy::Secret::TlsCertificateSdsApi>::removeDynamicSecretProvider(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /bazel-out/k8-fastbuild/bin/source/common/secret/_virtual_includes/secret_manager_impl_lib/common/secret/secret_manager_impl.h:75 #6 0x724aa9 in Envoy::Cleanup::~Cleanup() /bazel-out/k8-fastbuild/bin/source/common/common/_virtual_includes/cleanup_lib/common/common/cleanup.h:11:16 #7 0xc1ff33 in Envoy::Secret::SdsApi::~SdsApi() /bazel-out/k8-fastbuild/bin/source/common/secret/_virtual_includes/sds_api_lib/common/secret/sds_api.h:29:7 #8 0xc188a0 in __release_shared /usr/local/include/c++/v1/memory:3530:9 #9 0xc188a0 in __release_shared /usr/local/include/c++/v1/memory:3572 #10 0xc188a0 in std::__1::shared_ptr<Envoy::Secret::SecretProvider<Envoy::Ssl::TlsCertificateConfig> >::~shared_ptr() /usr/local/include/c++/v1/memory:4508 #11 0x149c922 in Envoy::Ssl::ContextConfigImpl::~ContextConfigImpl() /source/common/ssl/context_config_impl.cc:117:1 #12 0x14a0d8f in Envoy::Ssl::ClientContextConfigImpl::~ClientContextConfigImpl() /bazel-out/k8-fastbuild/bin/source/common/ssl/_virtual_includes/context_config_lib/common/ssl/context_config_impl.h:91:7 #13 0x14a0dc8 in Envoy::Ssl::ClientContextConfigImpl::~ClientContextConfigImpl() /bazel-out/k8-fastbuild/bin/source/common/ssl/_virtual_includes/context_config_lib/common/ssl/context_config_impl.h:91:7 #14 0x149815b in operator() /usr/local/include/c++/v1/memory:2325:5 #15 0x149815b in reset /usr/local/include/c++/v1/memory:2638 #16 0x149815b in ~unique_ptr /usr/local/include/c++/v1/memory:2592 #17 0x149815b in Envoy::Ssl::ClientSslSocketFactory::~ClientSslSocketFactory() /bazel-out/k8-fastbuild/bin/source/common/ssl/_virtual_includes/ssl_socket_lib/common/ssl/ssl_socket.h:83 #18 0x14981c8 in Envoy::Ssl::ClientSslSocketFactory::~ClientSslSocketFactory() /bazel-out/k8-fastbuild/bin/source/common/ssl/_virtual_includes/ssl_socket_lib/common/ssl/ssl_socket.h:83:7 #19 0x1362caf in operator() /usr/local/include/c++/v1/memory:2325:5 #20 0x1362caf in reset /usr/local/include/c++/v1/memory:2638 #21 0x1362caf in ~unique_ptr /usr/local/include/c++/v1/memory:2592 #22 0x1362caf in Envoy::Upstream::ClusterInfoImpl::~ClusterInfoImpl() /bazel-out/k8-fastbuild/bin/source/common/upstream/_virtual_includes/upstream_includes/common/upstream/upstream_impl.h:362 #23 0x1362d28 in Envoy::Upstream::ClusterInfoImpl::~ClusterInfoImpl() /bazel-out/k8-fastbuild/bin/source/common/upstream/_virtual_includes/upstream_includes/common/upstream/upstream_impl.h:362:7 #24 0x66e560 in __release_shared /usr/local/include/c++/v1/memory:3530:9 #25 0x66e560 in __release_shared /usr/local/include/c++/v1/memory:3572 #26 0x66e560 in std::__1::shared_ptr<Envoy::Upstream::ClusterInfo const>::~shared_ptr() /usr/local/include/c++/v1/memory:4508 #27 0x13621bf in Envoy::Upstream::HostImpl::~HostImpl() /bazel-out/k8-fastbuild/bin/source/common/upstream/_virtual_includes/upstream_includes/common/upstream/upstream_impl.h:156:7 #28 0x13621f8 in Envoy::Upstream::HostImpl::~HostImpl() /bazel-out/k8-fastbuild/bin/source/common/upstream/_virtual_includes/upstream_includes/common/upstream/upstream_impl.h:156:7 #29 0x66e650 in __release_shared /usr/local/include/c++/v1/memory:3530:9 #30 0x66e650 in __release_shared /usr/local/include/c++/v1/memory:3572 #31 0x66e650 in std::__1::shared_ptr<Envoy::Upstream::HostDescription const>::~shared_ptr() /usr/local/include/c++/v1/memory:4508 #32 0x13b20c3 in Envoy::Http::CodecClient::~CodecClient() /source/common/http/codec_client.cc:38:30 #33 0x13b2258 in Envoy::Http::CodecClientProd::~CodecClientProd() /bazel-out/k8-fastbuild/bin/source/common/http/_virtual_includes/codec_client_lib/common/http/codec_client.h:229:7 #34 0x751de6 in operator() /usr/local/include/c++/v1/memory:2325:5 #35 0x751de6 in reset /usr/local/include/c++/v1/memory:2638 #36 0x751de6 in ~unique_ptr /usr/local/include/c++/v1/memory:2592 #37 0x751de6 in destroy /usr/local/include/c++/v1/memory:1867 #38 0x751de6 in __destroy<std::__1::unique_ptr<Envoy::Event::DeferredDeletable, std::__1::default_delete<Envoy::Event::DeferredDeletable> > > /usr/local/include/c++/v1/memory:1729 #39 0x751de6 in destroy<std::__1::unique_ptr<Envoy::Event::DeferredDeletable, std::__1::default_delete<Envoy::Event::DeferredDeletable> > > /usr/local/include/c++/v1/memory:1597 #40 0x751de6 in __destruct_at_end /usr/local/include/c++/v1/vector:422 #41 0x751de6 in clear /usr/local/include/c++/v1/vector:365 #42 0x751de6 in std::__1::__vector_base<std::__1::unique_ptr<Envoy::Event::DeferredDeletable, std::__1::default_delete<Envoy::Event::DeferredDeletable> >, std::__1::allocator<std::__1::unique_ptr<Envoy::Event::DeferredDeletable, std::__1::default_delete<Envoy::Event::DeferredDeletable> > > >::~__vector_base() /usr/local/include/c++/v1/vector:459 #43 0x74d1aa in ~vector /usr/local/include/c++/v1/vector:551:5 #44 0x74d1aa in Envoy::Event::DispatcherImpl::~DispatcherImpl() /source/common/event/dispatcher_impl.cc:41 #45 0x74d658 in Envoy::Event::DispatcherImpl::~DispatcherImpl() /source/common/event/dispatcher_impl.cc:41:35 #46 0x697b76 in operator() /usr/local/include/c++/v1/memory:2325:5 #47 0x697b76 in reset /usr/local/include/c++/v1/memory:2638 #48 0x697b76 in ~unique_ptr /usr/local/include/c++/v1/memory:2592 #49 0x697b76 in Envoy::Server::InstanceImpl::InstanceImpl(Envoy::Server::Options&, Envoy::Event::TimeSystem&, std::__1::shared_ptr<Envoy::Network::Address::Instance const>, Envoy::TestHooks&, Envoy::Server::HotRestart&, Envoy::Stats::StoreRoot&, Envoy::Thread::BasicLockable&, Envoy::Server::ComponentFactory&, std::__1::unique_ptr<Envoy::Runtime::RandomGenerator, std::__1::default_delete<Envoy::Runtime::RandomGenerator> >&&, Envoy::ThreadLocal::Instance&) /source/server/server.cc:92 #50 0x586026 in make_unique<Envoy::Server::InstanceImpl, testing::NiceMock<Envoy::Server::MockOptions> &, Envoy::Event::TestTimeSystem &, std::__1::shared_ptr<Envoy::Network::Address::Ipv4Instance>, Envoy::DefaultTestHooks &, testing::NiceMock<Envoy::Server::MockHotRestart> &, Envoy::Stats::TestIsolatedStoreImpl &, Envoy::Thread::MutexBasicLockable &, Envoy::Server::TestComponentFactory &, std::__1::unique_ptr<Envoy::Runtime::RandomGeneratorImpl, std::__1::default_delete<Envoy::Runtime::RandomGeneratorImpl> >, Envoy::ThreadLocal::InstanceImpl &> /usr/local/include/c++/v1/memory:3118:32 #51 0x586026 in Envoy::Server::TestOneProtoInput(envoy::config::bootstrap::v2::Bootstrap const&) /test/server/server_fuzz_test.cc:78 Fixes oss-fuzz issue https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11231 Risk Level: Low Testing: Corpus entry added. It's pretty hard to build regressions for this kind of destruction ordering, so relying on server_fuzz_test + corpus. Signed-off-by: Harvey Tuch <[email protected]>
Provide the HTTP path normalization per RFC 3986 (sans case normalization). This addresses CVE-2019-9901. The config HttpConnectionManager.normalize_path needs to be set for each HCM configuration to enable (default is off). There is also a runtime optione http_connection_manager.normalize_path to change this default when not set in HCM. Risk level: Low Testing: New unit and integration tests added. Signed-off-by: Yuchen Dai <[email protected]> Signed-off-by: Harvey Tuch <[email protected]>
Draft solution to envoyproxy#2453