Commit 9c06ccf8 authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

[sync] Trivially adopt base::TimeDelta for constants

base::TimeDelta has a constexpr constructor and can be used for
constants, preventing bugs and avoiding the need for clarifying
comments.

Bug: 1152797
Change-Id: I9cd5168af01d8e9b17e83524ef37e10b50ceda44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2556641Reviewed-by: default avatarVictor Vianna <victorvianna@google.com>
Commit-Queue: Victor Vianna <victorvianna@google.com>
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#831094}
parent 574cee3d
......@@ -25,13 +25,13 @@ DelayInfo CalculateDelay(int64_t current_delay) {
syncer::kBackoffRandomizationFactor);
delay_info.max_delay = backoff_s + current_delay/2;
delay_info.min_delay =
std::max(static_cast<int64_t>(1),
std::min(delay_info.min_delay, syncer::kMaxBackoffSeconds));
delay_info.min_delay = std::max(
static_cast<int64_t>(1),
std::min(delay_info.min_delay, syncer::kMaxBackoffTime.InSeconds()));
delay_info.max_delay =
std::max(static_cast<int64_t>(1),
std::min(delay_info.max_delay, syncer::kMaxBackoffSeconds));
delay_info.max_delay = std::max(
static_cast<int64_t>(1),
std::min(delay_info.max_delay, syncer::kMaxBackoffTime.InSeconds()));
return delay_info;
}
......@@ -111,4 +111,3 @@ void RetryVerifier::VerifyRetryInterval(const syncer::SyncCycleSnapshot& snap) {
return;
}
}
......@@ -18,6 +18,7 @@ class SyncCycleSnapshot;
// place somewhere in this range. The algorithm that calculates the retry wait
// time uses rand functions.
struct DelayInfo {
// TODO(crbug.com/1152797): Adopt base::TimeDelta in this file.
int64_t min_delay;
int64_t max_delay;
};
......
......@@ -49,8 +49,7 @@ IN_PROC_BROWSER_TEST_F(SingleClientPollingSyncTest, ShouldInitializePollPrefs) {
// Execute a sync cycle and verify the client set up (and persisted) the
// default value.
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
EXPECT_THAT(sync_prefs.GetPollInterval().InSeconds(),
Eq(syncer::kDefaultPollIntervalSeconds));
EXPECT_THAT(sync_prefs.GetPollInterval(), Eq(syncer::kDefaultPollInterval));
}
// This test verifies that updates of the poll interval get persisted
......
......@@ -607,8 +607,7 @@ void ProfileSyncService::StartUpSlowEngineComponents() {
params.invalidation_versions = sync_prefs_.GetInvalidationVersions();
params.poll_interval = sync_prefs_.GetPollInterval();
if (params.poll_interval.is_zero()) {
params.poll_interval =
base::TimeDelta::FromSeconds(kDefaultPollIntervalSeconds);
params.poll_interval = kDefaultPollInterval;
}
if (!IsLocalSyncEnabled()) {
......
......@@ -22,7 +22,8 @@ namespace {
// The amount of time we'll wait to initialize sync if no data type requests
// immediately initialization.
const int kDefaultDeferredInitDelaySeconds = 10;
constexpr base::TimeDelta kDefaultDeferredInitDelay =
base::TimeDelta::FromSeconds(10);
base::TimeDelta GetDeferredInitDelay() {
const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
......@@ -37,7 +38,7 @@ base::TimeDelta GetDeferredInitDelay() {
return base::TimeDelta::FromSeconds(timeout);
}
}
return base::TimeDelta::FromSeconds(kDefaultDeferredInitDelaySeconds);
return kDefaultDeferredInitDelay;
}
bool IsDeferredStartupEnabled() {
......
......@@ -28,7 +28,7 @@ const char kEventEndpoint[] = "event";
// plenty of time. Since sync is off when this request is started, we don't
// want anything sync-related hanging around for very long from a human
// perspective either. This seems like a good compromise.
const int kRequestTimeoutSeconds = 10;
constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10);
} // namespace
......@@ -106,8 +106,8 @@ void SyncStoppedReporter::ReportSyncStopped(const std::string& access_token,
url_loader_factory_.get(),
base::BindOnce(&SyncStoppedReporter::OnSimpleLoaderComplete,
base::Unretained(this)));
timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kRequestTimeoutSeconds),
this, &SyncStoppedReporter::OnTimeout);
timer_.Start(FROM_HERE, kRequestTimeout, this,
&SyncStoppedReporter::OnTimeout);
}
void SyncStoppedReporter::OnSimpleLoaderComplete(
......
......@@ -34,7 +34,7 @@ namespace {
// It's possible for an http request to be silently stalled. We set a time
// limit for all http requests, beyond which the request is cancelled and
// treated as a transient failure.
const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes.
constexpr base::TimeDelta kMaxHttpRequestTime = base::TimeDelta::FromMinutes(5);
// Helper method for logging timeouts via UMA.
void LogTimeout(bool timed_out) {
......@@ -185,7 +185,7 @@ void HttpBridge::MakeAsynchronousPost() {
fetch_state_.http_request_timeout_timer =
std::make_unique<base::OneShotTimer>();
fetch_state_.http_request_timeout_timer->Start(
FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds),
FROM_HERE, kMaxHttpRequestTime,
base::BindOnce(&HttpBridge::OnURLLoadTimedOut, this));
// Some tests inject |url_loader_factory_| created to operated on the
......
......@@ -10,10 +10,10 @@ namespace syncer {
// We use high values here to ensure that failure to receive poll updates from
// the server doesn't result in rapid-fire polling from the client due to low
// local limits.
const int64_t kDefaultPollIntervalSeconds = 3600 * 8;
const base::TimeDelta kDefaultPollInterval = base::TimeDelta::FromHours(8);
// Maximum interval for exponential backoff.
const int64_t kMaxBackoffSeconds = 60 * 10; // 10 minutes.
const base::TimeDelta kMaxBackoffTime = base::TimeDelta::FromMinutes(10);
// Backoff interval randomization factor.
const int kBackoffRandomizationFactor = 2;
......@@ -21,16 +21,19 @@ const int kBackoffRandomizationFactor = 2;
// After a failure contacting sync servers, specifies how long to wait before
// reattempting and entering exponential backoff if consecutive failures
// occur.
const int kInitialBackoffRetrySeconds = 30; // 30 seconds.
const base::TimeDelta kInitialBackoffRetryTime =
base::TimeDelta::FromSeconds(30);
// A dangerously short retry value that would not actually protect servers from
// DDoS if it were used as a seed for exponential backoff, although the client
// would still follow exponential backoff. Useful for debugging and tests (when
// you don't want to wait 5 minutes).
const int kInitialBackoffShortRetrySeconds = 1;
const base::TimeDelta kInitialBackoffShortRetryTime =
base::TimeDelta::FromSeconds(1);
// Similar to kInitialBackoffRetrySeconds above, but only to be used in
// Similar to kInitialBackoffRetryTime above, but only to be used in
// certain exceptional error cases, such as MIGRATION_DONE.
const int kInitialBackoffImmediateRetrySeconds = 0;
const base::TimeDelta kInitialBackoffImmediateRetryTime =
base::TimeDelta::FromSeconds(0);
} // namespace syncer
......@@ -7,15 +7,17 @@
#include <stdint.h>
#include "base/time/time.h"
namespace syncer {
// Constants used by SyncScheduler when polling servers for updates.
extern const int64_t kDefaultPollIntervalSeconds;
extern const int64_t kMaxBackoffSeconds;
extern const base::TimeDelta kDefaultPollInterval;
extern const base::TimeDelta kMaxBackoffTime;
extern const int kBackoffRandomizationFactor;
extern const int kInitialBackoffRetrySeconds;
extern const int kInitialBackoffShortRetrySeconds;
extern const int kInitialBackoffImmediateRetrySeconds;
extern const base::TimeDelta kInitialBackoffRetryTime;
extern const base::TimeDelta kInitialBackoffShortRetryTime;
extern const base::TimeDelta kInitialBackoffImmediateRetryTime;
} // namespace syncer
......
......@@ -14,16 +14,13 @@
#include "components/sync/engine/cycle/model_neutral_state.h"
#include "components/sync/engine/polling_constants.h"
using base::TimeDelta;
namespace syncer {
// static
std::unique_ptr<BackoffDelayProvider> BackoffDelayProvider::FromDefaults() {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BackoffDelayProvider(
TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)));
kInitialBackoffRetryTime, kInitialBackoffImmediateRetryTime));
}
// static
......@@ -31,8 +28,7 @@ std::unique_ptr<BackoffDelayProvider>
BackoffDelayProvider::WithShortInitialRetryOverride() {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BackoffDelayProvider(
TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds),
TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)));
kInitialBackoffShortRetryTime, kInitialBackoffImmediateRetryTime));
}
BackoffDelayProvider::BackoffDelayProvider(
......@@ -43,31 +39,30 @@ BackoffDelayProvider::BackoffDelayProvider(
BackoffDelayProvider::~BackoffDelayProvider() {}
TimeDelta BackoffDelayProvider::GetDelay(const base::TimeDelta& last_delay) {
if (last_delay.InSeconds() >= kMaxBackoffSeconds)
return TimeDelta::FromSeconds(kMaxBackoffSeconds);
base::TimeDelta BackoffDelayProvider::GetDelay(
const base::TimeDelta& last_delay) {
if (last_delay >= kMaxBackoffTime)
return kMaxBackoffTime;
// This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
int64_t backoff_s =
std::max(static_cast<int64_t>(1),
last_delay.InSeconds() * kBackoffRandomizationFactor);
// This calculates approx. base_delay * 2 +/- base_delay / 2
base::TimeDelta backoff = std::max(base::TimeDelta::FromSeconds(1),
last_delay * kBackoffRandomizationFactor);
// Flip a coin to randomize backoff interval by +/- 50%.
int rand_sign = base::RandInt(0, 1) * 2 - 1;
// Truncation is adequate for rounding here.
backoff_s =
backoff_s +
(rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor));
// Cap the backoff interval.
backoff_s = std::max(static_cast<int64_t>(1),
std::min(backoff_s, kMaxBackoffSeconds));
return TimeDelta::FromSeconds(backoff_s);
base::TimeDelta jitter =
(last_delay / kBackoffRandomizationFactor)
.FloorToMultiple(base::TimeDelta::FromSeconds(1));
backoff += rand_sign * jitter;
// Clamp backoff between 1 second and |kMaxBackoffTime|.
return std::max(base::TimeDelta::FromSeconds(1),
std::min(backoff, kMaxBackoffTime));
}
TimeDelta BackoffDelayProvider::GetInitialDelay(
base::TimeDelta BackoffDelayProvider::GetInitialDelay(
const ModelNeutralState& state) const {
// NETWORK_CONNECTION_UNAVAILABLE implies we did not receive HTTP response
// from server because of some network error. If network is unavailable then
......
......@@ -30,10 +30,9 @@ TEST_F(BackoffDelayProviderTest, GetRecommendedDelay) {
delay->GetDelay(TimeDelta::FromSeconds(50)));
EXPECT_LE(TimeDelta::FromSeconds(10),
delay->GetDelay(TimeDelta::FromSeconds(10)));
EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds)));
EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds + 1)));
EXPECT_EQ(kMaxBackoffTime, delay->GetDelay(kMaxBackoffTime));
EXPECT_EQ(kMaxBackoffTime,
delay->GetDelay(kMaxBackoffTime + TimeDelta::FromSeconds(1)));
}
TEST_F(BackoffDelayProviderTest, GetInitialDelay) {
......@@ -42,48 +41,39 @@ TEST_F(BackoffDelayProviderTest, GetInitialDelay) {
ModelNeutralState state;
state.last_get_key_result =
SyncerError::HttpError(net::HTTP_INTERNAL_SERVER_ERROR);
EXPECT_EQ(kInitialBackoffRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
state.last_get_key_result = SyncerError();
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED);
EXPECT_EQ(kInitialBackoffRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR);
EXPECT_EQ(kInitialBackoffRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
EXPECT_EQ(kInitialBackoffRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::DATATYPE_TRIGGERED_RETRY);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result = SyncerError(SyncerError::SYNCER_OK);
state.commit_result = SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.commit_result =
SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED);
EXPECT_EQ(kInitialBackoffRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
state.commit_result = SyncerError(SyncerError::SERVER_RETURN_CONFLICT);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
}
TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
......@@ -92,38 +82,31 @@ TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
ModelNeutralState state;
state.last_get_key_result =
SyncerError::HttpError(net::HTTP_INTERNAL_SERVER_ERROR);
EXPECT_EQ(kInitialBackoffShortRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
state.last_get_key_result = SyncerError();
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR);
EXPECT_EQ(kInitialBackoffShortRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
EXPECT_EQ(kInitialBackoffShortRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result =
SyncerError(SyncerError::DATATYPE_TRIGGERED_RETRY);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.last_download_updates_result = SyncerError(SyncerError::SYNCER_OK);
state.commit_result = SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
state.commit_result = SyncerError(SyncerError::SERVER_RETURN_CONFLICT);
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
}
} // namespace syncer
......@@ -15,10 +15,14 @@ namespace syncer {
namespace {
// Delays for syncer nudges.
const int kDefaultNudgeDelayMilliseconds = 200;
const int kSlowNudgeDelayMilliseconds = 2000;
const int kSyncRefreshDelayMilliseconds = 500;
const int kSyncSchedulerDelayMilliseconds = 250;
constexpr base::TimeDelta kDefaultNudgeDelay =
base::TimeDelta::FromMilliseconds(200);
constexpr base::TimeDelta kSlowNudgeDelay =
base::TimeDelta::FromMilliseconds(2000);
constexpr base::TimeDelta kSyncRefreshDelay =
base::TimeDelta::FromMilliseconds(500);
constexpr base::TimeDelta kSyncSchedulerDelay =
base::TimeDelta::FromMilliseconds(250);
base::TimeDelta GetSharingMessageDelay(base::TimeDelta default_delay) {
if (!base::FeatureList::IsEnabled(
......@@ -37,13 +41,13 @@ base::TimeDelta GetDefaultDelayForType(ModelType model_type,
case USER_EVENTS:
// Accompany types rely on nudges from other types, and hence have long
// nudge delays.
return base::TimeDelta::FromSeconds(kDefaultPollIntervalSeconds);
return kDefaultPollInterval;
case BOOKMARKS:
case PREFERENCES:
case SESSIONS:
// Types with sometimes automatic changes get longer delays to allow more
// coalescing.
return base::TimeDelta::FromMilliseconds(kSlowNudgeDelayMilliseconds);
return kSlowNudgeDelay;
case SHARING_MESSAGE:
return GetSharingMessageDelay(minimum_delay);
default:
......@@ -56,12 +60,9 @@ base::TimeDelta GetDefaultDelayForType(ModelType model_type,
NudgeTracker::NudgeTracker()
: invalidations_enabled_(false),
invalidations_out_of_sync_(true),
minimum_local_nudge_delay_(
base::TimeDelta::FromMilliseconds(kDefaultNudgeDelayMilliseconds)),
local_refresh_nudge_delay_(
base::TimeDelta::FromMilliseconds(kSyncRefreshDelayMilliseconds)),
remote_invalidation_nudge_delay_(
base::TimeDelta::FromMilliseconds(kSyncSchedulerDelayMilliseconds)) {
minimum_local_nudge_delay_(kDefaultNudgeDelay),
local_refresh_nudge_delay_(kSyncRefreshDelay),
remote_invalidation_nudge_delay_(kSyncSchedulerDelay) {
// Default initialize all the type trackers.
for (ModelType type : ProtocolTypes()) {
type_trackers_.emplace(
......@@ -144,8 +145,7 @@ void NudgeTracker::RecordInitialSyncDone(ModelTypeSet types) {
base::TimeDelta NudgeTracker::RecordLocalChange(ModelTypeSet types) {
// Start with the longest delay.
base::TimeDelta delay =
base::TimeDelta::FromSeconds(kDefaultPollIntervalSeconds);
base::TimeDelta delay = kDefaultPollInterval;
for (ModelType type : types) {
TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
DCHECK(tracker_it != type_trackers_.end());
......
......@@ -829,8 +829,7 @@ void SyncSchedulerImpl::OnTypesThrottled(ModelTypeSet types,
void SyncSchedulerImpl::OnTypesBackedOff(ModelTypeSet types) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (ModelType type : types) {
TimeDelta last_backoff_time =
TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
TimeDelta last_backoff_time = kInitialBackoffRetryTime;
if (nudge_tracker_.GetTypeBlockingMode(type) ==
WaitInterval::EXPONENTIAL_BACKOFF_RETRYING) {
last_backoff_time = nudge_tracker_.GetTypeLastBackoffInterval(type);
......
......@@ -241,9 +241,8 @@ class SyncSchedulerImplTest : public testing::Test {
class MockDelayProvider : public BackoffDelayProvider {
public:
MockDelayProvider()
: BackoffDelayProvider(
TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {}
: BackoffDelayProvider(kInitialBackoffRetryTime,
kInitialBackoffImmediateRetryTime) {}
MOCK_METHOD(TimeDelta, GetDelay, (const TimeDelta&), (override));
};
......@@ -1499,7 +1498,7 @@ TEST_F(SyncSchedulerImplTest, BackoffElevation) {
DoAll(Invoke(SimulateCommitFailed),
RecordSyncShareMultiple(&times, kMinNumSamples, false)));
const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
const TimeDelta first = kInitialBackoffRetryTime;
const TimeDelta second = TimeDelta::FromMilliseconds(20);
const TimeDelta third = TimeDelta::FromMilliseconds(30);
const TimeDelta fourth = TimeDelta::FromMilliseconds(40);
......
......@@ -30,7 +30,8 @@ namespace syncer {
namespace {
// Time to backoff syncing after receiving a throttled response.
const int kSyncDelayAfterThrottled = 2 * 60 * 60; // 2 hours
constexpr base::TimeDelta kSyncDelayAfterThrottled =
base::TimeDelta::FromHours(2);
void LogResponseProfilingData(const ClientToServerResponse& response) {
if (response.has_profiling_data()) {
......@@ -383,8 +384,7 @@ bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm,
base::TimeDelta SyncerProtoUtil::GetThrottleDelay(
const ClientToServerResponse& response) {
base::TimeDelta throttle_delay =
base::TimeDelta::FromSeconds(kSyncDelayAfterThrottled);
base::TimeDelta throttle_delay = kSyncDelayAfterThrottled;
if (response.has_client_command()) {
const sync_pb::ClientCommand& command = response.client_command();
if (command.has_throttle_delay_seconds()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment