Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
src/histogram: Make Histogram::observe atomic across collects (#314)
* src/histogram: Add test ensuring Histogram::observe is atomic If an observe and a collect operation interleave, the latter should not expose a snapshot of the histogram that does not uphold all histogram invariants. For example for the invariant that the overall observation counter should equal the sum of all bucket counters: Say that an `observe` increases the overall counter but before updating a specific bucket counter a collect operation snapshots the histogram. This commits adds a basic unit test to test that the above is not happening. Signed-off-by: Max Inden <mail@max-inden.de> * src/{histogram,atomic64}: Make Histogram::observe atomic across collects A histogram supports two main execution paths: 1. `observe` which increases the overall observation counter, updates the observation sum and increases a single bucket counter. 2. `proto` (aka. collecting the metric, from now on referred to as the collect operation) which snapshots the state of the histogram and exposes it as a Protobuf struct. If an observe and a collect operation interleave, the latter could be exposing a snapshot of the histogram that does not uphold all histogram invariants. For example for the invariant that the overall observation counter should equal the sum of all bucket counters: Say that an `observe` increases the overall counter but before updating a specific bucket counter a collect operation snapshots the histogram. This commits adjusts the `HistogramCore` implementation to make such race conditions impossible. It introduces the notion of shards, one hot shard for `observe` operations to record their observation and one cold shard for collect operations to collect a consistent snapshot of the histogram. `observe` operations hit the hot shard and record their observation. Collect operations switch hot and cold, wait for all `observe` calls to finish on the previously hot now cold shard and then expose the consistent snapshot. Signed-off-by: Max Inden <mail@max-inden.de> * benches/histogram: Add benchmark for concurrent observe and collect Add a basic benchmark test which spawns 4 threads in the background continuously calling `observe` 1_000 times and then `collect`. At the same time call `observe` within the `Bencher::iter` closure to measure impact of background threads on `observe` call. Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram: Account for missing take without protobuf feature Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram,benches/histogram: Run Rust fmt Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram: Drop collect lock guard explicitly Rusts drop semantics can be confusing sometimes. E.g. `let _ = l.lock()` would drop the lock guard immediately whereas `let _guard = l.lock()` would drop the guard in LIFO order at the end of the current scope. Instead of relying on the above guarantee with `let _guard`, drop the mutex guard explicitely hopefully making this less error prone in the future. Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram: Remove underscore prefix from used variable Signed-off-by: Max Inden <mail@max-inden.de> * src/{atomic,histogram}: Make swap take ordering and tighten usage Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram: Test invariant that sum == count with observe(1.0) Signed-off-by: Max Inden <mail@max-inden.de> * src/atomic64: Adjust swap doc comment Signed-off-by: Max Inden <mail@max-inden.de> * src/histogram: Remove pub from shard related structs and fn Signed-off-by: Max Inden <mail@max-inden.de> Co-authored-by: Luca Bruno <luca.bruno@coreos.com>
- Loading branch information