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/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 |