Repository: envoyproxy/envoy
File: source/common/stats/thread_local_store.cc (C++)

Code before:
  }
}

void ThreadLocalStoreImpl::clearHistogramsFromCaches() {
  // If we are shutting down we no longer perform cache flushes as workers may be shutting down
  // at the same time.
  if (!shutting_down_) {
    // Move the histograms pending cleanup into a local variable. Future histogram deletions will be
    // batched until the next time this function is called.
    auto histograms = std::make_shared<std::vector<uint64_t>>();
    {
      Thread::LockGuard lock(hist_mutex_);
      histograms->swap(histograms_to_cleanup_);
    }

    tls_cache_->runOnAllThreads(
        [histograms](OptRef<TlsCache> tls_cache) { tls_cache->eraseHistograms(*histograms); });
  }
}

ThreadLocalStoreImpl::ScopeImpl::ScopeImpl(ThreadLocalStoreImpl& parent, StatName prefix,
                                           bool evictable, const ScopeStatsLimitSettings& limits)
    : scope_id_(parent.next_scope_id_++), parent_(parent), evictable_(evictable), limits_(limits),
      prefix_(prefix, parent.alloc_.symbolTable()),
      central_cache_(new CentralCacheEntry(parent.alloc_.symbolTable())) {
  Thread::LockGuard lock(parent_.lock_);
  if (limits_.max_counters.has_value() && parent_.counters_overflow_ == nullptr) {
    StatNamePool pool(parent_.symbolTable());
    StatName name = pool.add("stats.overflow.counters");
    parent_.counters_overflow_ = parent_.alloc_.makeCounter(name, name, {});
  }
  if (limits_.max_gauges.has_value() && parent_.gauges_overflow_ == nullptr) {
    StatNamePool pool(parent_.symbolTable());
    StatName name = pool.add("stats.overflow.gauges");
    parent_.gauges_overflow_ = parent_.alloc_.makeCounter(name, name, {});
  }
  if (limits_.max_histograms.has_value() && parent_.histograms_overflow_ == nullptr) {
    StatNamePool pool(parent_.symbolTable());
    StatName name = pool.add("stats.overflow.histograms");
    parent_.histograms_overflow_ = parent_.alloc_.makeCounter(name, name, {});
  }
}

ThreadLocalStoreImpl::ScopeImpl::~ScopeImpl() {
  // Helps reproduce a previous race condition by pausing here in tests while we
  // loop over scopes. 'this' will not have been removed from the scopes_ table
  // yet, so we need to be careful.
  parent_.sync_.syncPoint(DeleteScopeSync);

  // Note that scope iteration is thread-safe due to the lock held in
  // releaseScopeCrossThread. For more details see the comment in

Review comment (bug):
Can you move this into a function on the store implementation and call it `ensureOverflowStats`?

Code after:
  }
}

void ThreadLocalStoreImpl::clearHistogramsFromCaches() {
  // If we are shutting down we no longer perform cache flushes as workers may be shutting down
  // at the same time.
  if (!shutting_down_) {
    // Move the histograms pending cleanup into a local variable. Future histogram deletions will be
    // batched until the next time this function is called.
    auto histograms = std::make_shared<std::vector<uint64_t>>();
    {
      Thread::LockGuard lock(hist_mutex_);
      histograms->swap(histograms_to_cleanup_);
    }

    tls_cache_->runOnAllThreads(
        [histograms](OptRef<TlsCache> tls_cache) { tls_cache->eraseHistograms(*histograms); });
  }
}

ThreadLocalStoreImpl::ScopeImpl::ScopeImpl(ThreadLocalStoreImpl& parent, StatName prefix,
                                           bool evictable, const ScopeStatsLimitSettings& limits)
    : scope_id_(parent.next_scope_id_++), parent_(parent), evictable_(evictable), limits_(limits),
      prefix_(prefix, parent.alloc_.symbolTable()),
      central_cache_(new CentralCacheEntry(parent.alloc_.symbolTable())) {
  parent_.ensureOverflowStats(limits_);
}

ThreadLocalStoreImpl::ScopeImpl::~ScopeImpl() {
  // Helps reproduce a previous race condition by pausing here in tests while we
  // loop over scopes. 'this' will not have been removed from the scopes_ table
  // yet, so we need to be careful.
  parent_.sync_.syncPoint(DeleteScopeSync);

  // Note that scope iteration is thread-safe due to the lock held in
  // releaseScopeCrossThread. For more details see the comment in
  // `ThreadLocalStoreImpl::iterHelper`, and the lock it takes prior to the loop.
  parent_.releaseScopeCrossThread(this);
  prefix_.free(symbolTable());
}

// Helper for managing the potential truncation of tags from the metric names and
// converting them to StatName. Making the tag extraction optional within this class simplifies the
// RAII ergonomics (as opposed to making the construction of this object conditional).
//
// The StatNameTagVector returned by this object will be valid as long as this object is in scope
// and the provided stat_name_tags are valid.
//
// When tag extraction is not done, this class is just a passthrough for the provided name/tags.
class StatNameTagHelper {
public: