| OLD | NEW |
| 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/notifier/ack_tracker.h" | 5 #include "sync/notifier/ack_tracker.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 13 #include "base/time/tick_clock.h" |
| 13 #include "google/cacheinvalidation/include/types.h" | 14 #include "google/cacheinvalidation/include/types.h" |
| 14 | 15 |
| 15 namespace syncer { | 16 namespace syncer { |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 // All times are in milliseconds. | 20 // All times are in milliseconds. |
| 20 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { | 21 const net::BackoffEntry::Policy kDefaultBackoffPolicy = { |
| 21 // Number of initial errors (in sequence) to ignore before applying | 22 // Number of initial errors (in sequence) to ignore before applying |
| 22 // exponential back-off rules. | 23 // exponential back-off rules. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 } | 67 } |
| 67 | 68 |
| 68 AckTracker::Entry::Entry(scoped_ptr<net::BackoffEntry> backoff, | 69 AckTracker::Entry::Entry(scoped_ptr<net::BackoffEntry> backoff, |
| 69 const ObjectIdSet& ids) | 70 const ObjectIdSet& ids) |
| 70 : backoff(backoff.Pass()), ids(ids) { | 71 : backoff(backoff.Pass()), ids(ids) { |
| 71 } | 72 } |
| 72 | 73 |
| 73 AckTracker::Entry::~Entry() { | 74 AckTracker::Entry::~Entry() { |
| 74 } | 75 } |
| 75 | 76 |
| 76 AckTracker::AckTracker(Delegate* delegate) | 77 AckTracker::AckTracker(base::TickClock* tick_clock, Delegate* delegate) |
| 77 : now_callback_(base::Bind(&base::TimeTicks::Now)), | 78 : create_backoff_entry_callback_(base::Bind(&CreateDefaultBackoffEntry)), |
| 78 create_backoff_entry_callback_(base::Bind(&CreateDefaultBackoffEntry)), | 79 tick_clock_(tick_clock), |
| 79 delegate_(delegate) { | 80 delegate_(delegate) { |
| 81 DCHECK(tick_clock_); |
| 80 DCHECK(delegate_); | 82 DCHECK(delegate_); |
| 81 } | 83 } |
| 82 | 84 |
| 83 AckTracker::~AckTracker() { | 85 AckTracker::~AckTracker() { |
| 84 DCHECK(thread_checker_.CalledOnValidThread()); | 86 DCHECK(thread_checker_.CalledOnValidThread()); |
| 85 | 87 |
| 86 Clear(); | 88 Clear(); |
| 87 } | 89 } |
| 88 | 90 |
| 89 void AckTracker::Clear() { | 91 void AckTracker::Clear() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 NudgeTimer(); | 134 NudgeTimer(); |
| 133 } | 135 } |
| 134 | 136 |
| 135 void AckTracker::NudgeTimer() { | 137 void AckTracker::NudgeTimer() { |
| 136 DCHECK(thread_checker_.CalledOnValidThread()); | 138 DCHECK(thread_checker_.CalledOnValidThread()); |
| 137 | 139 |
| 138 if (queue_.empty()) { | 140 if (queue_.empty()) { |
| 139 return; | 141 return; |
| 140 } | 142 } |
| 141 | 143 |
| 142 const base::TimeTicks now = now_callback_.Run(); | 144 const base::TimeTicks now = tick_clock_->NowTicks(); |
| 143 // There are two cases when the timer needs to be started: | 145 // There are two cases when the timer needs to be started: |
| 144 // 1. |desired_run_time_| is in the past. By definition, the timer has already | 146 // 1. |desired_run_time_| is in the past. By definition, the timer has already |
| 145 // fired at this point. Since the queue is non-empty, we need to set the | 147 // fired at this point. Since the queue is non-empty, we need to set the |
| 146 // timer to fire again. | 148 // timer to fire again. |
| 147 // 2. The timer is already running but we need it to fire sooner if the first | 149 // 2. The timer is already running but we need it to fire sooner if the first |
| 148 // entry's timeout occurs before |desired_run_time_|. | 150 // entry's timeout occurs before |desired_run_time_|. |
| 149 if (desired_run_time_ <= now || queue_.begin()->first < desired_run_time_) { | 151 if (desired_run_time_ <= now || queue_.begin()->first < desired_run_time_) { |
| 150 base::TimeDelta delay = queue_.begin()->first - now; | 152 base::TimeDelta delay = queue_.begin()->first - now; |
| 151 if (delay < base::TimeDelta()) { | 153 if (delay < base::TimeDelta()) { |
| 152 delay = base::TimeDelta(); | 154 delay = base::TimeDelta(); |
| 153 } | 155 } |
| 154 timer_.Start(FROM_HERE, delay, this, &AckTracker::OnTimeout); | 156 timer_.Start(FROM_HERE, delay, this, &AckTracker::OnTimeout); |
| 155 desired_run_time_ = queue_.begin()->first; | 157 desired_run_time_ = queue_.begin()->first; |
| 156 } | 158 } |
| 157 } | 159 } |
| 158 | 160 |
| 159 void AckTracker::OnTimeout() { | 161 void AckTracker::OnTimeout() { |
| 160 DCHECK(thread_checker_.CalledOnValidThread()); | 162 DCHECK(thread_checker_.CalledOnValidThread()); |
| 161 | 163 |
| 162 OnTimeoutAt(now_callback_.Run()); | 164 OnTimeoutAt(tick_clock_->NowTicks()); |
| 163 } | 165 } |
| 164 | 166 |
| 165 void AckTracker::OnTimeoutAt(base::TimeTicks now) { | 167 void AckTracker::OnTimeoutAt(base::TimeTicks now) { |
| 166 DCHECK(thread_checker_.CalledOnValidThread()); | 168 DCHECK(thread_checker_.CalledOnValidThread()); |
| 167 | 169 |
| 168 if (queue_.empty()) | 170 if (queue_.empty()) |
| 169 return; | 171 return; |
| 170 | 172 |
| 171 ObjectIdSet expired_ids; | 173 ObjectIdSet expired_ids; |
| 172 std::multimap<base::TimeTicks, Entry*>::iterator end = | 174 std::multimap<base::TimeTicks, Entry*>::iterator end = |
| 173 queue_.upper_bound(now); | 175 queue_.upper_bound(now); |
| 174 std::vector<Entry*> expired_entries; | 176 std::vector<Entry*> expired_entries; |
| 175 for (std::multimap<base::TimeTicks, Entry*>::iterator it = queue_.begin(); | 177 for (std::multimap<base::TimeTicks, Entry*>::iterator it = queue_.begin(); |
| 176 it != end; ++it) { | 178 it != end; ++it) { |
| 177 expired_ids.insert(it->second->ids.begin(), it->second->ids.end()); | 179 expired_ids.insert(it->second->ids.begin(), it->second->ids.end()); |
| 178 it->second->backoff->InformOfRequest(false /* succeeded */); | 180 it->second->backoff->InformOfRequest(false /* succeeded */); |
| 179 expired_entries.push_back(it->second); | 181 expired_entries.push_back(it->second); |
| 180 } | 182 } |
| 181 queue_.erase(queue_.begin(), end); | 183 queue_.erase(queue_.begin(), end); |
| 182 for (std::vector<Entry*>::const_iterator it = expired_entries.begin(); | 184 for (std::vector<Entry*>::const_iterator it = expired_entries.begin(); |
| 183 it != expired_entries.end(); ++it) { | 185 it != expired_entries.end(); ++it) { |
| 184 queue_.insert(std::make_pair((*it)->backoff->GetReleaseTime(), *it)); | 186 queue_.insert(std::make_pair((*it)->backoff->GetReleaseTime(), *it)); |
| 185 } | 187 } |
| 186 delegate_->OnTimeout(expired_ids); | 188 delegate_->OnTimeout(expired_ids); |
| 187 NudgeTimer(); | 189 NudgeTimer(); |
| 188 } | 190 } |
| 189 | 191 |
| 190 // Testing helpers. | 192 // Testing helpers. |
| 191 void AckTracker::SetNowCallbackForTest( | |
| 192 const NowCallback& now_callback) { | |
| 193 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 194 | |
| 195 now_callback_ = now_callback; | |
| 196 } | |
| 197 | |
| 198 void AckTracker::SetCreateBackoffEntryCallbackForTest( | 193 void AckTracker::SetCreateBackoffEntryCallbackForTest( |
| 199 const CreateBackoffEntryCallback& create_backoff_entry_callback) { | 194 const CreateBackoffEntryCallback& create_backoff_entry_callback) { |
| 200 DCHECK(thread_checker_.CalledOnValidThread()); | 195 DCHECK(thread_checker_.CalledOnValidThread()); |
| 201 | 196 |
| 202 create_backoff_entry_callback_ = create_backoff_entry_callback; | 197 create_backoff_entry_callback_ = create_backoff_entry_callback; |
| 203 } | 198 } |
| 204 | 199 |
| 205 bool AckTracker::TriggerTimeoutAtForTest(base::TimeTicks now) { | 200 bool AckTracker::TriggerTimeoutAtForTest(base::TimeTicks now) { |
| 206 DCHECK(thread_checker_.CalledOnValidThread()); | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 207 | 202 |
| 208 bool no_timeouts_before_now = (queue_.lower_bound(now) == queue_.begin()); | 203 bool no_timeouts_before_now = (queue_.lower_bound(now) == queue_.begin()); |
| 209 OnTimeoutAt(now); | 204 OnTimeoutAt(now); |
| 210 return no_timeouts_before_now; | 205 return no_timeouts_before_now; |
| 211 } | 206 } |
| 212 | 207 |
| 213 bool AckTracker::IsQueueEmptyForTest() const { | 208 bool AckTracker::IsQueueEmptyForTest() const { |
| 214 DCHECK(thread_checker_.CalledOnValidThread()); | 209 DCHECK(thread_checker_.CalledOnValidThread()); |
| 215 | 210 |
| 216 return queue_.empty(); | 211 return queue_.empty(); |
| 217 } | 212 } |
| 218 | 213 |
| 219 const base::Timer& AckTracker::GetTimerForTest() const { | 214 const base::Timer& AckTracker::GetTimerForTest() const { |
| 220 DCHECK(thread_checker_.CalledOnValidThread()); | 215 DCHECK(thread_checker_.CalledOnValidThread()); |
| 221 | 216 |
| 222 return timer_; | 217 return timer_; |
| 223 } | 218 } |
| 224 | 219 |
| 225 } // namespace syncer | 220 } // namespace syncer |
| OLD | NEW |