2323#include " allocated.hpp"
2424#include " atomic.hpp"
2525#include " constants.hpp"
26+ #include " get_time.hpp"
2627#include " scoped_lock.hpp"
2728#include " scoped_ptr.hpp"
2829#include " utils.hpp"
@@ -268,9 +269,15 @@ class Metrics : public Allocated {
268269 int64_t percentile_999th;
269270 };
270271
271- Histogram (ThreadState* thread_state)
272+ Histogram (ThreadState* thread_state, unsigned refresh_interval = CASS_DEFAULT_HISTOGRAM_REFRESH_INTERVAL_NO_REFRESH )
272273 : thread_state_(thread_state)
273- , histograms_(new PerThreadHistogram[thread_state->max_threads ()]) {
274+ , histograms_(new PerThreadHistogram[thread_state->max_threads ()])
275+ , zero_snapshot_(Snapshot {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }) {
276+
277+ refresh_interval_ = refresh_interval;
278+ refresh_timestamp_ = get_time_since_epoch_ms ();
279+ cached_snapshot_ = zero_snapshot_;
280+
274281 hdr_init (1LL , HIGHEST_TRACKABLE_VALUE, 3 , &histogram_);
275282 uv_mutex_init (&mutex_);
276283 }
@@ -286,38 +293,76 @@ class Metrics : public Allocated {
286293
287294 void get_snapshot (Snapshot* snapshot) const {
288295 ScopedMutex l (&mutex_);
289- hdr_histogram* h = histogram_;
290- for (size_t i = 0 ; i < thread_state_->max_threads (); ++i) {
291- histograms_[i].add (h);
296+
297+ // In the "no refresh" case (the default) fall back to the old behaviour; add per-thread
298+ // timestamps to histogram_ (without any clearing of data) and return what's there.
299+ if (refresh_interval_ == CASS_DEFAULT_HISTOGRAM_REFRESH_INTERVAL_NO_REFRESH) {
300+
301+ for (size_t i = 0 ; i < thread_state_->max_threads (); ++i) {
302+ histograms_[i].add (histogram_);
303+ }
304+
305+ if (histogram_->total_count == 0 ) {
306+ // There is no data; default to 0 for the stats.
307+ copy_snapshot (zero_snapshot_, snapshot);
308+ } else {
309+ histogram_to_snapshot (histogram_, snapshot);
310+ }
311+ return ;
292312 }
293313
294- if (h->total_count == 0 ) {
295- // There is no data; default to 0 for the stats.
296- snapshot->max = 0 ;
297- snapshot->min = 0 ;
298- snapshot->mean = 0 ;
299- snapshot->stddev = 0 ;
300- snapshot->median = 0 ;
301- snapshot->percentile_75th = 0 ;
302- snapshot->percentile_95th = 0 ;
303- snapshot->percentile_98th = 0 ;
304- snapshot->percentile_99th = 0 ;
305- snapshot->percentile_999th = 0 ;
306- } else {
307- snapshot->max = hdr_max (h);
308- snapshot->min = hdr_min (h);
309- snapshot->mean = static_cast <int64_t >(hdr_mean (h));
310- snapshot->stddev = static_cast <int64_t >(hdr_stddev (h));
311- snapshot->median = hdr_value_at_percentile (h, 50.0 );
312- snapshot->percentile_75th = hdr_value_at_percentile (h, 75.0 );
313- snapshot->percentile_95th = hdr_value_at_percentile (h, 95.0 );
314- snapshot->percentile_98th = hdr_value_at_percentile (h, 98.0 );
315- snapshot->percentile_99th = hdr_value_at_percentile (h, 99.0 );
316- snapshot->percentile_999th = hdr_value_at_percentile (h, 99.9 );
314+ // Refresh interval is in use. If we've exceeded the interval clear histogram_,
315+ // compute a new aggregate histogram and build (and cache) a new snapshot. Otherwise
316+ // just return the cached version.
317+ uint64_t now = get_time_since_epoch_ms ();
318+ if (now - refresh_timestamp_ >= refresh_interval_) {
319+
320+ hdr_reset (histogram_);
321+
322+ for (size_t i = 0 ; i < thread_state_->max_threads (); ++i) {
323+ histograms_[i].add (histogram_);
324+ }
325+
326+ if (histogram_->total_count == 0 ) {
327+ copy_snapshot (zero_snapshot_, &cached_snapshot_);
328+ } else {
329+ histogram_to_snapshot (histogram_, &cached_snapshot_);
330+ }
331+ refresh_timestamp_ = now;
317332 }
333+
334+ copy_snapshot (cached_snapshot_, snapshot);
318335 }
319336
320337 private:
338+
339+ void copy_snapshot (Snapshot from, Snapshot* to) const {
340+ to->min = from.min ;
341+ to->max = from.max ;
342+ to->mean = from.mean ;
343+ to->stddev = from.stddev ;
344+ to->median = from.median ;
345+ to->percentile_75th = from.percentile_75th ;
346+ to->percentile_95th = from.percentile_95th ;
347+ to->percentile_98th = from.percentile_98th ;
348+ to->percentile_99th = from.percentile_99th ;
349+ to->percentile_999th = from.percentile_999th ;
350+ }
351+
352+ void histogram_to_snapshot (hdr_histogram* h, Snapshot* to) const {
353+ to->min = hdr_min (h);
354+ to->max = hdr_max (h);
355+ to->mean = static_cast <int64_t >(hdr_mean (h));
356+ to->stddev = static_cast <int64_t >(hdr_stddev (h));
357+ to->median = hdr_value_at_percentile (h, 50.0 );
358+ to->percentile_75th = hdr_value_at_percentile (h, 75.0 );
359+ to->percentile_95th = hdr_value_at_percentile (h, 95.0 );
360+ to->percentile_98th = hdr_value_at_percentile (h, 98.0 );
361+ to->percentile_99th = hdr_value_at_percentile (h, 99.0 );
362+ to->percentile_999th = hdr_value_at_percentile (h, 99.9 );
363+ }
364+
365+
321366 class WriterReaderPhaser {
322367 public:
323368 WriterReaderPhaser ()
@@ -409,14 +454,19 @@ class Metrics : public Allocated {
409454 hdr_histogram* histogram_;
410455 mutable uv_mutex_t mutex_;
411456
457+ unsigned refresh_interval_;
458+ mutable uint64_t refresh_timestamp_;
459+ mutable Snapshot cached_snapshot_;
460+ const Snapshot zero_snapshot_;
461+
412462 private:
413463 DISALLOW_COPY_AND_ASSIGN (Histogram);
414464 };
415465
416- Metrics (size_t max_threads)
466+ Metrics (size_t max_threads, unsigned histogram_refresh_interval )
417467 : thread_state_(max_threads)
418- , request_latencies(&thread_state_)
419- , speculative_request_latencies(&thread_state_)
468+ , request_latencies(&thread_state_, histogram_refresh_interval )
469+ , speculative_request_latencies(&thread_state_, histogram_refresh_interval )
420470 , request_rates(&thread_state_)
421471 , total_connections(&thread_state_)
422472 , connection_timeouts(&thread_state_)
@@ -447,6 +497,8 @@ class Metrics : public Allocated {
447497 Counter connection_timeouts;
448498 Counter request_timeouts;
449499
500+ unsigned histogram_refresh_interval;
501+
450502private:
451503 DISALLOW_COPY_AND_ASSIGN (Metrics);
452504};
0 commit comments