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

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

Issue 2002002: Http Cache: Handle the asynchronous instantiation of the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/http_cache.h" 5 #include "net/http/http_cache.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 10
11 #if defined(OS_POSIX) 11 #if defined(OS_POSIX)
12 #include <unistd.h> 12 #include <unistd.h>
13 #endif 13 #endif
14 14
15 #include "base/callback.h" 15 #include "base/callback.h"
16 #include "base/format_macros.h" 16 #include "base/format_macros.h"
17 #include "base/message_loop.h" 17 #include "base/message_loop.h"
18 #include "base/pickle.h" 18 #include "base/pickle.h"
19 #include "base/ref_counted.h" 19 #include "base/ref_counted.h"
20 #include "base/stl_util-inl.h"
20 #include "base/string_util.h" 21 #include "base/string_util.h"
21 #include "net/base/io_buffer.h" 22 #include "net/base/io_buffer.h"
22 #include "net/base/load_flags.h" 23 #include "net/base/load_flags.h"
23 #include "net/base/net_errors.h" 24 #include "net/base/net_errors.h"
24 #include "net/disk_cache/disk_cache.h" 25 #include "net/disk_cache/disk_cache.h"
25 #include "net/http/http_cache_transaction.h" 26 #include "net/http/http_cache_transaction.h"
26 #include "net/http/http_network_layer.h" 27 #include "net/http/http_network_layer.h"
27 #include "net/http/http_network_session.h" 28 #include "net/http/http_network_session.h"
28 #include "net/http/http_request_info.h" 29 #include "net/http/http_request_info.h"
29 #include "net/http/http_response_headers.h" 30 #include "net/http/http_response_headers.h"
(...skipping 12 matching lines...) Expand all
42 } 43 }
43 44
44 HttpCache::ActiveEntry::~ActiveEntry() { 45 HttpCache::ActiveEntry::~ActiveEntry() {
45 if (disk_entry) 46 if (disk_entry)
46 disk_entry->Close(); 47 disk_entry->Close();
47 } 48 }
48 49
49 //----------------------------------------------------------------------------- 50 //-----------------------------------------------------------------------------
50 51
51 // This structure keeps track of work items that are attempting to create or 52 // This structure keeps track of work items that are attempting to create or
52 // open cache entries. 53 // open cache entries or the backend itself.
53 struct HttpCache::NewEntry { 54 struct HttpCache::PendingOp {
54 NewEntry() : disk_entry(NULL), writer(NULL) {} 55 PendingOp() : disk_entry(NULL), writer(NULL), callback(NULL) {}
55 ~NewEntry() {} 56 ~PendingOp() {}
56 57
57 disk_cache::Entry* disk_entry; 58 disk_cache::Entry* disk_entry;
58 WorkItem* writer; 59 WorkItem* writer;
60 CompletionCallback* callback; // BackendCallback.
59 WorkItemList pending_queue; 61 WorkItemList pending_queue;
60 }; 62 };
61 63
62 //----------------------------------------------------------------------------- 64 //-----------------------------------------------------------------------------
63 65
64 // The type of operation represented by a work item. 66 // The type of operation represented by a work item.
65 enum WorkItemOperation { 67 enum WorkItemOperation {
68 WI_CREATE_BACKEND,
66 WI_OPEN_ENTRY, 69 WI_OPEN_ENTRY,
67 WI_CREATE_ENTRY, 70 WI_CREATE_ENTRY,
68 WI_DOOM_ENTRY 71 WI_DOOM_ENTRY
69 }; 72 };
70 73
71 // A work item encapsulates a single request for cache entry with all the 74 // A work item encapsulates a single request to the backend with all the
72 // information needed to complete that request. 75 // information needed to complete that request.
73 class HttpCache::WorkItem { 76 class HttpCache::WorkItem {
74 public: 77 public:
75 WorkItem(ActiveEntry** entry, Transaction* trans, WorkItemOperation operation) 78 WorkItem(WorkItemOperation operation, Transaction* trans, ActiveEntry** entry)
76 : entry_(entry), trans_(trans), operation_(operation) {} 79 : operation_(operation), trans_(trans), entry_(entry), callback_(NULL),
80 backend_(NULL) {}
81 WorkItem(WorkItemOperation operation, Transaction* trans,
82 CompletionCallback* cb, disk_cache::Backend** backend)
83 : operation_(operation), trans_(trans), entry_(NULL), callback_(cb),
84 backend_(backend) {}
77 ~WorkItem() {} 85 ~WorkItem() {}
78 WorkItemOperation operation() { return operation_; }
79 86
80 // Calls back the transaction with the result of the operation. 87 // Calls back the transaction with the result of the operation.
81 void NotifyTransaction(int result, ActiveEntry* entry) { 88 void NotifyTransaction(int result, ActiveEntry* entry) {
82 if (entry_) 89 if (entry_)
83 *entry_ = entry; 90 *entry_ = entry;
84 if (trans_) 91 if (trans_)
85 trans_->io_callback()->Run(result); 92 trans_->io_callback()->Run(result);
86 } 93 }
87 94
95 // Notifies the caller about the operation completion.
96 void DoCallback(int result, disk_cache::Backend* backend) {
97 if (backend_)
98 *backend_ = backend;
99 if (callback_)
100 callback_->Run(result);
101 }
102
103 WorkItemOperation operation() { return operation_; }
88 void ClearTransaction() { trans_ = NULL; } 104 void ClearTransaction() { trans_ = NULL; }
89 void ClearEntry() { entry_ = NULL; } 105 void ClearEntry() { entry_ = NULL; }
106 void ClearCallback() { callback_ = NULL; }
90 bool Matches(Transaction* trans) const { return trans == trans_; } 107 bool Matches(Transaction* trans) const { return trans == trans_; }
91 bool IsValid() const { return trans_ || entry_; } 108 bool IsValid() const { return trans_ || entry_ || callback_; }
92 109
93 private: 110 private:
111 WorkItemOperation operation_;
112 Transaction* trans_;
94 ActiveEntry** entry_; 113 ActiveEntry** entry_;
95 Transaction* trans_; 114 CompletionCallback* callback_; // User callback.
96 WorkItemOperation operation_; 115 disk_cache::Backend** backend_;
97 }; 116 };
98 117
99 //----------------------------------------------------------------------------- 118 //-----------------------------------------------------------------------------
100 119
101 // This class is a specialized type of CompletionCallback that allows us to 120 // This class is a specialized type of CompletionCallback that allows us to
102 // pass multiple arguments to the completion routine. 121 // pass multiple arguments to the completion routine.
103 class HttpCache::BackendCallback : public CallbackRunner<Tuple1<int> > { 122 class HttpCache::BackendCallback : public CallbackRunner<Tuple1<int> > {
104 public: 123 public:
105 BackendCallback(HttpCache* cache, NewEntry* entry) 124 BackendCallback(HttpCache* cache, PendingOp* pending_op)
106 : cache_(cache), entry_(entry) {} 125 : cache_(cache), pending_op_(pending_op) {}
107 ~BackendCallback() {} 126 ~BackendCallback() {}
108 127
109 virtual void RunWithParams(const Tuple1<int>& params) { 128 virtual void RunWithParams(const Tuple1<int>& params) {
110 cache_->OnIOComplete(params.a, entry_); 129 cache_->OnIOComplete(params.a, pending_op_);
111 delete this; 130 delete this;
112 } 131 }
113 132
114 private: 133 private:
115 HttpCache* cache_; 134 HttpCache* cache_;
116 NewEntry* entry_; 135 PendingOp* pending_op_;
117 DISALLOW_COPY_AND_ASSIGN(BackendCallback); 136 DISALLOW_COPY_AND_ASSIGN(BackendCallback);
118 }; 137 };
119 138
120 //----------------------------------------------------------------------------- 139 //-----------------------------------------------------------------------------
121 140
122 // This class encapsulates a transaction whose only purpose is to write metadata 141 // This class encapsulates a transaction whose only purpose is to write metadata
123 // to a given entry. 142 // to a given entry.
124 class HttpCache::MetadataWriter { 143 class HttpCache::MetadataWriter {
125 public: 144 public:
126 explicit MetadataWriter(HttpCache::Transaction* trans) 145 explicit MetadataWriter(HttpCache::Transaction* trans)
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier, 217 HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier,
199 HostResolver* host_resolver, 218 HostResolver* host_resolver,
200 ProxyService* proxy_service, 219 ProxyService* proxy_service,
201 SSLConfigService* ssl_config_service, 220 SSLConfigService* ssl_config_service,
202 HttpAuthHandlerFactory* http_auth_handler_factory, 221 HttpAuthHandlerFactory* http_auth_handler_factory,
203 const FilePath& cache_dir, 222 const FilePath& cache_dir,
204 MessageLoop* cache_thread, 223 MessageLoop* cache_thread,
205 int cache_size) 224 int cache_size)
206 : disk_cache_dir_(cache_dir), 225 : disk_cache_dir_(cache_dir),
207 cache_thread_(cache_thread), 226 cache_thread_(cache_thread),
227 temp_backend_(NULL),
228 building_backend_(false),
208 mode_(NORMAL), 229 mode_(NORMAL),
209 type_(DISK_CACHE), 230 type_(DISK_CACHE),
210 network_layer_(HttpNetworkLayer::CreateFactory( 231 network_layer_(HttpNetworkLayer::CreateFactory(
211 network_change_notifier, host_resolver, proxy_service, 232 network_change_notifier, host_resolver, proxy_service,
212 ssl_config_service, http_auth_handler_factory)), 233 ssl_config_service, http_auth_handler_factory)),
213 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), 234 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
214 enable_range_support_(true), 235 enable_range_support_(true),
215 cache_size_(cache_size) { 236 cache_size_(cache_size),
237 create_backend_fn_(NULL) {
216 } 238 }
217 239
218 HttpCache::HttpCache(HttpNetworkSession* session, 240 HttpCache::HttpCache(HttpNetworkSession* session,
219 const FilePath& cache_dir, 241 const FilePath& cache_dir,
220 MessageLoop* cache_thread, 242 MessageLoop* cache_thread,
221 int cache_size) 243 int cache_size)
222 : disk_cache_dir_(cache_dir), 244 : disk_cache_dir_(cache_dir),
223 cache_thread_(cache_thread), 245 cache_thread_(cache_thread),
246 temp_backend_(NULL),
247 building_backend_(false),
224 mode_(NORMAL), 248 mode_(NORMAL),
225 type_(DISK_CACHE), 249 type_(DISK_CACHE),
226 network_layer_(HttpNetworkLayer::CreateFactory(session)), 250 network_layer_(HttpNetworkLayer::CreateFactory(session)),
227 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), 251 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
228 enable_range_support_(true), 252 enable_range_support_(true),
229 cache_size_(cache_size) { 253 cache_size_(cache_size),
254 create_backend_fn_(NULL) {
230 } 255 }
231 256
232 HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier, 257 HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier,
233 HostResolver* host_resolver, 258 HostResolver* host_resolver,
234 ProxyService* proxy_service, 259 ProxyService* proxy_service,
235 SSLConfigService* ssl_config_service, 260 SSLConfigService* ssl_config_service,
236 HttpAuthHandlerFactory* http_auth_handler_factory, 261 HttpAuthHandlerFactory* http_auth_handler_factory,
237 int cache_size) 262 int cache_size)
238 : mode_(NORMAL), 263 : cache_thread_(NULL),
264 temp_backend_(NULL),
265 building_backend_(false),
266 mode_(NORMAL),
239 type_(MEMORY_CACHE), 267 type_(MEMORY_CACHE),
240 network_layer_(HttpNetworkLayer::CreateFactory( 268 network_layer_(HttpNetworkLayer::CreateFactory(
241 network_change_notifier, host_resolver, proxy_service, 269 network_change_notifier, host_resolver, proxy_service,
242 ssl_config_service, http_auth_handler_factory)), 270 ssl_config_service, http_auth_handler_factory)),
243 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), 271 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
244 enable_range_support_(true), 272 enable_range_support_(true),
245 cache_size_(cache_size) { 273 cache_size_(cache_size),
274 create_backend_fn_(NULL) {
246 } 275 }
247 276
248 HttpCache::HttpCache(HttpTransactionFactory* network_layer, 277 HttpCache::HttpCache(HttpTransactionFactory* network_layer,
249 disk_cache::Backend* disk_cache) 278 disk_cache::Backend* disk_cache)
250 : mode_(NORMAL), 279 : cache_thread_(NULL),
280 temp_backend_(NULL),
281 building_backend_(false),
282 mode_(NORMAL),
251 type_(DISK_CACHE), 283 type_(DISK_CACHE),
252 network_layer_(network_layer), 284 network_layer_(network_layer),
253 disk_cache_(disk_cache), 285 disk_cache_(disk_cache),
254 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), 286 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
255 enable_range_support_(true), 287 enable_range_support_(true),
256 cache_size_(0) { 288 cache_size_(0),
289 create_backend_fn_(NULL) {
257 } 290 }
258 291
259 HttpCache::~HttpCache() { 292 HttpCache::~HttpCache() {
260 // If we have any active entries remaining, then we need to deactivate them. 293 // If we have any active entries remaining, then we need to deactivate them.
261 // We may have some pending calls to OnProcessPendingQueue, but since those 294 // We may have some pending calls to OnProcessPendingQueue, but since those
262 // won't run (due to our destruction), we can simply ignore the corresponding 295 // won't run (due to our destruction), we can simply ignore the corresponding
263 // will_process_pending_queue flag. 296 // will_process_pending_queue flag.
264 while (!active_entries_.empty()) { 297 while (!active_entries_.empty()) {
265 ActiveEntry* entry = active_entries_.begin()->second; 298 ActiveEntry* entry = active_entries_.begin()->second;
266 entry->will_process_pending_queue = false; 299 entry->will_process_pending_queue = false;
267 entry->pending_queue.clear(); 300 entry->pending_queue.clear();
268 entry->readers.clear(); 301 entry->readers.clear();
269 entry->writer = NULL; 302 entry->writer = NULL;
270 DeactivateEntry(entry); 303 DeactivateEntry(entry);
271 } 304 }
272 305
273 ActiveEntriesSet::iterator it = doomed_entries_.begin(); 306 STLDeleteElements(&doomed_entries_);
274 for (; it != doomed_entries_.end(); ++it) 307
275 delete *it; 308 PendingOpsMap::iterator pending_it = pending_ops_.begin();
309 for (; pending_it != pending_ops_.end(); ++pending_it) {
310 // We are not notifying the transactions about the cache going away, even
311 // though they are waiting for a callback that will never fire.
312 PendingOp* pending_op = pending_it->second;
313 delete pending_op->writer;
314 delete pending_op->callback;
315
316 STLDeleteElements(&pending_op->pending_queue);
317 delete pending_op;
318 }
276 } 319 }
277 320
278 disk_cache::Backend* HttpCache::GetBackend() { 321 disk_cache::Backend* HttpCache::GetBackend() {
279 if (disk_cache_.get()) 322 if (disk_cache_.get())
280 return disk_cache_.get(); 323 return disk_cache_.get();
281 324
282 DCHECK_GE(cache_size_, 0); 325 DCHECK_GE(cache_size_, 0);
283 if (type_ == MEMORY_CACHE) { 326 if (type_ == MEMORY_CACHE) {
284 // We may end up with no folder name and no cache if the initialization 327 // We may end up with no folder name and no cache if the initialization
285 // of the disk cache fails. We want to be sure that what we wanted to have 328 // of the disk cache fails. We want to be sure that what we wanted to have
286 // was an in-memory cache. 329 // was an in-memory cache.
287 disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_)); 330 disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_));
288 } else if (!disk_cache_dir_.empty()) { 331 } else if (!disk_cache_dir_.empty()) {
289 disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true, 332 disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true,
290 cache_size_, type_)); 333 cache_size_, type_));
291 disk_cache_dir_ = FilePath(); // Reclaim memory. 334 disk_cache_dir_ = FilePath(); // Reclaim memory.
292 } 335 }
293 return disk_cache_.get(); 336 return disk_cache_.get();
294 } 337 }
295 338
296 int HttpCache::GetBackend(disk_cache::Backend** backend, 339 int HttpCache::GetBackend(disk_cache::Backend** backend,
297 CompletionCallback* callback) { 340 CompletionCallback* callback) {
298 DCHECK(callback != NULL); 341 DCHECK(callback != NULL);
299 *backend = GetBackend(); 342
300 return OK; 343 if (disk_cache_.get()) {
344 *backend = disk_cache_.get();
345 return OK;
346 }
347
348 DCHECK_GE(cache_size_, 0);
349 return CreateBackend(backend, callback);
301 } 350 }
302 351
303 int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) { 352 int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
304 // Do lazy initialization of disk cache if needed. 353 // Do lazy initialization of disk cache if needed.
305 GetBackend(); 354 if (!disk_cache_.get())
355 CreateBackend(NULL, NULL); // We don't care about the result.
356
306 trans->reset(new HttpCache::Transaction(this, enable_range_support_)); 357 trans->reset(new HttpCache::Transaction(this, enable_range_support_));
307 return OK; 358 return OK;
308 } 359 }
309 360
310 HttpCache* HttpCache::GetCache() { 361 HttpCache* HttpCache::GetCache() {
311 return this; 362 return this;
312 } 363 }
313 364
314 HttpNetworkSession* HttpCache::GetSession() { 365 HttpNetworkSession* HttpCache::GetSession() {
315 net::HttpNetworkLayer* network = 366 net::HttpNetworkLayer* network =
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 if (session) { 436 if (session) {
386 session->tcp_socket_pool()->CloseIdleSockets(); 437 session->tcp_socket_pool()->CloseIdleSockets();
387 if (session->spdy_session_pool()) 438 if (session->spdy_session_pool())
388 session->spdy_session_pool()->CloseAllSessions(); 439 session->spdy_session_pool()->CloseAllSessions();
389 session->ReplaceTCPSocketPool(); 440 session->ReplaceTCPSocketPool();
390 } 441 }
391 } 442 }
392 443
393 //----------------------------------------------------------------------------- 444 //-----------------------------------------------------------------------------
394 445
446 int HttpCache::CreateBackend(disk_cache::Backend** backend,
447 CompletionCallback* callback) {
448 // We may end up with no folder name and no cache if the initialization
449 // of the disk cache fails.
450 if (type_ != MEMORY_CACHE && disk_cache_dir_.empty())
451 return ERR_FAILED;
452
453 DCHECK_GE(cache_size_, 0);
454 building_backend_ = true;
455
456 scoped_ptr<WorkItem> item(new WorkItem(WI_CREATE_BACKEND, NULL, callback,
457 backend));
458
459 // This is the only operation that we can do that is not related to any given
460 // entry, so we use an empty key for it.
461 PendingOp* pending_op = GetPendingOp("");
462 if (pending_op->writer) {
463 if (callback)
464 pending_op->pending_queue.push_back(item.release());
465 return ERR_IO_PENDING;
466 }
467
468 DCHECK(pending_op->pending_queue.empty());
469
470 pending_op->writer = item.release();
471 BackendCallback* my_callback = new BackendCallback(this, pending_op);
472 pending_op->callback = my_callback;
473
474 // See if this is a unit test. TODO(rvargas): Cleanup this after removing the
475 // overloaded method.
476 int rv;
477 if (create_backend_fn_) {
478 rv = create_backend_fn_(type_, disk_cache_dir_, cache_size_, true,
479 cache_thread_, &temp_backend_, my_callback);
480 } else {
481 rv = disk_cache::CreateCacheBackend(type_, disk_cache_dir_, cache_size_,
482 true, cache_thread_, &temp_backend_,
483 my_callback);
484 }
485
486 if (rv != ERR_IO_PENDING) {
487 pending_op->writer->ClearCallback();
488 my_callback->Run(rv);
489 }
490
491 return rv;
492 }
493
494 int HttpCache::GetBackendForTransaction(Transaction* trans) {
495 if (disk_cache_.get())
496 return OK;
497
498 if (!building_backend_)
499 return ERR_FAILED;
500
501 WorkItem* item = new WorkItem(WI_CREATE_BACKEND, trans, NULL, NULL);
502 PendingOp* pending_op = GetPendingOp("");
503 DCHECK(pending_op->writer);
504 pending_op->pending_queue.push_back(item);
505 return ERR_IO_PENDING;
506 }
507
395 // Generate a key that can be used inside the cache. 508 // Generate a key that can be used inside the cache.
396 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) { 509 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
397 // Strip out the reference, username, and password sections of the URL. 510 // Strip out the reference, username, and password sections of the URL.
398 std::string url = HttpUtil::SpecForRequest(request->url); 511 std::string url = HttpUtil::SpecForRequest(request->url);
399 512
400 DCHECK(mode_ != DISABLE); 513 DCHECK(mode_ != DISABLE);
401 if (mode_ == NORMAL) { 514 if (mode_ == NORMAL) {
402 // No valid URL can begin with numerals, so we should not have to worry 515 // No valid URL can begin with numerals, so we should not have to worry
403 // about collisions with normal URLs. 516 // about collisions with normal URLs.
404 if (request->upload_data && request->upload_data->identifier()) { 517 if (request->upload_data && request->upload_data->identifier()) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 563
451 entry->disk_entry->Doom(); 564 entry->disk_entry->Doom();
452 entry->doomed = true; 565 entry->doomed = true;
453 566
454 DCHECK(entry->writer || !entry->readers.empty()); 567 DCHECK(entry->writer || !entry->readers.empty());
455 return OK; 568 return OK;
456 } 569 }
457 570
458 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 571 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
459 DCHECK(trans); 572 DCHECK(trans);
460 WorkItem* item = new WorkItem(NULL, trans, WI_DOOM_ENTRY); 573 WorkItem* item = new WorkItem(WI_DOOM_ENTRY, trans, NULL);
461 NewEntry* new_entry = GetNewEntry(key); 574 PendingOp* pending_op = GetPendingOp(key);
462 if (new_entry->writer) { 575 if (pending_op->writer) {
463 new_entry->pending_queue.push_back(item); 576 pending_op->pending_queue.push_back(item);
464 return ERR_IO_PENDING; 577 return ERR_IO_PENDING;
465 } 578 }
466 579
467 DCHECK(new_entry->pending_queue.empty()); 580 DCHECK(pending_op->pending_queue.empty());
468 581
469 new_entry->writer = item; 582 pending_op->writer = item;
470 BackendCallback* my_callback = new BackendCallback(this, new_entry); 583 BackendCallback* my_callback = new BackendCallback(this, pending_op);
584 pending_op->callback = my_callback;
471 585
472 int rv = disk_cache_->DoomEntry(key, my_callback); 586 int rv = disk_cache_->DoomEntry(key, my_callback);
473 if (rv != ERR_IO_PENDING) { 587 if (rv != ERR_IO_PENDING) {
474 item->ClearTransaction(); 588 item->ClearTransaction();
475 my_callback->Run(rv); 589 my_callback->Run(rv);
476 } 590 }
477 591
478 return rv; 592 return rv;
479 } 593 }
480 594
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 for (ActiveEntriesMap::iterator it = active_entries_.begin(); 643 for (ActiveEntriesMap::iterator it = active_entries_.begin();
530 it != active_entries_.end(); ++it) { 644 it != active_entries_.end(); ++it) {
531 if (it->second == entry) { 645 if (it->second == entry) {
532 active_entries_.erase(it); 646 active_entries_.erase(it);
533 delete entry; 647 delete entry;
534 break; 648 break;
535 } 649 }
536 } 650 }
537 } 651 }
538 652
539 HttpCache::NewEntry* HttpCache::GetNewEntry(const std::string& key) { 653 HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) {
540 DCHECK(!FindActiveEntry(key)); 654 DCHECK(!FindActiveEntry(key));
541 655
542 NewEntriesMap::const_iterator it = new_entries_.find(key); 656 PendingOpsMap::const_iterator it = pending_ops_.find(key);
543 if (it != new_entries_.end()) 657 if (it != pending_ops_.end())
544 return it->second; 658 return it->second;
545 659
546 NewEntry* entry = new NewEntry(); 660 PendingOp* operation = new PendingOp();
547 new_entries_[key] = entry; 661 pending_ops_[key] = operation;
548 return entry; 662 return operation;
549 } 663 }
550 664
551 void HttpCache::DeleteNewEntry(NewEntry* entry) { 665 void HttpCache::DeletePendingOp(PendingOp* pending_op) {
552 std::string key; 666 std::string key;
553 if (entry->disk_entry) 667 if (pending_op->disk_entry)
554 key = entry->disk_entry->GetKey(); 668 key = pending_op->disk_entry->GetKey();
555 669
556 if (!key.empty()) { 670 if (!key.empty()) {
557 NewEntriesMap::iterator it = new_entries_.find(key); 671 PendingOpsMap::iterator it = pending_ops_.find(key);
558 DCHECK(it != new_entries_.end()); 672 DCHECK(it != pending_ops_.end());
559 new_entries_.erase(it); 673 pending_ops_.erase(it);
560 } else { 674 } else {
561 for (NewEntriesMap::iterator it = new_entries_.begin(); 675 for (PendingOpsMap::iterator it = pending_ops_.begin();
562 it != new_entries_.end(); ++it) { 676 it != pending_ops_.end(); ++it) {
563 if (it->second == entry) { 677 if (it->second == pending_op) {
564 new_entries_.erase(it); 678 pending_ops_.erase(it);
565 break; 679 break;
566 } 680 }
567 } 681 }
568 } 682 }
683 DCHECK(pending_op->pending_queue.empty());
569 684
570 delete entry; 685 delete pending_op;
571 } 686 }
572 687
573 int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry, 688 int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry,
574 Transaction* trans) { 689 Transaction* trans) {
575 ActiveEntry* active_entry = FindActiveEntry(key); 690 ActiveEntry* active_entry = FindActiveEntry(key);
576 if (active_entry) { 691 if (active_entry) {
577 *entry = active_entry; 692 *entry = active_entry;
578 return OK; 693 return OK;
579 } 694 }
580 695
581 WorkItem* item = new WorkItem(entry, trans, WI_OPEN_ENTRY); 696 WorkItem* item = new WorkItem(WI_OPEN_ENTRY, trans, entry);
582 NewEntry* new_entry = GetNewEntry(key); 697 PendingOp* pending_op = GetPendingOp(key);
583 if (new_entry->writer) { 698 if (pending_op->writer) {
584 new_entry->pending_queue.push_back(item); 699 pending_op->pending_queue.push_back(item);
585 return ERR_IO_PENDING; 700 return ERR_IO_PENDING;
586 } 701 }
587 702
588 DCHECK(new_entry->pending_queue.empty()); 703 DCHECK(pending_op->pending_queue.empty());
589 704
590 new_entry->writer = item; 705 pending_op->writer = item;
591 BackendCallback* my_callback = new BackendCallback(this, new_entry); 706 BackendCallback* my_callback = new BackendCallback(this, pending_op);
707 pending_op->callback = my_callback;
592 708
593 int rv = disk_cache_->OpenEntry(key, &(new_entry->disk_entry), my_callback); 709 int rv = disk_cache_->OpenEntry(key, &(pending_op->disk_entry), my_callback);
594 if (rv != ERR_IO_PENDING) { 710 if (rv != ERR_IO_PENDING) {
595 item->ClearTransaction(); 711 item->ClearTransaction();
596 my_callback->Run(rv); 712 my_callback->Run(rv);
597 } 713 }
598 714
599 return rv; 715 return rv;
600 } 716 }
601 717
602 int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry, 718 int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry,
603 Transaction* trans) { 719 Transaction* trans) {
604 DCHECK(!FindActiveEntry(key)); 720 DCHECK(!FindActiveEntry(key));
605 721
606 WorkItem* item = new WorkItem(entry, trans, WI_CREATE_ENTRY); 722 WorkItem* item = new WorkItem(WI_CREATE_ENTRY, trans, entry);
607 NewEntry* new_entry = GetNewEntry(key); 723 PendingOp* pending_op = GetPendingOp(key);
608 if (new_entry->writer) { 724 if (pending_op->writer) {
609 new_entry->pending_queue.push_back(item); 725 pending_op->pending_queue.push_back(item);
610 return ERR_IO_PENDING; 726 return ERR_IO_PENDING;
611 } 727 }
612 728
613 DCHECK(new_entry->pending_queue.empty()); 729 DCHECK(pending_op->pending_queue.empty());
614 730
615 new_entry->writer = item; 731 pending_op->writer = item;
616 BackendCallback* my_callback = new BackendCallback(this, new_entry); 732 BackendCallback* my_callback = new BackendCallback(this, pending_op);
733 pending_op->callback = my_callback;
617 734
618 int rv = disk_cache_->CreateEntry(key, &(new_entry->disk_entry), my_callback); 735 int rv = disk_cache_->CreateEntry(key, &(pending_op->disk_entry),
736 my_callback);
619 if (rv != ERR_IO_PENDING) { 737 if (rv != ERR_IO_PENDING) {
620 item->ClearTransaction(); 738 item->ClearTransaction();
621 my_callback->Run(rv); 739 my_callback->Run(rv);
622 } 740 }
623 741
624 return rv; 742 return rv;
625 } 743 }
626 744
627 void HttpCache::DestroyEntry(ActiveEntry* entry) { 745 void HttpCache::DestroyEntry(ActiveEntry* entry) {
628 if (entry->doomed) { 746 if (entry->doomed) {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 866
749 void HttpCache::RemovePendingTransaction(Transaction* trans) { 867 void HttpCache::RemovePendingTransaction(Transaction* trans) {
750 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key()); 868 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
751 bool found = false; 869 bool found = false;
752 if (i != active_entries_.end()) 870 if (i != active_entries_.end())
753 found = RemovePendingTransactionFromEntry(i->second, trans); 871 found = RemovePendingTransactionFromEntry(i->second, trans);
754 872
755 if (found) 873 if (found)
756 return; 874 return;
757 875
758 NewEntriesMap::const_iterator j = new_entries_.find(trans->key()); 876 if (building_backend_) {
759 if (j != new_entries_.end()) 877 PendingOpsMap::const_iterator j = pending_ops_.find("");
760 found = RemovePendingTransactionFromNewEntry(j->second, trans); 878 if (j != pending_ops_.end())
879 found = RemovePendingTransactionFromPendingOp(j->second, trans);
880
881 if (found)
882 return;
883 }
884
885 PendingOpsMap::const_iterator j = pending_ops_.find(trans->key());
886 if (j != pending_ops_.end())
887 found = RemovePendingTransactionFromPendingOp(j->second, trans);
888
889 if (found)
890 return;
761 891
762 ActiveEntriesSet::iterator k = doomed_entries_.begin(); 892 ActiveEntriesSet::iterator k = doomed_entries_.begin();
763 for (; k != doomed_entries_.end() && !found; ++k) 893 for (; k != doomed_entries_.end() && !found; ++k)
764 found = RemovePendingTransactionFromEntry(*k, trans); 894 found = RemovePendingTransactionFromEntry(*k, trans);
765 895
766 DCHECK(found) << "Pending transaction not found"; 896 DCHECK(found) << "Pending transaction not found";
767 } 897 }
768 898
769 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 899 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
770 Transaction* trans) { 900 Transaction* trans) {
771 TransactionList& pending_queue = entry->pending_queue; 901 TransactionList& pending_queue = entry->pending_queue;
772 902
773 TransactionList::iterator j = 903 TransactionList::iterator j =
774 find(pending_queue.begin(), pending_queue.end(), trans); 904 find(pending_queue.begin(), pending_queue.end(), trans);
775 if (j == pending_queue.end()) 905 if (j == pending_queue.end())
776 return false; 906 return false;
777 907
778 pending_queue.erase(j); 908 pending_queue.erase(j);
779 return true; 909 return true;
780 } 910 }
781 911
782 bool HttpCache::RemovePendingTransactionFromNewEntry(NewEntry* entry, 912 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
783 Transaction* trans) { 913 Transaction* trans) {
784 if (entry->writer->Matches(trans)) { 914 if (pending_op->writer->Matches(trans)) {
785 entry->writer->ClearTransaction(); 915 pending_op->writer->ClearTransaction();
786 entry->writer->ClearEntry(); 916 pending_op->writer->ClearEntry();
787 return true; 917 return true;
788 } 918 }
789 WorkItemList& pending_queue = entry->pending_queue; 919 WorkItemList& pending_queue = pending_op->pending_queue;
790 920
791 WorkItemList::iterator it = pending_queue.begin(); 921 WorkItemList::iterator it = pending_queue.begin();
792 for (; it != pending_queue.end(); ++it) { 922 for (; it != pending_queue.end(); ++it) {
793 if ((*it)->Matches(trans)) { 923 if ((*it)->Matches(trans)) {
794 delete *it; 924 delete *it;
795 pending_queue.erase(it); 925 pending_queue.erase(it);
796 return true; 926 return true;
797 } 927 }
798 } 928 }
799 return false; 929 return false;
(...skipping 30 matching lines...) Expand all
830 return; // Have to wait. 960 return; // Have to wait.
831 961
832 entry->pending_queue.erase(entry->pending_queue.begin()); 962 entry->pending_queue.erase(entry->pending_queue.begin());
833 963
834 int rv = AddTransactionToEntry(entry, next); 964 int rv = AddTransactionToEntry(entry, next);
835 if (rv != ERR_IO_PENDING) { 965 if (rv != ERR_IO_PENDING) {
836 next->io_callback()->Run(rv); 966 next->io_callback()->Run(rv);
837 } 967 }
838 } 968 }
839 969
840 void HttpCache::OnIOComplete(int result, NewEntry* new_entry) { 970 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
841 scoped_ptr<WorkItem> item(new_entry->writer); 971 WorkItemOperation op = pending_op->writer->operation();
842 WorkItemOperation op = item->operation(); 972
973 // Completing the creation of the backend is simpler than the other cases.
974 if (op == WI_CREATE_BACKEND)
975 return OnBackendCreated(result, pending_op);
976
977 scoped_ptr<WorkItem> item(pending_op->writer);
843 bool fail_requests = false; 978 bool fail_requests = false;
844 979
845 ActiveEntry* entry = NULL; 980 ActiveEntry* entry = NULL;
846 std::string key; 981 std::string key;
847 if (result == OK) { 982 if (result == OK) {
848 if (op == WI_DOOM_ENTRY) { 983 if (op == WI_DOOM_ENTRY) {
849 // Anything after a Doom has to be restarted. 984 // Anything after a Doom has to be restarted.
850 fail_requests = true; 985 fail_requests = true;
851 } else if (item->IsValid()) { 986 } else if (item->IsValid()) {
852 key = new_entry->disk_entry->GetKey(); 987 key = pending_op->disk_entry->GetKey();
853 entry = ActivateEntry(key, new_entry->disk_entry); 988 entry = ActivateEntry(key, pending_op->disk_entry);
854 } else { 989 } else {
855 // The writer transaction is gone. 990 // The writer transaction is gone.
856 if (op == WI_CREATE_ENTRY) 991 if (op == WI_CREATE_ENTRY)
857 new_entry->disk_entry->Doom(); 992 pending_op->disk_entry->Doom();
858 new_entry->disk_entry->Close(); 993 pending_op->disk_entry->Close();
859 fail_requests = true; 994 fail_requests = true;
860 } 995 }
861 } 996 }
862 997
863 // We are about to notify a bunch of transactions, and they may decide to 998 // We are about to notify a bunch of transactions, and they may decide to
864 // re-issue a request (or send a different one). If we don't delete new_entry, 999 // re-issue a request (or send a different one). If we don't delete
865 // the new request will be appended to the end of the list, and we'll see it 1000 // pending_op, the new request will be appended to the end of the list, and
866 // again from this point before it has a chance to complete (and we'll be 1001 // we'll see it again from this point before it has a chance to complete (and
867 // messing out the request order). The down side is that if for some reason 1002 // we'll be messing out the request order). The down side is that if for some
868 // notifying request A ends up cancelling request B (for the same key), we 1003 // reason notifying request A ends up cancelling request B (for the same key),
869 // won't find request B anywhere (because it would be in a local variable 1004 // we won't find request B anywhere (because it would be in a local variable
870 // here) and that's bad. If there is a chance for that to happen, we'll have 1005 // here) and that's bad. If there is a chance for that to happen, we'll have
871 // to move the callback used to be a CancelableCallback. By the way, for this 1006 // to move the callback used to be a CancelableCallback. By the way, for this
872 // to happen the action (to cancel B) has to be synchronous to the 1007 // to happen the action (to cancel B) has to be synchronous to the
873 // notification for request A. 1008 // notification for request A.
874 WorkItemList pending_items; 1009 WorkItemList pending_items;
875 pending_items.swap(new_entry->pending_queue); 1010 pending_items.swap(pending_op->pending_queue);
876 DeleteNewEntry(new_entry); 1011 DeletePendingOp(pending_op);
877 1012
878 item->NotifyTransaction(result, entry); 1013 item->NotifyTransaction(result, entry);
879 1014
880 while (!pending_items.empty()) { 1015 while (!pending_items.empty()) {
881 item.reset(pending_items.front()); 1016 item.reset(pending_items.front());
882 pending_items.pop_front(); 1017 pending_items.pop_front();
883 1018
884 if (item->operation() == WI_DOOM_ENTRY) { 1019 if (item->operation() == WI_DOOM_ENTRY) {
885 // A queued doom request is always a race. 1020 // A queued doom request is always a race.
886 fail_requests = true; 1021 fail_requests = true;
(...skipping 26 matching lines...) Expand all
913 // Failed Create followed by an Open. 1048 // Failed Create followed by an Open.
914 item->NotifyTransaction(ERR_CACHE_RACE, NULL); 1049 item->NotifyTransaction(ERR_CACHE_RACE, NULL);
915 fail_requests = true; 1050 fail_requests = true;
916 } else { 1051 } else {
917 item->NotifyTransaction(result, entry); 1052 item->NotifyTransaction(result, entry);
918 } 1053 }
919 } 1054 }
920 } 1055 }
921 } 1056 }
922 1057
1058 void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
1059 scoped_ptr<WorkItem> item(pending_op->writer);
1060 WorkItemOperation op = item->operation();
1061 DCHECK_EQ(WI_CREATE_BACKEND, op);
1062
1063 if (type_ != MEMORY_CACHE)
1064 disk_cache_dir_ = FilePath(); // Reclaim memory.
1065
1066 if (result == OK)
1067 disk_cache_.reset(temp_backend_);
1068
1069 item->DoCallback(result, temp_backend_);
1070
1071 // Notify and all callers and delete all pending work items.
1072 while (!pending_op->pending_queue.empty()) {
1073 scoped_ptr<WorkItem> pending_item(pending_op->pending_queue.front());
1074 pending_op->pending_queue.pop_front();
1075 DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
1076
1077 // This could be an external caller or a transaction waiting on Start().
1078 pending_item->DoCallback(result, temp_backend_);
1079 pending_item->NotifyTransaction(result, NULL);
1080 }
1081
1082 DeletePendingOp(pending_op);
1083 building_backend_ = false;
1084 }
1085
923 } // namespace net 1086 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698