Skip to content

Commit

Permalink
Reduce and smooth traffic on drive back ends when requesting change l…
Browse files Browse the repository at this point in the history
…ists.

As requested by Drive SRE these changes reduce the frequency of requests on the
drive back ends, and also lessens the likelihood of convoying.

1. When XMPP is connected, change the poll timeout for changes from 5 minutes to
   between 60 & 120 minutes.
2. When XMPP is disconnected, change the poll timeout for changes from 1 minute
   to between 1 and 2 minutes. This issues start page token requests which are
   cheap for the drive back ends.
3. When batching XMPP notifications, change the batch time from 5 seconds to
   between 15 and 30 seconds. This reduces the QPS on drive back ends when a
   team drive change notification is broadcast to a large corpus of users, and
   prevents convoying of requests by introducing jitter.

Bug: 905201
Change-Id: I5310d956c9ccb5b59261cdf99bbefb515f75771f
Reviewed-on: https://chromium-review.googlesource.com/c/1336949
Reviewed-by: Sam McNally <sammc@chromium.org>
Commit-Queue: Stuart Langley <slangley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608239}
  • Loading branch information
sjlangley authored and Commit Bot committed Nov 15, 2018
1 parent 13f7b17 commit 6477fb0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 17 deletions.
35 changes: 23 additions & 12 deletions components/drive/drive_notification_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <utility>

#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/strings/char_traits.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
Expand All @@ -25,11 +26,10 @@ const int kFastPollingIntervalInSecs = 60;

// The polling interval time is used when XMPP is enabled. Theoretically
// polling should be unnecessary if XMPP is enabled, but just in case.
const int kSlowPollingIntervalInSecs = 300;
const int kSlowPollingIntervalInSecs = 3600;

// The period to batch together invalidations before passing them to observers.
constexpr base::TimeDelta kInvalidationBatchInterval =
base::TimeDelta::FromSeconds(5);
constexpr int kInvalidationBatchIntervalSecs = 15;

// The sync invalidation object ID for Google Drive.
const char kDriveInvalidationObjectId[] = "CHANGELOG";
Expand All @@ -49,16 +49,11 @@ DriveNotificationManager::DriveNotificationManager(
push_notification_registered_(false),
push_notification_enabled_(false),
observers_notified_(false),
batch_timer_(clock),
weak_ptr_factory_(this) {
DCHECK(invalidation_service_);
RegisterDriveNotifications();
RestartPollingTimer();

batch_timer_ = std::make_unique<base::RetainingOneShotTimer>(
FROM_HERE, kInvalidationBatchInterval,
base::BindRepeating(&DriveNotificationManager::OnBatchTimerExpired,
weak_ptr_factory_.GetWeakPtr()),
clock);
}

DriveNotificationManager::~DriveNotificationManager() {
Expand Down Expand Up @@ -122,12 +117,12 @@ void DriveNotificationManager::OnIncomingInvalidation(
// See crbug.com/320878.
invalidation_map.AcknowledgeAll();

if (!batch_timer_->IsRunning() && !invalidated_change_ids_.empty()) {
if (!batch_timer_.IsRunning() && !invalidated_change_ids_.empty()) {
// Stop the polling timer as we'll be sending a batch soon.
polling_timer_.Stop();

// Restart the timer to send the batch when the timer fires.
batch_timer_->Reset();
RestartBatchTimer();
}
}

Expand Down Expand Up @@ -175,14 +170,30 @@ void DriveNotificationManager::RestartPollingTimer() {
const int interval_secs = (push_notification_enabled_ ?
kSlowPollingIntervalInSecs :
kFastPollingIntervalInSecs);

int jitter = base::RandInt(0, interval_secs);

polling_timer_.Stop();
polling_timer_.Start(
FROM_HERE, base::TimeDelta::FromSeconds(interval_secs),
FROM_HERE, base::TimeDelta::FromSeconds(interval_secs + jitter),
base::BindOnce(&DriveNotificationManager::NotifyObserversToUpdate,
weak_ptr_factory_.GetWeakPtr(), NOTIFICATION_POLLING,
std::map<std::string, int64_t>()));
}

void DriveNotificationManager::RestartBatchTimer() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

int jitter = base::RandInt(0, kInvalidationBatchIntervalSecs);

batch_timer_.Stop();
batch_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kInvalidationBatchIntervalSecs + jitter),
base::BindOnce(&DriveNotificationManager::OnBatchTimerExpired,
weak_ptr_factory_.GetWeakPtr()));
}

void DriveNotificationManager::NotifyObserversToUpdate(
NotificationSource source,
std::map<std::string, int64_t> invalidations) {
Expand Down
6 changes: 5 additions & 1 deletion components/drive/drive_notification_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class DriveNotificationManager : public KeyedService,
// Restarts the polling timer. Used for polling-based notification.
void RestartPollingTimer();

// Restarts the batch notification timer. Used for batching together XMPP
// notifications so we can smooth out the traffic on the drive backends.
void RestartBatchTimer();

// Notifies the observers that it's time to check for updates.
// |source| indicates where the notification comes from.
void NotifyObserversToUpdate(NotificationSource source,
Expand Down Expand Up @@ -123,7 +127,7 @@ class DriveNotificationManager : public KeyedService,
// This timer is used to batch together invalidations. The invalidation
// service can send many invalidations for the same id in rapid succession,
// batching them together and removing duplicates is an optimzation.
std::unique_ptr<base::RetainingOneShotTimer> batch_timer_;
base::OneShotTimer batch_timer_;

// The batch of invalidation id's that we've seen from the invaliation
// service, will be reset when when send the invalidations to the observers.
Expand Down
8 changes: 4 additions & 4 deletions components/drive/drive_notification_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ TEST_F(DriveNotificationManagerTest, TestBatchInvalidation) {
syncer::Invalidation::InitUnknownVersion(kDefaultCorpusObjectId));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());

task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(5));
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));

// Default corpus is has the id "" when sent to observers.
std::map<std::string, int64_t> expected_ids = {{"", -1}};
Expand All @@ -181,7 +181,7 @@ TEST_F(DriveNotificationManagerTest, TestBatchInvalidation) {
syncer::Invalidation::Init(kDefaultCorpusObjectId, 1, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());

task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(5));
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));

// Default corpus is has the id "" when sent to observers.
expected_ids = {{"", 2}};
Expand All @@ -193,7 +193,7 @@ TEST_F(DriveNotificationManagerTest, TestBatchInvalidation) {
syncer::Invalidation::Init(team_drive_1_object_id, 2, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());

task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(5));
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
expected_ids = {{team_drive_id_1, 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
drive_notification_observer_->ClearNotificationIds();
Expand All @@ -214,7 +214,7 @@ TEST_F(DriveNotificationManagerTest, TestBatchInvalidation) {

EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());

task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(5));
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
expected_ids = {{"", 2}, {team_drive_id_1, 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
}
Expand Down

0 comments on commit 6477fb0

Please sign in to comment.