Skip to content

Commit

Permalink
Add method to check whether Deferred Stats are present. (envoyproxy#3…
Browse files Browse the repository at this point in the history
…3877)

Commit Message: Add method to check whether Deferred Stats are present.
Risk Level: low
Testing: unit
Docs Changes: none
Release Notes: none

Signed-off-by: Paul Ogilby <[email protected]>
  • Loading branch information
paul-r-gall authored May 1, 2024
1 parent 65dc162 commit c3b0ea0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
20 changes: 19 additions & 1 deletion envoy/stats/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,20 @@ Envoy
*/
template <typename StatsStructType> class DeferredCreationCompatibleInterface {
public:
// Helper function to get-or-create and return the StatsStructType object.
/**
* Returns an already existing StatsStructType, or creates a new one and returns it.
*
* @return The new or already existing StatsStructType.
*/
virtual StatsStructType& getOrCreate() PURE;

/**
* Returns whether or not the underlying stats have been initialized yet.
*
* @return If the underlying stats have been initialized.
*/
virtual bool isPresent() const PURE;

virtual ~DeferredCreationCompatibleInterface() = default;
};

Expand All @@ -250,6 +261,13 @@ template <typename StatsStructType> class DeferredCreationCompatibleStats {
inline StatsStructType* operator->() { return &data_->getOrCreate(); };
inline StatsStructType& operator*() { return data_->getOrCreate(); };

/**
* Returns whether or not the underlying data_ has been initialized yet.
*
* @return If the underlying data_ has been initialized.
*/
bool isPresent() const { return data_->isPresent(); }

private:
std::unique_ptr<DeferredCreationCompatibleInterface<StatsStructType>> data_;
};
Expand Down
13 changes: 13 additions & 0 deletions source/common/common/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ class AtomicPtrArray : NonCopyable {
return atomic_ref.load();
}

/**
* Returns whether the underlying pointer at the index is null.
*
* @param index the Index to look up.
* @return true if the underlying pointer at the index is null.
*/
bool isNull(uint32_t index) const { return data_[index].load() == nullptr; }

private:
std::atomic<T*> data_[size];
absl::Mutex mutex_;
Expand Down Expand Up @@ -166,6 +174,11 @@ class AtomicPtr : private AtomicPtrArray<T, 1, alloc_mode> {
* @return The new or already-existing T*, possibly nullptr if make_object returns nullptr.
*/
T* get(const MakeObject& make_object) { return BaseClass::get(0, make_object); }

/**
* @return true if the underlying pointer is null.
*/
bool isNull() const { return BaseClass::isNull(0); }
};

// We use platform-specific functions to determine whether the current thread is
Expand Down
2 changes: 2 additions & 0 deletions source/common/stats/deferred_creation.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class DeferredStats : public DeferredCreationCompatibleInterface<StatsStructType
}
}
inline StatsStructType& getOrCreate() override { return getOrCreateHelper(); }
bool isPresent() const override { return !internal_stats_.isNull(); }

private:
// We can't call getOrCreate directly from constructor, otherwise the compiler complains about
Expand Down Expand Up @@ -92,6 +93,7 @@ class DirectStats : public DeferredCreationCompatibleInterface<StatsStructType>
DirectStats(const typename StatsStructType::StatNameType& stat_names, Stats::Scope& scope)
: stats_(stat_names, scope) {}
inline StatsStructType& getOrCreate() override { return stats_; }
bool isPresent() const override { return true; }

private:
StatsStructType stats_;
Expand Down
6 changes: 6 additions & 0 deletions test/common/stats/deferred_creation_stats_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ TEST_F(DeferredCreationStatsTest, StatsGoneWithScope) {
MyStats x = createDeferredCompatibleStats<AwesomeStats>(scope, stats_names_, true);
MyStats y = createDeferredCompatibleStats<AwesomeStats>(scope, stats_names_, true);
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized")->value(), 0);
EXPECT_FALSE(x.isPresent());
x->foo_.inc();
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized")->value(), 1);
EXPECT_TRUE(x.isPresent());
EXPECT_FALSE(y.isPresent());
EXPECT_EQ(x->foo_.value(), 1);
EXPECT_EQ(y->foo_.value(), 1);
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized")->value(), 2);
EXPECT_TRUE(y.isPresent());
}
// Deleted as scope deleted.
EXPECT_EQ(TestUtility::findCounter(store_, "bluh.foo"), nullptr);
Expand All @@ -68,11 +72,13 @@ TEST_F(DeferredCreationStatsTest, StatsGoneWithScope) {
ScopeSharedPtr scope = store_.createScope("bluh");
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized"), nullptr);
MyStats x = createDeferredCompatibleStats<AwesomeStats>(scope, stats_names_, true);
EXPECT_FALSE(x.isPresent());
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized")->value(), 0);
// Previous data is gone, as scope_v2 and scope_1's lifecycle do not overlap.
EXPECT_EQ(x->foo_.value(), 0);
// Initialized now.
EXPECT_EQ(TestUtility::findGauge(store_, "bluh.AwesomeStats.initialized")->value(), 1);
EXPECT_TRUE(x.isPresent());
}
}

Expand Down

0 comments on commit c3b0ea0

Please sign in to comment.