Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: sync/engine/sync_scheduler_impl.cc

Issue 124083002: Client-side changes to support retry GU. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/engine/sync_scheduler_impl.h" 5 #include "sync/engine/sync_scheduler_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cstring> 8 #include <cstring>
9 9
10 #include "base/auto_reset.h" 10 #include "base/auto_reset.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/time/default_clock.h"
17 #include "sync/engine/backoff_delay_provider.h" 18 #include "sync/engine/backoff_delay_provider.h"
18 #include "sync/engine/syncer.h" 19 #include "sync/engine/syncer.h"
19 #include "sync/notifier/object_id_invalidation_map.h" 20 #include "sync/notifier/object_id_invalidation_map.h"
20 #include "sync/protocol/proto_enum_conversions.h" 21 #include "sync/protocol/proto_enum_conversions.h"
21 #include "sync/protocol/sync.pb.h" 22 #include "sync/protocol/sync.pb.h"
22 #include "sync/util/data_type_histogram.h" 23 #include "sync/util/data_type_histogram.h"
23 #include "sync/util/logging.h" 24 #include "sync/util/logging.h"
24 25
25 using base::TimeDelta; 26 using base::TimeDelta;
26 using base::TimeTicks; 27 using base::TimeTicks;
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 : name_(name), 159 : name_(name),
159 started_(false), 160 started_(false),
160 syncer_short_poll_interval_seconds_( 161 syncer_short_poll_interval_seconds_(
161 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)), 162 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)),
162 syncer_long_poll_interval_seconds_( 163 syncer_long_poll_interval_seconds_(
163 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)), 164 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)),
164 sessions_commit_delay_( 165 sessions_commit_delay_(
165 TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds)), 166 TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds)),
166 mode_(NORMAL_MODE), 167 mode_(NORMAL_MODE),
167 delay_provider_(delay_provider), 168 delay_provider_(delay_provider),
169 nudge_tracker_(new base::DefaultClock),
168 syncer_(syncer), 170 syncer_(syncer),
169 session_context_(context), 171 session_context_(context),
170 no_scheduling_allowed_(false), 172 no_scheduling_allowed_(false),
171 do_poll_after_credentials_updated_(false), 173 do_poll_after_credentials_updated_(false),
172 next_sync_session_job_priority_(NORMAL_PRIORITY), 174 next_sync_session_job_priority_(NORMAL_PRIORITY),
173 weak_ptr_factory_(this), 175 weak_ptr_factory_(this),
174 weak_ptr_factory_for_weak_handle_(this) { 176 weak_ptr_factory_for_weak_handle_(this) {
175 weak_handle_this_ = MakeWeakHandle( 177 weak_handle_this_ = MakeWeakHandle(
176 weak_ptr_factory_for_weak_handle_.GetWeakPtr()); 178 weak_ptr_factory_for_weak_handle_.GetWeakPtr());
177 } 179 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 } 229 }
228 230
229 DCHECK(!session_context_->account_name().empty()); 231 DCHECK(!session_context_->account_name().empty());
230 DCHECK(syncer_.get()); 232 DCHECK(syncer_.get());
231 Mode old_mode = mode_; 233 Mode old_mode = mode_;
232 mode_ = mode; 234 mode_ = mode;
233 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed. 235 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed.
234 236
235 if (old_mode != mode_ && 237 if (old_mode != mode_ &&
236 mode_ == NORMAL_MODE && 238 mode_ == NORMAL_MODE &&
237 nudge_tracker_.IsSyncRequired() && 239 (nudge_tracker_.IsSyncRequired() || nudge_tracker_.IsRetryRequired()) &&
238 CanRunNudgeJobNow(NORMAL_PRIORITY)) { 240 CanRunNudgeJobNow(NORMAL_PRIORITY)) {
239 // We just got back to normal mode. Let's try to run the work that was 241 // We just got back to normal mode. Let's try to run the work that was
240 // queued up while we were configuring. 242 // queued up while we were configuring.
241 TrySyncSessionJob(); 243 TrySyncSessionJob();
242 } 244 }
243 } 245 }
244 246
245 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() { 247 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() {
246 ModelTypeSet enabled_types = session_context_->enabled_types(); 248 ModelTypeSet enabled_types = session_context_->enabled_types();
247 ModelTypeSet throttled_types = nudge_tracker_.GetThrottledTypes(); 249 ModelTypeSet throttled_types = nudge_tracker_.GetThrottledTypes();
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 } 442 }
441 443
442 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { 444 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) {
443 switch (mode) { 445 switch (mode) {
444 ENUM_CASE(CONFIGURATION_MODE); 446 ENUM_CASE(CONFIGURATION_MODE);
445 ENUM_CASE(NORMAL_MODE); 447 ENUM_CASE(NORMAL_MODE);
446 } 448 }
447 return ""; 449 return "";
448 } 450 }
449 451
450 void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) {
451 DCHECK(CalledOnValidThread());
452 DCHECK(CanRunNudgeJobNow(priority));
453
454 DVLOG(2) << "Will run normal mode sync cycle with types "
455 << ModelTypeSetToString(session_context_->enabled_types());
456 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
457 bool premature_exit = !syncer_->NormalSyncShare(
458 GetEnabledAndUnthrottledTypes(),
459 nudge_tracker_,
460 session.get());
461 AdjustPolling(FORCE_RESET);
462 // Don't run poll job till the next time poll timer fires.
463 do_poll_after_credentials_updated_ = false;
464
465 bool success = !premature_exit
466 && !sessions::HasSyncerError(
467 session->status_controller().model_neutral_state());
468
469 if (success) {
470 // That cycle took care of any outstanding work we had.
471 SDVLOG(2) << "Nudge succeeded.";
472 nudge_tracker_.RecordSuccessfulSyncCycle();
473 scheduled_nudge_time_ = base::TimeTicks();
474
475 // If we're here, then we successfully reached the server. End all backoff.
476 wait_interval_.reset();
477 NotifyRetryTime(base::Time());
478 return;
479 } else {
480 HandleFailure(session->status_controller().model_neutral_state());
481 }
482 }
483
484 void SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) { 452 void SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) {
485 DCHECK(CalledOnValidThread()); 453 DCHECK(CalledOnValidThread());
486 DCHECK_EQ(mode_, CONFIGURATION_MODE); 454 DCHECK_EQ(mode_, CONFIGURATION_MODE);
487 DCHECK(pending_configure_params_ != NULL); 455 DCHECK(pending_configure_params_ != NULL);
488 456
489 if (!CanRunJobNow(priority)) { 457 if (!CanRunJobNow(priority)) {
490 SDVLOG(2) << "Unable to run configure job right now."; 458 SDVLOG(2) << "Unable to run configure job right now.";
491 if (!pending_configure_params_->retry_task.is_null()) { 459 if (!pending_configure_params_->retry_task.is_null()) {
492 pending_configure_params_->retry_task.Run(); 460 pending_configure_params_->retry_task.Run();
493 pending_configure_params_->retry_task.Reset(); 461 pending_configure_params_->retry_task.Reset();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 TimeDelta length = delay_provider_->GetDelay( 507 TimeDelta length = delay_provider_->GetDelay(
540 delay_provider_->GetInitialDelay(model_neutral_state)); 508 delay_provider_->GetInitialDelay(model_neutral_state));
541 wait_interval_.reset( 509 wait_interval_.reset(
542 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); 510 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
543 SDVLOG(2) << "Sync cycle failed. Will back off for " 511 SDVLOG(2) << "Sync cycle failed. Will back off for "
544 << wait_interval_->length.InMilliseconds() << "ms."; 512 << wait_interval_->length.InMilliseconds() << "ms.";
545 RestartWaiting(); 513 RestartWaiting();
546 } 514 }
547 } 515 }
548 516
549 void SyncSchedulerImpl::DoPollSyncSessionJob() { 517 bool SyncSchedulerImpl::DoNudgeSyncSessionJob(SyncSession* session) {
518 DCHECK(CalledOnValidThread());
519
520 DVLOG(2) << "Will run normal mode sync cycle with types "
521 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes());
522 return syncer_->NormalSyncShare(GetEnabledAndUnthrottledTypes(),
523 nudge_tracker_,
524 session);
525 }
526
527 bool SyncSchedulerImpl::DoPollSyncSessionJob(SyncSession* session) {
528 DCHECK(CalledOnValidThread());
529 DCHECK_EQ(mode_, NORMAL_MODE);
530
550 base::AutoReset<bool> protector(&no_scheduling_allowed_, true); 531 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
551 532
552 if (!CanRunJobNow(NORMAL_PRIORITY)) { 533 SDVLOG(2) << "Polling with types "
553 SDVLOG(2) << "Unable to run a poll job right now."; 534 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes());
554 return; 535 return syncer_->PollSyncShare(GetEnabledAndUnthrottledTypes(),
555 } 536 session);
537 }
556 538
557 if (mode_ != NORMAL_MODE) { 539 bool SyncSchedulerImpl::DoRetrySyncSessionJob(SyncSession* session) {
558 SDVLOG(2) << "Not running poll job in configure mode."; 540 DCHECK(CalledOnValidThread());
559 return; 541 DCHECK_EQ(mode_, NORMAL_MODE);
560 }
561 542
562 SDVLOG(2) << "Polling with types " 543 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
563 << ModelTypeSetToString(session_context_->enabled_types());
564 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
565 syncer_->PollSyncShare(
566 GetEnabledAndUnthrottledTypes(),
567 session.get());
568 544
569 AdjustPolling(FORCE_RESET); 545 SDVLOG(2) << "Retry with types "
570 546 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes());
571 if (IsCurrentlyThrottled()) { 547 return syncer_->RetrySyncShare(GetEnabledAndUnthrottledTypes(),
572 SDVLOG(2) << "Poll request got us throttled."; 548 session);
573 // The OnSilencedUntil() call set up the WaitInterval for us. All we need
574 // to do is start the timer.
575 RestartWaiting();
576 }
577 } 549 }
578 550
579 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { 551 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) {
580 DCHECK(CalledOnValidThread()); 552 DCHECK(CalledOnValidThread());
581 base::TimeTicks now = TimeTicks::Now(); 553 base::TimeTicks now = TimeTicks::Now();
582 // Update timing information for how often datatypes are triggering nudges. 554 // Update timing information for how often datatypes are triggering nudges.
583 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { 555 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
584 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; 556 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()];
585 last_local_nudges_by_model_type_[iter.Get()] = now; 557 last_local_nudges_by_model_type_[iter.Get()] = now;
586 if (previous.is_null()) 558 if (previous.is_null())
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 next_sync_session_job_priority_ = NORMAL_PRIORITY; 650 next_sync_session_job_priority_ = NORMAL_PRIORITY;
679 651
680 DCHECK(CalledOnValidThread()); 652 DCHECK(CalledOnValidThread());
681 if (mode_ == CONFIGURATION_MODE) { 653 if (mode_ == CONFIGURATION_MODE) {
682 if (pending_configure_params_) { 654 if (pending_configure_params_) {
683 SDVLOG(2) << "Found pending configure job"; 655 SDVLOG(2) << "Found pending configure job";
684 DoConfigurationSyncSessionJob(priority); 656 DoConfigurationSyncSessionJob(priority);
685 } 657 }
686 } else { 658 } else {
687 DCHECK(mode_ == NORMAL_MODE); 659 DCHECK(mode_ == NORMAL_MODE);
688 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(priority)) { 660 if (!CanRunNudgeJobNow(priority))
661 return;
662
663 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
rlarocque 2014/01/06 23:00:33 I'm strongly against this. I spent a lot of time
haitaol1 2014/01/07 19:03:37 Done.
664 bool tried_sync = false;
665
666 if (nudge_tracker_.IsSyncRequired()) {
689 SDVLOG(2) << "Found pending nudge job"; 667 SDVLOG(2) << "Found pending nudge job";
690 DoNudgeSyncSessionJob(priority); 668 tried_sync = DoNudgeSyncSessionJob(session.get());
669 } else if (nudge_tracker_.IsRetryRequired()) {
670 tried_sync = DoRetrySyncSessionJob(session.get());
691 } else if (do_poll_after_credentials_updated_ || 671 } else if (do_poll_after_credentials_updated_ ||
692 ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { 672 (base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval()) {
693 DoPollSyncSessionJob(); 673 tried_sync = DoPollSyncSessionJob(session.get());
694 // Poll timer fires infrequently. Usually by this time access token is
695 // already expired and poll job will fail with auth error. Set flag to
696 // retry poll once ProfileSyncService gets new access token, TryCanaryJob
697 // will be called after access token is retrieved.
698 if (HttpResponse::SYNC_AUTH_ERROR ==
699 session_context_->connection_manager()->server_status()) {
700 do_poll_after_credentials_updated_ = true;
701 }
702 } 674 }
675
676 if (tried_sync)
677 SyncSessionPostProcessing(session.get());
703 } 678 }
704 679
705 if (priority == CANARY_PRIORITY) { 680 if (priority == CANARY_PRIORITY) {
706 // If this is canary job then whatever result was don't run poll job till 681 // If this is canary job then whatever result was don't run poll job till
707 // the next time poll timer fires. 682 // the next time poll timer fires.
708 do_poll_after_credentials_updated_ = false; 683 do_poll_after_credentials_updated_ = false;
709 } 684 }
710 685
711 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) { 686 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) {
712 // If we succeeded, our wait interval would have been cleared. If it hasn't 687 // If we succeeded, our wait interval would have been cleared. If it hasn't
713 // been cleared, then we should increase our backoff interval and schedule 688 // been cleared, then we should increase our backoff interval and schedule
714 // another retry. 689 // another retry.
715 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length); 690 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length);
716 wait_interval_.reset( 691 wait_interval_.reset(
717 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); 692 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
718 SDVLOG(2) << "Sync cycle failed. Will back off for " 693 SDVLOG(2) << "Sync cycle failed. Will back off for "
719 << wait_interval_->length.InMilliseconds() << "ms."; 694 << wait_interval_->length.InMilliseconds() << "ms.";
720 RestartWaiting(); 695 RestartWaiting();
721 } 696 }
722 } 697 }
723 698
699 void SyncSchedulerImpl::SyncSessionPostProcessing(SyncSession* session) {
700 AdjustPolling(FORCE_RESET);
701 // Don't run poll job till the next time poll timer fires.
702 do_poll_after_credentials_updated_ = false;
703
704 bool success = !sessions::HasSyncerError(
705 session->status_controller().model_neutral_state());
706
707 if (success) {
708 // That cycle took care of any outstanding work we had.
709 SDVLOG(2) << "Sync session succeeded.";
710 nudge_tracker_.RecordSuccessfulSyncCycle();
rlarocque 2014/01/06 23:00:33 The SyncScheduler used to have code that looks lik
haitaol1 2014/01/07 19:03:37 Done.
711 scheduled_nudge_time_ = base::TimeTicks();
712
713 // If we're here, then we successfully reached the server. End all backoff.
714 wait_interval_.reset();
715 NotifyRetryTime(base::Time());
716
717 return;
718 } else {
719 HandleFailure(session->status_controller().model_neutral_state());
720 }
721 }
722
724 void SyncSchedulerImpl::PollTimerCallback() { 723 void SyncSchedulerImpl::PollTimerCallback() {
725 DCHECK(CalledOnValidThread()); 724 DCHECK(CalledOnValidThread());
726 if (no_scheduling_allowed_) { 725 if (no_scheduling_allowed_) {
727 // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in 726 // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in
728 // functions that are called only on the sync thread. This function is also 727 // functions that are called only on the sync thread. This function is also
729 // called only on the sync thread, and only when it is posted by an expiring 728 // called only on the sync thread, and only when it is posted by an expiring
730 // timer. If we find that no_scheduling_allowed_ is set here, then 729 // timer. If we find that no_scheduling_allowed_ is set here, then
731 // something is very wrong. Maybe someone mistakenly called us directly, or 730 // something is very wrong. Maybe someone mistakenly called us directly, or
732 // mishandled the book-keeping for no_scheduling_allowed_. 731 // mishandled the book-keeping for no_scheduling_allowed_.
733 NOTREACHED() << "Illegal to schedule job while session in progress."; 732 NOTREACHED() << "Illegal to schedule job while session in progress.";
734 return; 733 return;
735 } 734 }
736 735
737 TrySyncSessionJob(); 736 TrySyncSessionJob();
738 } 737 }
739 738
739 void SyncSchedulerImpl::RetryTimerCallback() {
740 TrySyncSessionJob();
741 }
742
740 void SyncSchedulerImpl::Unthrottle() { 743 void SyncSchedulerImpl::Unthrottle() {
741 DCHECK(CalledOnValidThread()); 744 DCHECK(CalledOnValidThread());
742 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode); 745 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode);
743 746
744 // We're no longer throttled, so clear the wait interval. 747 // We're no longer throttled, so clear the wait interval.
745 wait_interval_.reset(); 748 wait_interval_.reset();
746 NotifyRetryTime(base::Time()); 749 NotifyRetryTime(base::Time());
747 750
748 // We treat this as a 'canary' in the sense that it was originally scheduled 751 // We treat this as a 'canary' in the sense that it was originally scheduled
749 // to run some time ago, failed, and we now want to retry, versus a job that 752 // to run some time ago, failed, and we now want to retry, versus a job that
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 DCHECK(CalledOnValidThread()); 886 DCHECK(CalledOnValidThread());
884 if (ShouldRequestEarlyExit( 887 if (ShouldRequestEarlyExit(
885 snapshot.model_neutral_state().sync_protocol_error)) { 888 snapshot.model_neutral_state().sync_protocol_error)) {
886 SDVLOG(2) << "Sync Scheduler requesting early exit."; 889 SDVLOG(2) << "Sync Scheduler requesting early exit.";
887 Stop(); 890 Stop();
888 } 891 }
889 if (IsActionableError(snapshot.model_neutral_state().sync_protocol_error)) 892 if (IsActionableError(snapshot.model_neutral_state().sync_protocol_error))
890 OnActionableError(snapshot); 893 OnActionableError(snapshot);
891 } 894 }
892 895
896 void SyncSchedulerImpl::OnReceivedGuRetryDelaySeconds(int delay_seconds) {
897 nudge_tracker_.set_next_retry_time(
898 base::Time::Now() + base::TimeDelta::FromSeconds(delay_seconds));
899 retry_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
900 this, &SyncSchedulerImpl::RetryTimerCallback);
901 }
902
893 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { 903 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) {
894 DCHECK(CalledOnValidThread()); 904 DCHECK(CalledOnValidThread());
895 session_context_->set_notifications_enabled(notifications_enabled); 905 session_context_->set_notifications_enabled(notifications_enabled);
896 if (notifications_enabled) 906 if (notifications_enabled)
897 nudge_tracker_.OnInvalidationsEnabled(); 907 nudge_tracker_.OnInvalidationsEnabled();
898 else 908 else
899 nudge_tracker_.OnInvalidationsDisabled(); 909 nudge_tracker_.OnInvalidationsDisabled();
900 } 910 }
901 911
902 base::TimeDelta SyncSchedulerImpl::GetSessionsCommitDelay() const { 912 base::TimeDelta SyncSchedulerImpl::GetSessionsCommitDelay() const {
903 DCHECK(CalledOnValidThread()); 913 DCHECK(CalledOnValidThread());
904 return sessions_commit_delay_; 914 return sessions_commit_delay_;
905 } 915 }
906 916
907 #undef SDVLOG_LOC 917 #undef SDVLOG_LOC
908 918
909 #undef SDVLOG 919 #undef SDVLOG
910 920
911 #undef SLOG 921 #undef SLOG
912 922
913 #undef ENUM_CASE 923 #undef ENUM_CASE
914 924
915 } // namespace syncer 925 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698