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

Side by Side Diff: net/http/disk_cache_based_quic_server_info.cc

Issue 2820573004: Remove the code to store and load QUIC server configs in the disk cache. (Closed)
Patch Set: Fix Created 3 years, 8 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
OLDNEW
(Empty)
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.
4
5 #include "net/http/disk_cache_based_quic_server_info.h"
6
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_macros.h"
12 #include "base/stl_util.h"
13 #include "base/trace_event/memory_usage_estimator.h"
14 #include "net/base/completion_callback.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_cache.h"
18 #include "net/http/http_network_session.h"
19 #include "net/quic/core/quic_server_id.h"
20
21 namespace net {
22
23 // Some APIs inside disk_cache take a handle that the caller must keep alive
24 // until the API has finished its asynchronous execution.
25 //
26 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the
27 // operation completes causing a use-after-free.
28 //
29 // This data shim struct is meant to provide a location for the disk_cache
30 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo
31 // object has been deleted. The lifetime for instances of this struct
32 // should be bound to the CompletionCallback that is passed to the disk_cache
33 // API. We do this by binding an instance of this struct to an unused
34 // parameter for OnIOComplete() using base::Owned().
35 //
36 // This is a hack. A better fix is to make it so that the disk_cache APIs
37 // take a Callback to a mutator for setting the output value rather than
38 // writing into a raw handle. Then the caller can just pass in a Callback
39 // bound to WeakPtr for itself. This callback would correctly "no-op" itself
40 // when the DiskCacheBasedQuicServerInfo object is deleted.
41 //
42 // TODO(ajwong): Change disk_cache's API to return results via Callback.
43 struct DiskCacheBasedQuicServerInfo::CacheOperationDataShim {
44 CacheOperationDataShim() : backend(NULL), entry(NULL) {}
45
46 disk_cache::Backend* backend;
47 disk_cache::Entry* entry;
48 };
49
50 DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo(
51 const QuicServerId& server_id,
52 HttpCache* http_cache)
53 : QuicServerInfo(server_id),
54 data_shim_(new CacheOperationDataShim()),
55 state_(GET_BACKEND),
56 ready_(false),
57 found_entry_(false),
58 server_id_(server_id),
59 http_cache_(http_cache),
60 backend_(NULL),
61 entry_(NULL),
62 last_failure_(NO_FAILURE),
63 weak_factory_(this) {
64 io_callback_ =
65 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
66 weak_factory_.GetWeakPtr(),
67 base::Owned(data_shim_)); // Ownership assigned.
68 }
69
70 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
71 DCHECK(wait_for_ready_callback_.is_null());
72 if (entry_)
73 entry_->Close();
74 }
75
76 void DiskCacheBasedQuicServerInfo::Start() {
77 DCHECK(CalledOnValidThread());
78 DCHECK_EQ(GET_BACKEND, state_);
79 DCHECK_EQ(last_failure_, NO_FAILURE);
80 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
81 load_start_time_ = base::TimeTicks::Now();
82 DoLoop(OK);
83 }
84
85 int DiskCacheBasedQuicServerInfo::WaitForDataReady(
86 const CompletionCallback& callback) {
87 DCHECK(CalledOnValidThread());
88 DCHECK_NE(GET_BACKEND, state_);
89 wait_for_data_start_time_ = base::TimeTicks::Now();
90
91 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
92 if (ready_) {
93 wait_for_data_end_time_ = base::TimeTicks::Now();
94 RecordLastFailure();
95 return OK;
96 }
97
98 if (!callback.is_null()) {
99 // Prevent a new callback for WaitForDataReady overwriting an existing
100 // pending callback (|wait_for_ready_callback_|).
101 if (!wait_for_ready_callback_.is_null()) {
102 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
103 return ERR_INVALID_ARGUMENT;
104 }
105 wait_for_ready_callback_ = callback;
106 }
107
108 return ERR_IO_PENDING;
109 }
110
111 void DiskCacheBasedQuicServerInfo::ResetWaitForDataReadyCallback() {
112 DCHECK(CalledOnValidThread());
113 wait_for_ready_callback_.Reset();
114 }
115
116 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() {
117 DCHECK(CalledOnValidThread());
118
119 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
120 if (!wait_for_ready_callback_.is_null()) {
121 RecordLastFailure();
122 wait_for_ready_callback_.Reset();
123 }
124 }
125
126 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
127 return ready_;
128 }
129
130 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
131 // The data can be persisted if it has been loaded from the disk cache
132 // and there are no pending writes.
133 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
134 if (ready_ && new_data_.empty())
135 return true;
136 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE);
137 return false;
138 }
139
140 void DiskCacheBasedQuicServerInfo::Persist() {
141 DCHECK(CalledOnValidThread());
142 if (!IsReadyToPersist()) {
143 // Handle updates while a write is pending or if we haven't loaded from disk
144 // cache. Save the data to be written into a temporary buffer and then
145 // persist that data when we are ready to persist.
146 pending_write_data_ = Serialize();
147 return;
148 }
149 PersistInternal();
150 }
151
152 void DiskCacheBasedQuicServerInfo::PersistInternal() {
153 DCHECK(CalledOnValidThread());
154 DCHECK_NE(GET_BACKEND, state_);
155 DCHECK(new_data_.empty());
156 CHECK(ready_);
157 DCHECK(wait_for_ready_callback_.is_null());
158
159 if (pending_write_data_.empty()) {
160 new_data_ = Serialize();
161 } else {
162 new_data_ = pending_write_data_;
163 base::STLClearObject(&pending_write_data_);
164 }
165
166 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
167 if (!backend_) {
168 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
169 return;
170 }
171
172 state_ = CREATE_OR_OPEN;
173 DoLoop(OK);
174 }
175
176 void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
177 DCHECK(CalledOnValidThread());
178 DCHECK_NE(GET_BACKEND, state_);
179
180 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
181 if (!backend_) {
182 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
183 return;
184 }
185
186 backend_->OnExternalCacheHit(key());
187 }
188
189 size_t DiskCacheBasedQuicServerInfo::EstimateMemoryUsage() const {
190 return base::trace_event::EstimateMemoryUsage(new_data_) +
191 base::trace_event::EstimateMemoryUsage(pending_write_data_) +
192 base::trace_event::EstimateMemoryUsage(server_id_) +
193 (read_buffer_ == nullptr ? 0 : read_buffer_->size()) +
194 (write_buffer_ == nullptr ? 0 : write_buffer_->size()) +
195 base::trace_event::EstimateMemoryUsage(data_);
196 }
197
198 std::string DiskCacheBasedQuicServerInfo::key() const {
199 return "quicserverinfo:" + server_id_.ToString();
200 }
201
202 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused,
203 int rv) {
204 DCHECK_NE(NONE, state_);
205 rv = DoLoop(rv);
206 if (rv == ERR_IO_PENDING)
207 return;
208
209 base::WeakPtr<DiskCacheBasedQuicServerInfo> weak_this =
210 weak_factory_.GetWeakPtr();
211
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);
216 }
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();
222 }
223 }
224
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();
267 }
268 } while (rv != ERR_IO_PENDING && state_ != NONE);
269
270 return rv;
271 }
272
273 int DiskCacheBasedQuicServerInfo::DoGetBackendComplete(int rv) {
274 if (rv == OK) {
275 backend_ = data_shim_->backend;
276 state_ = OPEN;
277 } else {
278 RecordQuicServerInfoFailure(GET_BACKEND_FAILURE);
279 state_ = WAIT_FOR_DATA_READY_DONE;
280 }
281 return OK;
282 }
283
284 int DiskCacheBasedQuicServerInfo::DoOpenComplete(int rv) {
285 if (rv == OK) {
286 entry_ = data_shim_->entry;
287 state_ = READ;
288 found_entry_ = true;
289 } else {
290 RecordQuicServerInfoFailure(OPEN_FAILURE);
291 state_ = WAIT_FOR_DATA_READY_DONE;
292 }
293
294 return OK;
295 }
296
297 int DiskCacheBasedQuicServerInfo::DoReadComplete(int rv) {
298 if (rv > 0)
299 data_.assign(read_buffer_->data(), rv);
300 else if (rv < 0)
301 RecordQuicServerInfoFailure(READ_FAILURE);
302
303 read_buffer_ = nullptr;
304 state_ = WAIT_FOR_DATA_READY_DONE;
305 return OK;
306 }
307
308 int DiskCacheBasedQuicServerInfo::DoWriteComplete(int rv) {
309 if (rv < 0)
310 RecordQuicServerInfoFailure(WRITE_FAILURE);
311 write_buffer_ = nullptr;
312 state_ = SET_DONE;
313 return OK;
314 }
315
316 int DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete(int rv) {
317 if (rv != OK) {
318 RecordQuicServerInfoFailure(CREATE_OR_OPEN_FAILURE);
319 state_ = SET_DONE;
320 } else {
321 if (!entry_) {
322 entry_ = data_shim_->entry;
323 found_entry_ = true;
324 }
325 DCHECK(entry_);
326 state_ = WRITE;
327 }
328 return OK;
329 }
330
331 int DiskCacheBasedQuicServerInfo::DoGetBackend() {
332 state_ = GET_BACKEND_COMPLETE;
333 return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
334 }
335
336 int DiskCacheBasedQuicServerInfo::DoOpen() {
337 state_ = OPEN_COMPLETE;
338 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
339 }
340
341 int DiskCacheBasedQuicServerInfo::DoRead() {
342 const int32_t size = entry_->GetDataSize(0 /* index */);
343 if (!size) {
344 state_ = WAIT_FOR_DATA_READY_DONE;
345 return OK;
346 }
347
348 read_buffer_ = new IOBufferWithSize(size);
349 state_ = READ_COMPLETE;
350 return entry_->ReadData(
351 0 /* index */, 0 /* offset */, read_buffer_.get(), size, io_callback_);
352 }
353
354 int DiskCacheBasedQuicServerInfo::DoWrite() {
355 write_buffer_ = new IOBufferWithSize(new_data_.size());
356 memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
357 state_ = WRITE_COMPLETE;
358
359 return entry_->WriteData(0 /* index */,
360 0 /* offset */,
361 write_buffer_.get(),
362 new_data_.size(),
363 io_callback_,
364 true /* truncate */);
365 }
366
367 int DiskCacheBasedQuicServerInfo::DoCreateOrOpen() {
368 state_ = CREATE_OR_OPEN_COMPLETE;
369 if (entry_)
370 return OK;
371
372 if (found_entry_) {
373 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
374 }
375
376 return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
377 }
378
379 int DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone() {
380 DCHECK(!ready_);
381 state_ = NONE;
382 ready_ = true;
383 // We close the entry because, if we shutdown before ::Persist is called,
384 // then we might leak a cache reference, which causes a DCHECK on shutdown.
385 if (entry_)
386 entry_->Close();
387 entry_ = NULL;
388
389 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE);
390 if (!Parse(data_)) {
391 if (data_.empty())
392 RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE);
393 else
394 RecordQuicServerInfoFailure(PARSE_FAILURE);
395 }
396
397 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheLoadTime",
398 base::TimeTicks::Now() - load_start_time_);
399 return OK;
400 }
401
402 int DiskCacheBasedQuicServerInfo::DoSetDone() {
403 if (entry_)
404 entry_->Close();
405 entry_ = NULL;
406 base::STLClearObject(&new_data_);
407 state_ = NONE;
408 return OK;
409 }
410
411 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
412 QuicServerInfoAPICall call) {
413 if (!backend_) {
414 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
415 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
416 } else if (backend_->GetCacheType() == MEMORY_CACHE) {
417 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
418 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
419 } else {
420 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
421 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
422 }
423 }
424
425 void DiskCacheBasedQuicServerInfo::RecordLastFailure() {
426 if (last_failure_ != NO_FAILURE) {
427 UMA_HISTOGRAM_ENUMERATION(
428 "Net.QuicDiskCache.FailureReason.WaitForDataReady",
429 last_failure_, NUM_OF_FAILURES);
430 }
431 last_failure_ = NO_FAILURE;
432 }
433
434 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
435 FailureReason failure) {
436 last_failure_ = failure;
437
438 if (!backend_) {
439 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
440 failure, NUM_OF_FAILURES);
441 } else if (backend_->GetCacheType() == MEMORY_CACHE) {
442 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
443 failure, NUM_OF_FAILURES);
444 } else {
445 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
446 failure, NUM_OF_FAILURES);
447 }
448 }
449
450 } // namespace net
OLDNEW
« no previous file with comments | « net/http/disk_cache_based_quic_server_info.h ('k') | net/http/disk_cache_based_quic_server_info_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698