| // Copyright 2022 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "components/sync/engine/cycle/commit_quota.h" | |
| #include <algorithm> | |
| #include "base/check_op.h" | |
| #include "base/time/time.h" | |
| namespace syncer { | |
| CommitQuota::CommitQuota(int max_tokens, base::TimeDelta refill_interval) | |
| : max_tokens_(max_tokens), | |
| refill_interval_(refill_interval), | |
| tokens_(max_tokens), | |
| last_refilled_(base::TimeTicks::Now()) { | |
| DCHECK_GT(max_tokens_, 0); | |
| DCHECK_GT(refill_interval_, base::TimeDelta()); | |
| } | |
| CommitQuota::CommitQuota(const CommitQuota&) = default; | |
| CommitQuota& CommitQuota::operator=(const CommitQuota&) = default; | |
| CommitQuota::CommitQuota(CommitQuota&&) = default; | |
| CommitQuota& CommitQuota::operator=(CommitQuota&&) = default; | |
| CommitQuota::~CommitQuota() = default; | |
| void CommitQuota::SetParams(int new_max_tokens, | |
| base::TimeDelta refill_interval) { | |
| DCHECK_GT(new_max_tokens, 0); | |
| DCHECK_GT(refill_interval, base::TimeDelta()); | |
| if (max_tokens_ > new_max_tokens) { | |
| // Cap current tokens by the newly lowered `new_max_tokens` count. | |
| tokens_ = std::min(tokens_, new_max_tokens); | |
| } else if (max_tokens_ < new_max_tokens) { | |
| // Raise current tokens by the newly raised `max_tokens` count. This | |
| // respects the current level of consumed tokens and does not automatically | |
| // reset the token count to `max_tokens`. | |
| const int additional_tokens = new_max_tokens - max_tokens_; | |
| tokens_ += additional_tokens; | |
| } | |
| max_tokens_ = new_max_tokens; | |
| refill_interval_ = refill_interval; | |
| DCHECK_GE(tokens_, 0); | |
| DCHECK_LE(tokens_, max_tokens_); | |
| } | |
| bool CommitQuota::HasTokensAvailable() { | |
| RefillTokens(); | |
| return tokens_ > 0; | |
| } | |
| void CommitQuota::ConsumeToken() { | |
| RefillTokens(); | |
| if (tokens_ > 0) { | |
| --tokens_; | |
| return; | |
| } | |
| // When no token is available to consume, at least push away the next refill | |
| // time to make sure any `HasTokensAvailable()` calls in the next | |
| // `refill_interval_` period return false. | |
| last_refilled_ = base::TimeTicks::Now(); | |
| } | |
| void CommitQuota::RefillTokens() { | |
| const base::TimeDelta since_last_refilled = | |
| base::TimeTicks::Now() - last_refilled_; | |
| const int new_tokens = since_last_refilled / refill_interval_; | |
| if (new_tokens == 0) { | |
| return; | |
| } | |
| tokens_ = std::min(tokens_ + new_tokens, max_tokens_); | |
| last_refilled_ += new_tokens * refill_interval_; | |
| DCHECK_GE(tokens_, 0); | |
| } | |
| } // namespace syncer |