| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "net/http/disk_cache_based_quic_server_info.h" | 5 #include "net/http/disk_cache_based_quic_server_info.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/callback_helpers.h" |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 11 #include "net/base/completion_callback.h" | 12 #include "net/base/completion_callback.h" |
| 12 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
| 13 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 14 #include "net/http/http_cache.h" | 15 #include "net/http/http_cache.h" |
| 15 #include "net/http/http_network_session.h" | 16 #include "net/http/http_network_session.h" |
| 16 #include "net/quic/quic_server_id.h" | 17 #include "net/quic/quic_server_id.h" |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 20 // Histogram that tracks number of times data read/parse/write API calls of | |
| 21 // QuicServerInfo to and from disk cache is called. | |
| 22 enum QuicServerInfoAPICall { | |
| 23 QUIC_SERVER_INFO_START = 0, | |
| 24 QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1, | |
| 25 QUIC_SERVER_INFO_PARSE = 2, | |
| 26 QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3, | |
| 27 QUIC_SERVER_INFO_READY_TO_PERSIST = 4, | |
| 28 QUIC_SERVER_INFO_PERSIST = 5, | |
| 29 QUIC_SERVER_INFO_NUM_OF_API_CALLS = 6, | |
| 30 }; | |
| 31 | |
| 32 // Histogram that tracks failure reasons to read/load/write of QuicServerInfo to | |
| 33 // and from disk cache. | |
| 34 enum FailureReason { | |
| 35 WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0, | |
| 36 GET_BACKEND_FAILURE = 1, | |
| 37 OPEN_FAILURE = 2, | |
| 38 CREATE_OR_OPEN_FAILURE = 3, | |
| 39 PARSE_NO_DATA_FAILURE = 4, | |
| 40 PARSE_FAILURE = 5, | |
| 41 READ_FAILURE = 6, | |
| 42 READY_TO_PERSIST_FAILURE = 7, | |
| 43 PERSIST_NO_BACKEND_FAILURE = 8, | |
| 44 WRITE_FAILURE = 9, | |
| 45 NUM_OF_FAILURES = 10, | |
| 46 }; | |
| 47 | |
| 48 void RecordQuicServerInfoStatus(QuicServerInfoAPICall call) { | |
| 49 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall", call, | |
| 50 QUIC_SERVER_INFO_NUM_OF_API_CALLS); | |
| 51 } | |
| 52 | |
| 53 void RecordQuicServerInfoFailure(FailureReason failure) { | |
| 54 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason", failure, | |
| 55 NUM_OF_FAILURES); | |
| 56 } | |
| 57 | |
| 58 // Some APIs inside disk_cache take a handle that the caller must keep alive | 21 // Some APIs inside disk_cache take a handle that the caller must keep alive |
| 59 // until the API has finished its asynchronous execution. | 22 // until the API has finished its asynchronous execution. |
| 60 // | 23 // |
| 61 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the | 24 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the |
| 62 // operation completes causing a use-after-free. | 25 // operation completes causing a use-after-free. |
| 63 // | 26 // |
| 64 // This data shim struct is meant to provide a location for the disk_cache | 27 // This data shim struct is meant to provide a location for the disk_cache |
| 65 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo | 28 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo |
| 66 // object has been deleted. The lifetime for instances of this struct | 29 // object has been deleted. The lifetime for instances of this struct |
| 67 // should be bound to the CompletionCallback that is passed to the disk_cache | 30 // should be bound to the CompletionCallback that is passed to the disk_cache |
| (...skipping 19 matching lines...) Expand all Loading... |
| 87 HttpCache* http_cache) | 50 HttpCache* http_cache) |
| 88 : QuicServerInfo(server_id), | 51 : QuicServerInfo(server_id), |
| 89 data_shim_(new CacheOperationDataShim()), | 52 data_shim_(new CacheOperationDataShim()), |
| 90 state_(GET_BACKEND), | 53 state_(GET_BACKEND), |
| 91 ready_(false), | 54 ready_(false), |
| 92 found_entry_(false), | 55 found_entry_(false), |
| 93 server_id_(server_id), | 56 server_id_(server_id), |
| 94 http_cache_(http_cache), | 57 http_cache_(http_cache), |
| 95 backend_(NULL), | 58 backend_(NULL), |
| 96 entry_(NULL), | 59 entry_(NULL), |
| 60 last_failure_(NO_FAILURE), |
| 97 weak_factory_(this) { | 61 weak_factory_(this) { |
| 98 io_callback_ = | 62 io_callback_ = |
| 99 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete, | 63 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete, |
| 100 weak_factory_.GetWeakPtr(), | 64 weak_factory_.GetWeakPtr(), |
| 101 base::Owned(data_shim_)); // Ownership assigned. | 65 base::Owned(data_shim_)); // Ownership assigned. |
| 102 } | 66 } |
| 103 | 67 |
| 104 void DiskCacheBasedQuicServerInfo::Start() { | 68 void DiskCacheBasedQuicServerInfo::Start() { |
| 105 DCHECK(CalledOnValidThread()); | 69 DCHECK(CalledOnValidThread()); |
| 106 DCHECK_EQ(GET_BACKEND, state_); | 70 DCHECK_EQ(GET_BACKEND, state_); |
| 71 DCHECK_EQ(last_failure_, NO_FAILURE); |
| 107 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START); | 72 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START); |
| 108 load_start_time_ = base::TimeTicks::Now(); | 73 load_start_time_ = base::TimeTicks::Now(); |
| 109 DoLoop(OK); | 74 DoLoop(OK); |
| 110 } | 75 } |
| 111 | 76 |
| 112 int DiskCacheBasedQuicServerInfo::WaitForDataReady( | 77 int DiskCacheBasedQuicServerInfo::WaitForDataReady( |
| 113 const CompletionCallback& callback) { | 78 const CompletionCallback& callback) { |
| 114 DCHECK(CalledOnValidThread()); | 79 DCHECK(CalledOnValidThread()); |
| 115 DCHECK_NE(GET_BACKEND, state_); | 80 DCHECK_NE(GET_BACKEND, state_); |
| 116 | 81 |
| 117 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY); | 82 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY); |
| 118 if (ready_) | 83 if (ready_) { |
| 84 RecordLastFailure(); |
| 119 return OK; | 85 return OK; |
| 86 } |
| 120 | 87 |
| 121 if (!callback.is_null()) { | 88 if (!callback.is_null()) { |
| 122 // Prevent a new callback for WaitForDataReady overwriting an existing | 89 // Prevent a new callback for WaitForDataReady overwriting an existing |
| 123 // pending callback (|user_callback_|). | 90 // pending callback (|wait_for_ready_callback_|). |
| 124 if (!user_callback_.is_null()) { | 91 if (!wait_for_ready_callback_.is_null()) { |
| 125 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE); | 92 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE); |
| 126 return ERR_INVALID_ARGUMENT; | 93 return ERR_INVALID_ARGUMENT; |
| 127 } | 94 } |
| 128 user_callback_ = callback; | 95 wait_for_ready_callback_ = callback; |
| 129 } | 96 } |
| 130 | 97 |
| 131 return ERR_IO_PENDING; | 98 return ERR_IO_PENDING; |
| 132 } | 99 } |
| 133 | 100 |
| 134 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() { | 101 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() { |
| 135 DCHECK(CalledOnValidThread()); | 102 DCHECK(CalledOnValidThread()); |
| 136 | 103 |
| 137 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL); | 104 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL); |
| 138 if (!user_callback_.is_null()) | 105 if (!wait_for_ready_callback_.is_null()) { |
| 139 user_callback_.Reset(); | 106 RecordLastFailure(); |
| 107 wait_for_ready_callback_.Reset(); |
| 108 } |
| 140 } | 109 } |
| 141 | 110 |
| 142 bool DiskCacheBasedQuicServerInfo::IsDataReady() { | 111 bool DiskCacheBasedQuicServerInfo::IsDataReady() { |
| 143 return ready_; | 112 return ready_; |
| 144 } | 113 } |
| 145 | 114 |
| 146 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() { | 115 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() { |
| 147 // TODO(rtenneti): Handle updates while a write is pending. Change | |
| 148 // Persist() to save the data to be written into a temporary buffer | |
| 149 // and then persist that data when we are ready to persist. | |
| 150 // | |
| 151 // The data can be persisted if it has been loaded from the disk cache | 116 // The data can be persisted if it has been loaded from the disk cache |
| 152 // and there are no pending writes. | 117 // and there are no pending writes. |
| 153 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST); | 118 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST); |
| 154 if (ready_ && new_data_.empty()) | 119 if (ready_ && new_data_.empty()) |
| 155 return true; | 120 return true; |
| 156 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE); | 121 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE); |
| 157 return false; | 122 return false; |
| 158 } | 123 } |
| 159 | 124 |
| 160 void DiskCacheBasedQuicServerInfo::Persist() { | 125 void DiskCacheBasedQuicServerInfo::Persist() { |
| 161 DCHECK(CalledOnValidThread()); | 126 DCHECK(CalledOnValidThread()); |
| 127 if (!IsReadyToPersist()) { |
| 128 // Handle updates while a write is pending or if we haven't loaded from disk |
| 129 // cache. Save the data to be written into a temporary buffer and then |
| 130 // persist that data when we are ready to persist. |
| 131 pending_write_data_ = Serialize(); |
| 132 return; |
| 133 } |
| 134 PersistInternal(); |
| 135 } |
| 136 |
| 137 void DiskCacheBasedQuicServerInfo::PersistInternal() { |
| 138 DCHECK(CalledOnValidThread()); |
| 162 DCHECK_NE(GET_BACKEND, state_); | 139 DCHECK_NE(GET_BACKEND, state_); |
| 163 | |
| 164 DCHECK(new_data_.empty()); | 140 DCHECK(new_data_.empty()); |
| 165 CHECK(ready_); | 141 CHECK(ready_); |
| 166 DCHECK(user_callback_.is_null()); | 142 DCHECK(wait_for_ready_callback_.is_null()); |
| 167 new_data_ = Serialize(); | 143 |
| 144 if (pending_write_data_.empty()) { |
| 145 new_data_ = Serialize(); |
| 146 } else { |
| 147 new_data_ = pending_write_data_; |
| 148 pending_write_data_.clear(); |
| 149 } |
| 168 | 150 |
| 169 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST); | 151 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST); |
| 170 if (!backend_) { | 152 if (!backend_) { |
| 171 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE); | 153 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE); |
| 172 return; | 154 return; |
| 173 } | 155 } |
| 174 | 156 |
| 175 state_ = CREATE_OR_OPEN; | 157 state_ = CREATE_OR_OPEN; |
| 176 DoLoop(OK); | 158 DoLoop(OK); |
| 177 } | 159 } |
| 178 | 160 |
| 161 void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() { |
| 162 DCHECK(CalledOnValidThread()); |
| 163 DCHECK_NE(GET_BACKEND, state_); |
| 164 |
| 165 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT); |
| 166 if (!backend_) { |
| 167 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE); |
| 168 return; |
| 169 } |
| 170 |
| 171 backend_->OnExternalCacheHit(key()); |
| 172 } |
| 173 |
| 179 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() { | 174 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() { |
| 180 DCHECK(user_callback_.is_null()); | 175 DCHECK(wait_for_ready_callback_.is_null()); |
| 181 if (entry_) | 176 if (entry_) |
| 182 entry_->Close(); | 177 entry_->Close(); |
| 183 } | 178 } |
| 184 | 179 |
| 185 std::string DiskCacheBasedQuicServerInfo::key() const { | 180 std::string DiskCacheBasedQuicServerInfo::key() const { |
| 186 return "quicserverinfo:" + server_id_.ToString(); | 181 return "quicserverinfo:" + server_id_.ToString(); |
| 187 } | 182 } |
| 188 | 183 |
| 189 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused, | 184 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused, |
| 190 int rv) { | 185 int rv) { |
| 191 DCHECK_NE(NONE, state_); | 186 DCHECK_NE(NONE, state_); |
| 192 rv = DoLoop(rv); | 187 rv = DoLoop(rv); |
| 193 if (rv != ERR_IO_PENDING && !user_callback_.is_null()) { | 188 if (rv == ERR_IO_PENDING) |
| 194 CompletionCallback callback = user_callback_; | 189 return; |
| 195 user_callback_.Reset(); | 190 if (!wait_for_ready_callback_.is_null()) { |
| 196 callback.Run(rv); | 191 RecordLastFailure(); |
| 192 base::ResetAndReturn(&wait_for_ready_callback_).Run(rv); |
| 193 } |
| 194 if (ready_ && !pending_write_data_.empty()) { |
| 195 DCHECK_EQ(NONE, state_); |
| 196 PersistInternal(); |
| 197 } | 197 } |
| 198 } | 198 } |
| 199 | 199 |
| 200 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) { | 200 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) { |
| 201 do { | 201 do { |
| 202 switch (state_) { | 202 switch (state_) { |
| 203 case GET_BACKEND: | 203 case GET_BACKEND: |
| 204 rv = DoGetBackend(); | 204 rv = DoGetBackend(); |
| 205 break; | 205 break; |
| 206 case GET_BACKEND_COMPLETE: | 206 case GET_BACKEND_COMPLETE: |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 | 374 |
| 375 int DiskCacheBasedQuicServerInfo::DoSetDone() { | 375 int DiskCacheBasedQuicServerInfo::DoSetDone() { |
| 376 if (entry_) | 376 if (entry_) |
| 377 entry_->Close(); | 377 entry_->Close(); |
| 378 entry_ = NULL; | 378 entry_ = NULL; |
| 379 new_data_.clear(); | 379 new_data_.clear(); |
| 380 state_ = NONE; | 380 state_ = NONE; |
| 381 return OK; | 381 return OK; |
| 382 } | 382 } |
| 383 | 383 |
| 384 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus( |
| 385 QuicServerInfoAPICall call) { |
| 386 if (!backend_) { |
| 387 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call, |
| 388 QUIC_SERVER_INFO_NUM_OF_API_CALLS); |
| 389 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) { |
| 390 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call, |
| 391 QUIC_SERVER_INFO_NUM_OF_API_CALLS); |
| 392 } else { |
| 393 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call, |
| 394 QUIC_SERVER_INFO_NUM_OF_API_CALLS); |
| 395 } |
| 396 } |
| 397 |
| 398 void DiskCacheBasedQuicServerInfo::RecordLastFailure() { |
| 399 if (last_failure_ != NO_FAILURE) { |
| 400 UMA_HISTOGRAM_ENUMERATION( |
| 401 "Net.QuicDiskCache.FailureReason.WaitForDataReady", |
| 402 last_failure_, NUM_OF_FAILURES); |
| 403 } |
| 404 last_failure_ = NO_FAILURE; |
| 405 } |
| 406 |
| 407 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure( |
| 408 FailureReason failure) { |
| 409 last_failure_ = failure; |
| 410 |
| 411 if (!backend_) { |
| 412 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend", |
| 413 failure, NUM_OF_FAILURES); |
| 414 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) { |
| 415 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache", |
| 416 failure, NUM_OF_FAILURES); |
| 417 } else { |
| 418 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache", |
| 419 failure, NUM_OF_FAILURES); |
| 420 } |
| 421 } |
| 422 |
| 384 } // namespace net | 423 } // namespace net |
| OLD | NEW |