Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions envoy/stats/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ envoy_cc_library(
envoy_cc_library(
name = "symbol_table_interface",
hdrs = ["symbol_table.h"],
external_deps = ["abseil_inlined_vector"],
deps = [
"//source/common/common:hash_lib",
],
)

envoy_cc_library(
Expand Down
227 changes: 6 additions & 221 deletions envoy/stats/symbol_table.h
Original file line number Diff line number Diff line change
@@ -1,235 +1,20 @@
#pragma once

#include <functional>
#include <memory>
#include <utility>
#include <vector>

#include "envoy/common/pure.h"

#include "absl/container/inlined_vector.h"
#include "absl/strings/string_view.h"

namespace Envoy {
namespace Stats {

/**
* Runtime representation of an encoded stat name. This is predeclared only in
* the interface without abstract methods, because (a) the underlying class
* representation is common to both implementations of SymbolTable, and (b)
* we do not want or need the overhead of a vptr per StatName. The common
* declaration for StatName is in source/common/stats/symbol_table_impl.h
*/
class StatName;
using StatNameVec = absl::InlinedVector<StatName, 8>;

class StatNameList;
class StatNameSet;

using StatNameSetPtr = std::unique_ptr<StatNameSet>;
// Forward declarations for the symbol table classes. See
// source/common/stats/symbol_table_impl.h" for the class definitions.

/**
* Holds a range of indexes indicating which parts of a stat-name are
* dynamic. This is used to transfer stats from hot-restart parent to child,
* retaining the same name structure.
* Runtime representation of an encoded stat name.
*/
using DynamicSpan = std::pair<uint32_t, uint32_t>;
using DynamicSpans = std::vector<DynamicSpan>;
class StatName;

/**
* SymbolTable manages a namespace optimized for stat names, exploiting their
* typical composition from "."-separated tokens, with a significant overlap
* between the tokens. The interface is designed to balance optimal storage
* at scale with hiding details from users. We seek to provide the most abstract
* interface possible that avoids adding per-stat overhead or taking locks in
* the hot path.
* Holds a set of symbols used to compose hierarhical names.
*/
class SymbolTable {
public:
/**
* Efficient byte-encoded storage of an array of tokens. The most common
* tokens are typically < 127, and are represented directly. tokens >= 128
* spill into the next byte, allowing for tokens of arbitrary numeric value to
* be stored. As long as the most common tokens are low-valued, the
* representation is space-efficient. This scheme is similar to UTF-8. The
* token ordering is dependent on the order in which stat-names are encoded
* into the SymbolTable, which will not be optimal, but in practice appears
* to be pretty good.
*
* This is exposed in the interface for the benefit of join(), which is
* used in the hot-path to append two stat-names into a temp without taking
* locks. This is used then in thread-local cache lookup, so that once warm,
* no locks are taken when looking up stats.
*/
using Storage = uint8_t[];
using StoragePtr = std::unique_ptr<Storage>;

virtual ~SymbolTable() = default;

/**
* @return uint64_t the number of symbols in the symbol table.
*/
virtual uint64_t numSymbols() const PURE;

/**
* Decodes a vector of symbols back into its period-delimited stat name. If
Comment thread
jmarantz marked this conversation as resolved.
* decoding fails on any part of the symbol_vec, we release_assert and crash,
* since this should never happen, and we don't want to continue running
* with a corrupt stats set.
*
* @param stat_name the stat name.
* @return std::string stringified stat_name.
*/
virtual std::string toString(const StatName& stat_name) const PURE;

/**
* Determines whether one StatName lexically precedes another. Note that
* the lexical order may not exactly match the lexical order of the
* elaborated strings. For example, stat-name of "-.-" would lexically
* sort after "---" but when encoded as a StatName would come lexically
* earlier. In practice this is unlikely to matter as those are not
* reasonable names for Envoy stats.
*
* Note that this operation has to be performed with the context of the
* SymbolTable so that the individual Symbol objects can be converted
* into strings for lexical comparison.
*
* @param a the first stat name
* @param b the second stat name
* @return bool true if a lexically precedes b.
*/
virtual bool lessThan(const StatName& a, const StatName& b) const PURE;

/**
* Joins two or more StatNames. For example if we have StatNames for {"a.b",
* "c.d", "e.f"} then the joined stat-name matches "a.b.c.d.e.f". The
* advantage of using this representation is that it avoids having to
* decode/encode into the elaborated form, and does not require locking the
* SymbolTable.
*
* Note that this method does not bump reference counts on the referenced
* Symbols in the SymbolTable, so it's only valid as long for the lifetime of
* the joined StatNames.
*
* This is intended for use doing cached name lookups of scoped stats, where
* the scope prefix and the names to combine it with are already in StatName
* form. Using this class, they can be combined without accessing the
* SymbolTable or, in particular, taking its lock.
*
* @param stat_names the names to join.
* @return Storage allocated for the joined name.
*/
virtual StoragePtr join(const StatNameVec& stat_names) const PURE;

/**
* Populates a StatNameList from a list of encodings. This is not done at
* construction time to enable StatNameList to be instantiated directly in
* a class that doesn't have a live SymbolTable when it is constructed.
*
* @param names A pointer to the first name in an array, allocated by the caller.
* @param num_names The number of names.
* @param list The StatNameList representing the stat names.
*/
virtual void populateList(const StatName* names, uint32_t num_names, StatNameList& list) PURE;

#ifndef ENVOY_CONFIG_COVERAGE
virtual void debugPrint() const PURE;
#endif

using RecentLookupsFn = std::function<void(absl::string_view, uint64_t)>;

/**
* Calls the provided function with the name of the most recently looked-up
* symbols, including lookups on any StatNameSets, and with a count of
* the recent lookups on that symbol.
*
* @param iter the function to call for every recent item.
*/
virtual uint64_t getRecentLookups(const RecentLookupsFn& iter) const PURE;

/**
* Clears the recent-lookups structures.
*/
virtual void clearRecentLookups() PURE;

/**
* Sets the recent-lookup capacity.
*/
virtual void setRecentLookupCapacity(uint64_t capacity) PURE;

/**
* @return The configured recent-lookup tracking capacity.
*/
virtual uint64_t recentLookupCapacity() const PURE;

/**
* Creates a StatNameSet.
*
* @param name the name of the set.
* @return the set.
*/
virtual StatNameSetPtr makeSet(absl::string_view name) PURE;

/**
* Identifies the dynamic components of a stat_name into an array of integer
* pairs, indicating the begin/end of spans of tokens in the stat-name that
* are created from StatNameDynamicStore or StatNameDynamicPool.
*
* This can be used to reconstruct the same exact StatNames in
* StatNames::mergeStats(), to enable stat continuity across hot-restart.
*
* @param stat_name the input stat name.
* @return the array of pairs indicating the bounds.
*/
virtual DynamicSpans getDynamicSpans(StatName stat_name) const PURE;

private:
friend struct HeapStatData;
friend class StatNameDynamicStorage;
friend class StatNameStorage;
friend class StatNameList;
friend class StatNameSet;

// The following methods are private, but are called by friend classes
// StatNameStorage and StatNameList, which must be friendly with SymbolTable
// in order to manage the reference-counted symbols they own.

/**
* Since SymbolTable does manual reference counting, a client of SymbolTable
* must manually call free(symbol_vec) when it is freeing the backing store
* for a StatName. This way, the symbol table will grow and shrink
* dynamically, instead of being write-only.
*
* @param stat_name the stat name.
*/
virtual void free(const StatName& stat_name) PURE;

/**
* StatName backing-store can be managed by callers in a variety of ways
* to minimize overhead. But any persistent reference to a StatName needs
* to hold onto its own reference-counts for all symbols. This method
* helps callers ensure the symbol-storage is maintained for the lifetime
* of a reference.
*
* @param stat_name the stat name.
*/
virtual void incRefCount(const StatName& stat_name) PURE;

/**
* Encodes 'name' into the symbol table. Bumps reference counts for referenced
* symbols. The caller must manage the storage, and is responsible for calling
* SymbolTable::free() to release the reference counts.
*
* @param name The name to encode.
* @return The encoded name, transferring ownership to the caller.
*
*/
virtual StoragePtr encode(absl::string_view name) PURE;

virtual StoragePtr makeDynamicStorage(absl::string_view name) PURE;
};

using SymbolTablePtr = std::unique_ptr<SymbolTable>;
class SymbolTable;

} // namespace Stats
} // namespace Envoy
6 changes: 4 additions & 2 deletions source/common/stats/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ envoy_cc_library(
deps = [
":symbol_table_lib",
"//envoy/stats:stats_interface",
"//envoy/stats:symbol_table_interface",
"//source/common/config:well_known_names",
],
)
Expand Down Expand Up @@ -190,7 +189,10 @@ envoy_cc_library(
name = "symbol_table_lib",
srcs = ["symbol_table_impl.cc"],
hdrs = ["symbol_table_impl.h"],
external_deps = ["abseil_base"],
external_deps = [
"abseil_base",
"abseil_inlined_vector",
],
deps = [
":recent_lookups_lib",
"//envoy/stats:symbol_table_interface",
Expand Down
1 change: 0 additions & 1 deletion source/common/stats/allocator_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include "envoy/stats/sink.h"
#include "envoy/stats/stats.h"
#include "envoy/stats/symbol_table.h"

#include "source/common/common/hash.h"
#include "source/common/common/lock_guard.h"
Expand Down
Loading