Skip to content

Commit 632634d

Browse files
author
knkhmelevsky
committed
feat userver-recentperiod: lower contention effects on buckets
Under high contention, `RecentPeriod` tended to increment the current index twice, which led to "zeroed" buckets that stopped the cycle in `GetStatsForPeriod`. In cases of a stable signal, this caused drops in the returned value down to 0, with restoration to the actual value only after `MaxDuration`—when all buckets had been revisited. This fix does not aim to provide an algorithmically safe solution, but it does practically reduce the frequency of such drops. commit_hash:ec2be57aec578dcce323ac1a17468c3e1779a091
1 parent 64e1219 commit 632634d

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

core/include/userver/utils/statistics/recentperiod.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class RecentPeriod {
109109

110110
void Reset() {
111111
for (auto& item : items_) {
112-
item.Reset();
112+
item.Reset(Duration::min());
113113
}
114114
}
115115

@@ -121,12 +121,14 @@ class RecentPeriod {
121121
std::size_t index = epoch_index_.load();
122122
const Duration bucket_epoch = items_[index].epoch.load();
123123

124-
if (epoch != bucket_epoch) {
124+
// Second condition allows non-monotonic timeline (that is common for tests)
125+
// but still forbids race (rewrite of fresh bucket by sleeped after L113 thread)
126+
if (epoch > bucket_epoch || epoch + max_duration_ < bucket_epoch) {
125127
const std::size_t new_index = (index + 1) % items_.size();
126128

127129
if (epoch_index_.compare_exchange_weak(index, new_index)) {
128130
items_[new_index].epoch = epoch;
129-
items_[(new_index + 1) % items_.size()].Reset();
131+
items_[(new_index + 1) % items_.size()].Reset(epoch + epoch_duration_);
130132
return new_index;
131133
}
132134
} else {
@@ -159,10 +161,10 @@ class RecentPeriod {
159161
std::atomic<Duration> epoch;
160162
Counter counter;
161163

162-
EpochBucket() { Reset(); }
164+
EpochBucket() { Reset(Duration::min()); }
163165

164-
void Reset() {
165-
epoch = Duration::min();
166+
void Reset(Duration epoch_duration) {
167+
epoch = epoch_duration;
166168
if constexpr (kUseReset) {
167169
counter.Reset();
168170
} else {

0 commit comments

Comments
 (0)