Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / net / http / disk_cache_based_quic_server_info.cc
blob3951b2e5c0bb17bb658e97e2ce090575ffe2dcdf
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/disk_cache_based_quic_server_info.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_cache.h"
17 #include "net/http/http_network_session.h"
18 #include "net/quic/quic_server_id.h"
20 namespace net {
22 // Some APIs inside disk_cache take a handle that the caller must keep alive
23 // until the API has finished its asynchronous execution.
25 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the
26 // operation completes causing a use-after-free.
28 // This data shim struct is meant to provide a location for the disk_cache
29 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo
30 // object has been deleted. The lifetime for instances of this struct
31 // should be bound to the CompletionCallback that is passed to the disk_cache
32 // API. We do this by binding an instance of this struct to an unused
33 // parameter for OnIOComplete() using base::Owned().
35 // This is a hack. A better fix is to make it so that the disk_cache APIs
36 // take a Callback to a mutator for setting the output value rather than
37 // writing into a raw handle. Then the caller can just pass in a Callback
38 // bound to WeakPtr for itself. This callback would correctly "no-op" itself
39 // when the DiskCacheBasedQuicServerInfo object is deleted.
41 // TODO(ajwong): Change disk_cache's API to return results via Callback.
42 struct DiskCacheBasedQuicServerInfo::CacheOperationDataShim {
43 CacheOperationDataShim() : backend(NULL), entry(NULL) {}
45 disk_cache::Backend* backend;
46 disk_cache::Entry* entry;
49 DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo(
50 const QuicServerId& server_id,
51 HttpCache* http_cache)
52 : QuicServerInfo(server_id),
53 data_shim_(new CacheOperationDataShim()),
54 state_(GET_BACKEND),
55 ready_(false),
56 found_entry_(false),
57 server_id_(server_id),
58 http_cache_(http_cache),
59 backend_(NULL),
60 entry_(NULL),
61 last_failure_(NO_FAILURE),
62 weak_factory_(this) {
63 io_callback_ =
64 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
65 weak_factory_.GetWeakPtr(),
66 base::Owned(data_shim_)); // Ownership assigned.
69 void DiskCacheBasedQuicServerInfo::Start() {
70 DCHECK(CalledOnValidThread());
71 DCHECK_EQ(GET_BACKEND, state_);
72 DCHECK_EQ(last_failure_, NO_FAILURE);
73 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
74 load_start_time_ = base::TimeTicks::Now();
75 DoLoop(OK);
78 int DiskCacheBasedQuicServerInfo::WaitForDataReady(
79 const CompletionCallback& callback) {
80 DCHECK(CalledOnValidThread());
81 DCHECK_NE(GET_BACKEND, state_);
82 wait_for_data_start_time_ = base::TimeTicks::Now();
84 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
85 if (ready_) {
86 wait_for_data_end_time_ = base::TimeTicks::Now();
87 RecordLastFailure();
88 return OK;
91 if (!callback.is_null()) {
92 // Prevent a new callback for WaitForDataReady overwriting an existing
93 // pending callback (|wait_for_ready_callback_|).
94 if (!wait_for_ready_callback_.is_null()) {
95 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
96 return ERR_INVALID_ARGUMENT;
98 wait_for_ready_callback_ = callback;
101 return ERR_IO_PENDING;
104 void DiskCacheBasedQuicServerInfo::ResetWaitForDataReadyCallback() {
105 DCHECK(CalledOnValidThread());
106 wait_for_ready_callback_.Reset();
109 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() {
110 DCHECK(CalledOnValidThread());
112 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
113 if (!wait_for_ready_callback_.is_null()) {
114 RecordLastFailure();
115 wait_for_ready_callback_.Reset();
119 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
120 return ready_;
123 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
124 // The data can be persisted if it has been loaded from the disk cache
125 // and there are no pending writes.
126 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
127 if (ready_ && new_data_.empty())
128 return true;
129 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE);
130 return false;
133 void DiskCacheBasedQuicServerInfo::Persist() {
134 DCHECK(CalledOnValidThread());
135 if (!IsReadyToPersist()) {
136 // Handle updates while a write is pending or if we haven't loaded from disk
137 // cache. Save the data to be written into a temporary buffer and then
138 // persist that data when we are ready to persist.
139 pending_write_data_ = Serialize();
140 return;
142 PersistInternal();
145 void DiskCacheBasedQuicServerInfo::PersistInternal() {
146 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
147 tracked_objects::ScopedTracker tracking_profile(
148 FROM_HERE_WITH_EXPLICIT_FUNCTION(
149 "422516 DiskCacheBasedQuicServerInfo::PersistInternal"));
151 DCHECK(CalledOnValidThread());
152 DCHECK_NE(GET_BACKEND, state_);
153 DCHECK(new_data_.empty());
154 CHECK(ready_);
155 DCHECK(wait_for_ready_callback_.is_null());
157 if (pending_write_data_.empty()) {
158 new_data_ = Serialize();
159 } else {
160 new_data_ = pending_write_data_;
161 pending_write_data_.clear();
164 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
165 if (!backend_) {
166 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
167 return;
170 state_ = CREATE_OR_OPEN;
171 DoLoop(OK);
174 void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
175 DCHECK(CalledOnValidThread());
176 DCHECK_NE(GET_BACKEND, state_);
178 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
179 if (!backend_) {
180 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
181 return;
184 backend_->OnExternalCacheHit(key());
187 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
188 DCHECK(wait_for_ready_callback_.is_null());
189 if (entry_)
190 entry_->Close();
193 std::string DiskCacheBasedQuicServerInfo::key() const {
194 return "quicserverinfo:" + server_id_.ToString();
197 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused,
198 int rv) {
199 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
200 tracked_objects::ScopedTracker tracking_profile(
201 FROM_HERE_WITH_EXPLICIT_FUNCTION(
202 "422516 DiskCacheBasedQuicServerInfo::OnIOComplete"));
204 DCHECK_NE(NONE, state_);
205 rv = DoLoop(rv);
206 if (rv == ERR_IO_PENDING)
207 return;
209 base::WeakPtr<DiskCacheBasedQuicServerInfo> weak_this =
210 weak_factory_.GetWeakPtr();
212 if (!wait_for_ready_callback_.is_null()) {
213 wait_for_data_end_time_ = base::TimeTicks::Now();
214 RecordLastFailure();
215 base::ResetAndReturn(&wait_for_ready_callback_).Run(rv);
217 // |wait_for_ready_callback_| could delete the object if there is an error.
218 // Check if |weak_this| still exists before accessing it.
219 if (weak_this.get() && ready_ && !pending_write_data_.empty()) {
220 DCHECK_EQ(NONE, state_);
221 PersistInternal();
225 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) {
226 do {
227 switch (state_) {
228 case GET_BACKEND:
229 rv = DoGetBackend();
230 break;
231 case GET_BACKEND_COMPLETE:
232 rv = DoGetBackendComplete(rv);
233 break;
234 case OPEN:
235 rv = DoOpen();
236 break;
237 case OPEN_COMPLETE:
238 rv = DoOpenComplete(rv);
239 break;
240 case READ:
241 rv = DoRead();
242 break;
243 case READ_COMPLETE:
244 rv = DoReadComplete(rv);
245 break;
246 case WAIT_FOR_DATA_READY_DONE:
247 rv = DoWaitForDataReadyDone();
248 break;
249 case CREATE_OR_OPEN:
250 rv = DoCreateOrOpen();
251 break;
252 case CREATE_OR_OPEN_COMPLETE:
253 rv = DoCreateOrOpenComplete(rv);
254 break;
255 case WRITE:
256 rv = DoWrite();
257 break;
258 case WRITE_COMPLETE:
259 rv = DoWriteComplete(rv);
260 break;
261 case SET_DONE:
262 rv = DoSetDone();
263 break;
264 default:
265 rv = OK;
266 NOTREACHED();
268 } while (rv != ERR_IO_PENDING && state_ != NONE);
270 return rv;
273 int DiskCacheBasedQuicServerInfo::DoGetBackendComplete(int rv) {
274 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
275 tracked_objects::ScopedTracker tracking_profile(
276 FROM_HERE_WITH_EXPLICIT_FUNCTION(
277 "422516 DiskCacheBasedQuicServerInfo::DoGetBackendComplete"));
279 if (rv == OK) {
280 backend_ = data_shim_->backend;
281 state_ = OPEN;
282 } else {
283 RecordQuicServerInfoFailure(GET_BACKEND_FAILURE);
284 state_ = WAIT_FOR_DATA_READY_DONE;
286 return OK;
289 int DiskCacheBasedQuicServerInfo::DoOpenComplete(int rv) {
290 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
291 tracked_objects::ScopedTracker tracking_profile(
292 FROM_HERE_WITH_EXPLICIT_FUNCTION(
293 "422516 DiskCacheBasedQuicServerInfo::DoOpenComplete"));
295 if (rv == OK) {
296 entry_ = data_shim_->entry;
297 state_ = READ;
298 found_entry_ = true;
299 } else {
300 RecordQuicServerInfoFailure(OPEN_FAILURE);
301 state_ = WAIT_FOR_DATA_READY_DONE;
304 return OK;
307 int DiskCacheBasedQuicServerInfo::DoReadComplete(int rv) {
308 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
309 tracked_objects::ScopedTracker tracking_profile(
310 FROM_HERE_WITH_EXPLICIT_FUNCTION(
311 "422516 DiskCacheBasedQuicServerInfo::DoReadComplete"));
313 if (rv > 0)
314 data_.assign(read_buffer_->data(), rv);
315 else if (rv < 0)
316 RecordQuicServerInfoFailure(READ_FAILURE);
318 state_ = WAIT_FOR_DATA_READY_DONE;
319 return OK;
322 int DiskCacheBasedQuicServerInfo::DoWriteComplete(int rv) {
323 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
324 tracked_objects::ScopedTracker tracking_profile(
325 FROM_HERE_WITH_EXPLICIT_FUNCTION(
326 "422516 DiskCacheBasedQuicServerInfo::DoWriteComplete"));
328 if (rv < 0)
329 RecordQuicServerInfoFailure(WRITE_FAILURE);
330 state_ = SET_DONE;
331 return OK;
334 int DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete(int rv) {
335 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
336 tracked_objects::ScopedTracker tracking_profile(
337 FROM_HERE_WITH_EXPLICIT_FUNCTION(
338 "422516 DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete"));
340 if (rv != OK) {
341 RecordQuicServerInfoFailure(CREATE_OR_OPEN_FAILURE);
342 state_ = SET_DONE;
343 } else {
344 if (!entry_) {
345 entry_ = data_shim_->entry;
346 found_entry_ = true;
348 DCHECK(entry_);
349 state_ = WRITE;
351 return OK;
354 int DiskCacheBasedQuicServerInfo::DoGetBackend() {
355 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
356 tracked_objects::ScopedTracker tracking_profile(
357 FROM_HERE_WITH_EXPLICIT_FUNCTION(
358 "422516 DiskCacheBasedQuicServerInfo::DoGetBackend"));
360 state_ = GET_BACKEND_COMPLETE;
361 return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
364 int DiskCacheBasedQuicServerInfo::DoOpen() {
365 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
366 tracked_objects::ScopedTracker tracking_profile(
367 FROM_HERE_WITH_EXPLICIT_FUNCTION(
368 "422516 DiskCacheBasedQuicServerInfo::DoOpen"));
370 state_ = OPEN_COMPLETE;
371 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
374 int DiskCacheBasedQuicServerInfo::DoRead() {
375 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
376 tracked_objects::ScopedTracker tracking_profile(
377 FROM_HERE_WITH_EXPLICIT_FUNCTION(
378 "422516 DiskCacheBasedQuicServerInfo::DoRead"));
380 const int32 size = entry_->GetDataSize(0 /* index */);
381 if (!size) {
382 state_ = WAIT_FOR_DATA_READY_DONE;
383 return OK;
386 read_buffer_ = new IOBuffer(size);
387 state_ = READ_COMPLETE;
388 return entry_->ReadData(
389 0 /* index */, 0 /* offset */, read_buffer_.get(), size, io_callback_);
392 int DiskCacheBasedQuicServerInfo::DoWrite() {
393 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
394 tracked_objects::ScopedTracker tracking_profile(
395 FROM_HERE_WITH_EXPLICIT_FUNCTION(
396 "422516 DiskCacheBasedQuicServerInfo::DoWrite"));
398 write_buffer_ = new IOBuffer(new_data_.size());
399 memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
400 state_ = WRITE_COMPLETE;
402 return entry_->WriteData(0 /* index */,
403 0 /* offset */,
404 write_buffer_.get(),
405 new_data_.size(),
406 io_callback_,
407 true /* truncate */);
410 int DiskCacheBasedQuicServerInfo::DoCreateOrOpen() {
411 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
412 tracked_objects::ScopedTracker tracking_profile(
413 FROM_HERE_WITH_EXPLICIT_FUNCTION(
414 "422516 DiskCacheBasedQuicServerInfo::DoCreateOrOpen"));
416 state_ = CREATE_OR_OPEN_COMPLETE;
417 if (entry_)
418 return OK;
420 if (found_entry_) {
421 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
424 return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
427 int DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone() {
428 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
429 tracked_objects::ScopedTracker tracking_profile(
430 FROM_HERE_WITH_EXPLICIT_FUNCTION(
431 "422516 DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone"));
433 DCHECK(!ready_);
434 state_ = NONE;
435 ready_ = true;
436 // We close the entry because, if we shutdown before ::Persist is called,
437 // then we might leak a cache reference, which causes a DCHECK on shutdown.
438 if (entry_)
439 entry_->Close();
440 entry_ = NULL;
442 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE);
443 if (!Parse(data_)) {
444 if (data_.empty())
445 RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE);
446 else
447 RecordQuicServerInfoFailure(PARSE_FAILURE);
450 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheLoadTime",
451 base::TimeTicks::Now() - load_start_time_);
452 return OK;
455 int DiskCacheBasedQuicServerInfo::DoSetDone() {
456 if (entry_)
457 entry_->Close();
458 entry_ = NULL;
459 new_data_.clear();
460 state_ = NONE;
461 return OK;
464 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
465 QuicServerInfoAPICall call) {
466 if (!backend_) {
467 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
468 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
469 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
470 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
471 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
472 } else {
473 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
474 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
478 void DiskCacheBasedQuicServerInfo::RecordLastFailure() {
479 if (last_failure_ != NO_FAILURE) {
480 UMA_HISTOGRAM_ENUMERATION(
481 "Net.QuicDiskCache.FailureReason.WaitForDataReady",
482 last_failure_, NUM_OF_FAILURES);
484 last_failure_ = NO_FAILURE;
487 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
488 FailureReason failure) {
489 last_failure_ = failure;
491 if (!backend_) {
492 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
493 failure, NUM_OF_FAILURES);
494 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
495 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
496 failure, NUM_OF_FAILURES);
497 } else {
498 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
499 failure, NUM_OF_FAILURES);
503 } // namespace net