| Index: net/http/http_cache.cc
|
| ===================================================================
|
| --- net/http/http_cache.cc (revision 46487)
|
| +++ net/http/http_cache.cc (working copy)
|
| @@ -17,6 +17,7 @@
|
| #include "base/message_loop.h"
|
| #include "base/pickle.h"
|
| #include "base/ref_counted.h"
|
| +#include "base/stl_util-inl.h"
|
| #include "base/string_util.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/load_flags.h"
|
| @@ -49,13 +50,14 @@
|
| //-----------------------------------------------------------------------------
|
|
|
| // This structure keeps track of work items that are attempting to create or
|
| -// open cache entries.
|
| -struct HttpCache::NewEntry {
|
| - NewEntry() : disk_entry(NULL), writer(NULL) {}
|
| - ~NewEntry() {}
|
| +// open cache entries or the backend itself.
|
| +struct HttpCache::PendingOp {
|
| + PendingOp() : disk_entry(NULL), writer(NULL), callback(NULL) {}
|
| + ~PendingOp() {}
|
|
|
| disk_cache::Entry* disk_entry;
|
| WorkItem* writer;
|
| + CompletionCallback* callback; // BackendCallback.
|
| WorkItemList pending_queue;
|
| };
|
|
|
| @@ -63,19 +65,24 @@
|
|
|
| // The type of operation represented by a work item.
|
| enum WorkItemOperation {
|
| + WI_CREATE_BACKEND,
|
| WI_OPEN_ENTRY,
|
| WI_CREATE_ENTRY,
|
| WI_DOOM_ENTRY
|
| };
|
|
|
| -// A work item encapsulates a single request for cache entry with all the
|
| +// A work item encapsulates a single request to the backend with all the
|
| // information needed to complete that request.
|
| class HttpCache::WorkItem {
|
| public:
|
| - WorkItem(ActiveEntry** entry, Transaction* trans, WorkItemOperation operation)
|
| - : entry_(entry), trans_(trans), operation_(operation) {}
|
| + WorkItem(WorkItemOperation operation, Transaction* trans, ActiveEntry** entry)
|
| + : operation_(operation), trans_(trans), entry_(entry), callback_(NULL),
|
| + backend_(NULL) {}
|
| + WorkItem(WorkItemOperation operation, Transaction* trans,
|
| + CompletionCallback* cb, disk_cache::Backend** backend)
|
| + : operation_(operation), trans_(trans), entry_(NULL), callback_(cb),
|
| + backend_(backend) {}
|
| ~WorkItem() {}
|
| - WorkItemOperation operation() { return operation_; }
|
|
|
| // Calls back the transaction with the result of the operation.
|
| void NotifyTransaction(int result, ActiveEntry* entry) {
|
| @@ -85,15 +92,27 @@
|
| trans_->io_callback()->Run(result);
|
| }
|
|
|
| + // Notifies the caller about the operation completion.
|
| + void DoCallback(int result, disk_cache::Backend* backend) {
|
| + if (backend_)
|
| + *backend_ = backend;
|
| + if (callback_)
|
| + callback_->Run(result);
|
| + }
|
| +
|
| + WorkItemOperation operation() { return operation_; }
|
| void ClearTransaction() { trans_ = NULL; }
|
| void ClearEntry() { entry_ = NULL; }
|
| + void ClearCallback() { callback_ = NULL; }
|
| bool Matches(Transaction* trans) const { return trans == trans_; }
|
| - bool IsValid() const { return trans_ || entry_; }
|
| + bool IsValid() const { return trans_ || entry_ || callback_; }
|
|
|
| private:
|
| + WorkItemOperation operation_;
|
| + Transaction* trans_;
|
| ActiveEntry** entry_;
|
| - Transaction* trans_;
|
| - WorkItemOperation operation_;
|
| + CompletionCallback* callback_; // User callback.
|
| + disk_cache::Backend** backend_;
|
| };
|
|
|
| //-----------------------------------------------------------------------------
|
| @@ -102,18 +121,18 @@
|
| // pass multiple arguments to the completion routine.
|
| class HttpCache::BackendCallback : public CallbackRunner<Tuple1<int> > {
|
| public:
|
| - BackendCallback(HttpCache* cache, NewEntry* entry)
|
| - : cache_(cache), entry_(entry) {}
|
| + BackendCallback(HttpCache* cache, PendingOp* pending_op)
|
| + : cache_(cache), pending_op_(pending_op) {}
|
| ~BackendCallback() {}
|
|
|
| virtual void RunWithParams(const Tuple1<int>& params) {
|
| - cache_->OnIOComplete(params.a, entry_);
|
| + cache_->OnIOComplete(params.a, pending_op_);
|
| delete this;
|
| }
|
|
|
| private:
|
| HttpCache* cache_;
|
| - NewEntry* entry_;
|
| + PendingOp* pending_op_;
|
| DISALLOW_COPY_AND_ASSIGN(BackendCallback);
|
| };
|
|
|
| @@ -205,6 +224,8 @@
|
| int cache_size)
|
| : disk_cache_dir_(cache_dir),
|
| cache_thread_(cache_thread),
|
| + temp_backend_(NULL),
|
| + building_backend_(false),
|
| mode_(NORMAL),
|
| type_(DISK_CACHE),
|
| network_layer_(HttpNetworkLayer::CreateFactory(
|
| @@ -212,7 +233,8 @@
|
| ssl_config_service, http_auth_handler_factory)),
|
| ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| + cache_size_(cache_size),
|
| + create_backend_fn_(NULL) {
|
| }
|
|
|
| HttpCache::HttpCache(HttpNetworkSession* session,
|
| @@ -221,12 +243,15 @@
|
| int cache_size)
|
| : disk_cache_dir_(cache_dir),
|
| cache_thread_(cache_thread),
|
| + temp_backend_(NULL),
|
| + building_backend_(false),
|
| mode_(NORMAL),
|
| type_(DISK_CACHE),
|
| network_layer_(HttpNetworkLayer::CreateFactory(session)),
|
| ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| + cache_size_(cache_size),
|
| + create_backend_fn_(NULL) {
|
| }
|
|
|
| HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier,
|
| @@ -235,25 +260,33 @@
|
| SSLConfigService* ssl_config_service,
|
| HttpAuthHandlerFactory* http_auth_handler_factory,
|
| int cache_size)
|
| - : mode_(NORMAL),
|
| + : cache_thread_(NULL),
|
| + temp_backend_(NULL),
|
| + building_backend_(false),
|
| + mode_(NORMAL),
|
| type_(MEMORY_CACHE),
|
| network_layer_(HttpNetworkLayer::CreateFactory(
|
| network_change_notifier, host_resolver, proxy_service,
|
| ssl_config_service, http_auth_handler_factory)),
|
| ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| + cache_size_(cache_size),
|
| + create_backend_fn_(NULL) {
|
| }
|
|
|
| HttpCache::HttpCache(HttpTransactionFactory* network_layer,
|
| disk_cache::Backend* disk_cache)
|
| - : mode_(NORMAL),
|
| + : cache_thread_(NULL),
|
| + temp_backend_(NULL),
|
| + building_backend_(false),
|
| + mode_(NORMAL),
|
| type_(DISK_CACHE),
|
| network_layer_(network_layer),
|
| disk_cache_(disk_cache),
|
| ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| enable_range_support_(true),
|
| - cache_size_(0) {
|
| + cache_size_(0),
|
| + create_backend_fn_(NULL) {
|
| }
|
|
|
| HttpCache::~HttpCache() {
|
| @@ -270,9 +303,19 @@
|
| DeactivateEntry(entry);
|
| }
|
|
|
| - ActiveEntriesSet::iterator it = doomed_entries_.begin();
|
| - for (; it != doomed_entries_.end(); ++it)
|
| - delete *it;
|
| + STLDeleteElements(&doomed_entries_);
|
| +
|
| + PendingOpsMap::iterator pending_it = pending_ops_.begin();
|
| + for (; pending_it != pending_ops_.end(); ++pending_it) {
|
| + // We are not notifying the transactions about the cache going away, even
|
| + // though they are waiting for a callback that will never fire.
|
| + PendingOp* pending_op = pending_it->second;
|
| + delete pending_op->writer;
|
| + delete pending_op->callback;
|
| +
|
| + STLDeleteElements(&pending_op->pending_queue);
|
| + delete pending_op;
|
| + }
|
| }
|
|
|
| disk_cache::Backend* HttpCache::GetBackend() {
|
| @@ -296,13 +339,21 @@
|
| int HttpCache::GetBackend(disk_cache::Backend** backend,
|
| CompletionCallback* callback) {
|
| DCHECK(callback != NULL);
|
| - *backend = GetBackend();
|
| - return OK;
|
| +
|
| + if (disk_cache_.get()) {
|
| + *backend = disk_cache_.get();
|
| + return OK;
|
| + }
|
| +
|
| + DCHECK_GE(cache_size_, 0);
|
| + return CreateBackend(backend, callback);
|
| }
|
|
|
| int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
|
| // Do lazy initialization of disk cache if needed.
|
| - GetBackend();
|
| + if (!disk_cache_.get())
|
| + CreateBackend(NULL, NULL); // We don't care about the result.
|
| +
|
| trans->reset(new HttpCache::Transaction(this, enable_range_support_));
|
| return OK;
|
| }
|
| @@ -392,6 +443,68 @@
|
|
|
| //-----------------------------------------------------------------------------
|
|
|
| +int HttpCache::CreateBackend(disk_cache::Backend** backend,
|
| + CompletionCallback* callback) {
|
| + // We may end up with no folder name and no cache if the initialization
|
| + // of the disk cache fails.
|
| + if (type_ != MEMORY_CACHE && disk_cache_dir_.empty())
|
| + return ERR_FAILED;
|
| +
|
| + DCHECK_GE(cache_size_, 0);
|
| + building_backend_ = true;
|
| +
|
| + scoped_ptr<WorkItem> item(new WorkItem(WI_CREATE_BACKEND, NULL, callback,
|
| + backend));
|
| +
|
| + // This is the only operation that we can do that is not related to any given
|
| + // entry, so we use an empty key for it.
|
| + PendingOp* pending_op = GetPendingOp("");
|
| + if (pending_op->writer) {
|
| + if (callback)
|
| + pending_op->pending_queue.push_back(item.release());
|
| + return ERR_IO_PENDING;
|
| + }
|
| +
|
| + DCHECK(pending_op->pending_queue.empty());
|
| +
|
| + pending_op->writer = item.release();
|
| + BackendCallback* my_callback = new BackendCallback(this, pending_op);
|
| + pending_op->callback = my_callback;
|
| +
|
| + // See if this is a unit test. TODO(rvargas): Cleanup this after removing the
|
| + // overloaded method.
|
| + int rv;
|
| + if (create_backend_fn_) {
|
| + rv = create_backend_fn_(type_, disk_cache_dir_, cache_size_, true,
|
| + cache_thread_, &temp_backend_, my_callback);
|
| + } else {
|
| + rv = disk_cache::CreateCacheBackend(type_, disk_cache_dir_, cache_size_,
|
| + true, cache_thread_, &temp_backend_,
|
| + my_callback);
|
| + }
|
| +
|
| + if (rv != ERR_IO_PENDING) {
|
| + pending_op->writer->ClearCallback();
|
| + my_callback->Run(rv);
|
| + }
|
| +
|
| + return rv;
|
| +}
|
| +
|
| +int HttpCache::GetBackendForTransaction(Transaction* trans) {
|
| + if (disk_cache_.get())
|
| + return OK;
|
| +
|
| + if (!building_backend_)
|
| + return ERR_FAILED;
|
| +
|
| + WorkItem* item = new WorkItem(WI_CREATE_BACKEND, trans, NULL, NULL);
|
| + PendingOp* pending_op = GetPendingOp("");
|
| + DCHECK(pending_op->writer);
|
| + pending_op->pending_queue.push_back(item);
|
| + return ERR_IO_PENDING;
|
| +}
|
| +
|
| // Generate a key that can be used inside the cache.
|
| std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
|
| // Strip out the reference, username, and password sections of the URL.
|
| @@ -457,17 +570,18 @@
|
|
|
| int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
|
| DCHECK(trans);
|
| - WorkItem* item = new WorkItem(NULL, trans, WI_DOOM_ENTRY);
|
| - NewEntry* new_entry = GetNewEntry(key);
|
| - if (new_entry->writer) {
|
| - new_entry->pending_queue.push_back(item);
|
| + WorkItem* item = new WorkItem(WI_DOOM_ENTRY, trans, NULL);
|
| + PendingOp* pending_op = GetPendingOp(key);
|
| + if (pending_op->writer) {
|
| + pending_op->pending_queue.push_back(item);
|
| return ERR_IO_PENDING;
|
| }
|
|
|
| - DCHECK(new_entry->pending_queue.empty());
|
| + DCHECK(pending_op->pending_queue.empty());
|
|
|
| - new_entry->writer = item;
|
| - BackendCallback* my_callback = new BackendCallback(this, new_entry);
|
| + pending_op->writer = item;
|
| + BackendCallback* my_callback = new BackendCallback(this, pending_op);
|
| + pending_op->callback = my_callback;
|
|
|
| int rv = disk_cache_->DoomEntry(key, my_callback);
|
| if (rv != ERR_IO_PENDING) {
|
| @@ -536,38 +650,39 @@
|
| }
|
| }
|
|
|
| -HttpCache::NewEntry* HttpCache::GetNewEntry(const std::string& key) {
|
| +HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) {
|
| DCHECK(!FindActiveEntry(key));
|
|
|
| - NewEntriesMap::const_iterator it = new_entries_.find(key);
|
| - if (it != new_entries_.end())
|
| + PendingOpsMap::const_iterator it = pending_ops_.find(key);
|
| + if (it != pending_ops_.end())
|
| return it->second;
|
|
|
| - NewEntry* entry = new NewEntry();
|
| - new_entries_[key] = entry;
|
| - return entry;
|
| + PendingOp* operation = new PendingOp();
|
| + pending_ops_[key] = operation;
|
| + return operation;
|
| }
|
|
|
| -void HttpCache::DeleteNewEntry(NewEntry* entry) {
|
| +void HttpCache::DeletePendingOp(PendingOp* pending_op) {
|
| std::string key;
|
| - if (entry->disk_entry)
|
| - key = entry->disk_entry->GetKey();
|
| + if (pending_op->disk_entry)
|
| + key = pending_op->disk_entry->GetKey();
|
|
|
| if (!key.empty()) {
|
| - NewEntriesMap::iterator it = new_entries_.find(key);
|
| - DCHECK(it != new_entries_.end());
|
| - new_entries_.erase(it);
|
| + PendingOpsMap::iterator it = pending_ops_.find(key);
|
| + DCHECK(it != pending_ops_.end());
|
| + pending_ops_.erase(it);
|
| } else {
|
| - for (NewEntriesMap::iterator it = new_entries_.begin();
|
| - it != new_entries_.end(); ++it) {
|
| - if (it->second == entry) {
|
| - new_entries_.erase(it);
|
| + for (PendingOpsMap::iterator it = pending_ops_.begin();
|
| + it != pending_ops_.end(); ++it) {
|
| + if (it->second == pending_op) {
|
| + pending_ops_.erase(it);
|
| break;
|
| }
|
| }
|
| }
|
| + DCHECK(pending_op->pending_queue.empty());
|
|
|
| - delete entry;
|
| + delete pending_op;
|
| }
|
|
|
| int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry,
|
| @@ -578,19 +693,20 @@
|
| return OK;
|
| }
|
|
|
| - WorkItem* item = new WorkItem(entry, trans, WI_OPEN_ENTRY);
|
| - NewEntry* new_entry = GetNewEntry(key);
|
| - if (new_entry->writer) {
|
| - new_entry->pending_queue.push_back(item);
|
| + WorkItem* item = new WorkItem(WI_OPEN_ENTRY, trans, entry);
|
| + PendingOp* pending_op = GetPendingOp(key);
|
| + if (pending_op->writer) {
|
| + pending_op->pending_queue.push_back(item);
|
| return ERR_IO_PENDING;
|
| }
|
|
|
| - DCHECK(new_entry->pending_queue.empty());
|
| + DCHECK(pending_op->pending_queue.empty());
|
|
|
| - new_entry->writer = item;
|
| - BackendCallback* my_callback = new BackendCallback(this, new_entry);
|
| + pending_op->writer = item;
|
| + BackendCallback* my_callback = new BackendCallback(this, pending_op);
|
| + pending_op->callback = my_callback;
|
|
|
| - int rv = disk_cache_->OpenEntry(key, &(new_entry->disk_entry), my_callback);
|
| + int rv = disk_cache_->OpenEntry(key, &(pending_op->disk_entry), my_callback);
|
| if (rv != ERR_IO_PENDING) {
|
| item->ClearTransaction();
|
| my_callback->Run(rv);
|
| @@ -603,19 +719,21 @@
|
| Transaction* trans) {
|
| DCHECK(!FindActiveEntry(key));
|
|
|
| - WorkItem* item = new WorkItem(entry, trans, WI_CREATE_ENTRY);
|
| - NewEntry* new_entry = GetNewEntry(key);
|
| - if (new_entry->writer) {
|
| - new_entry->pending_queue.push_back(item);
|
| + WorkItem* item = new WorkItem(WI_CREATE_ENTRY, trans, entry);
|
| + PendingOp* pending_op = GetPendingOp(key);
|
| + if (pending_op->writer) {
|
| + pending_op->pending_queue.push_back(item);
|
| return ERR_IO_PENDING;
|
| }
|
|
|
| - DCHECK(new_entry->pending_queue.empty());
|
| + DCHECK(pending_op->pending_queue.empty());
|
|
|
| - new_entry->writer = item;
|
| - BackendCallback* my_callback = new BackendCallback(this, new_entry);
|
| + pending_op->writer = item;
|
| + BackendCallback* my_callback = new BackendCallback(this, pending_op);
|
| + pending_op->callback = my_callback;
|
|
|
| - int rv = disk_cache_->CreateEntry(key, &(new_entry->disk_entry), my_callback);
|
| + int rv = disk_cache_->CreateEntry(key, &(pending_op->disk_entry),
|
| + my_callback);
|
| if (rv != ERR_IO_PENDING) {
|
| item->ClearTransaction();
|
| my_callback->Run(rv);
|
| @@ -755,10 +873,22 @@
|
| if (found)
|
| return;
|
|
|
| - NewEntriesMap::const_iterator j = new_entries_.find(trans->key());
|
| - if (j != new_entries_.end())
|
| - found = RemovePendingTransactionFromNewEntry(j->second, trans);
|
| + if (building_backend_) {
|
| + PendingOpsMap::const_iterator j = pending_ops_.find("");
|
| + if (j != pending_ops_.end())
|
| + found = RemovePendingTransactionFromPendingOp(j->second, trans);
|
|
|
| + if (found)
|
| + return;
|
| + }
|
| +
|
| + PendingOpsMap::const_iterator j = pending_ops_.find(trans->key());
|
| + if (j != pending_ops_.end())
|
| + found = RemovePendingTransactionFromPendingOp(j->second, trans);
|
| +
|
| + if (found)
|
| + return;
|
| +
|
| ActiveEntriesSet::iterator k = doomed_entries_.begin();
|
| for (; k != doomed_entries_.end() && !found; ++k)
|
| found = RemovePendingTransactionFromEntry(*k, trans);
|
| @@ -779,14 +909,14 @@
|
| return true;
|
| }
|
|
|
| -bool HttpCache::RemovePendingTransactionFromNewEntry(NewEntry* entry,
|
| - Transaction* trans) {
|
| - if (entry->writer->Matches(trans)) {
|
| - entry->writer->ClearTransaction();
|
| - entry->writer->ClearEntry();
|
| +bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
|
| + Transaction* trans) {
|
| + if (pending_op->writer->Matches(trans)) {
|
| + pending_op->writer->ClearTransaction();
|
| + pending_op->writer->ClearEntry();
|
| return true;
|
| }
|
| - WorkItemList& pending_queue = entry->pending_queue;
|
| + WorkItemList& pending_queue = pending_op->pending_queue;
|
|
|
| WorkItemList::iterator it = pending_queue.begin();
|
| for (; it != pending_queue.end(); ++it) {
|
| @@ -837,9 +967,14 @@
|
| }
|
| }
|
|
|
| -void HttpCache::OnIOComplete(int result, NewEntry* new_entry) {
|
| - scoped_ptr<WorkItem> item(new_entry->writer);
|
| - WorkItemOperation op = item->operation();
|
| +void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
|
| + WorkItemOperation op = pending_op->writer->operation();
|
| +
|
| + // Completing the creation of the backend is simpler than the other cases.
|
| + if (op == WI_CREATE_BACKEND)
|
| + return OnBackendCreated(result, pending_op);
|
| +
|
| + scoped_ptr<WorkItem> item(pending_op->writer);
|
| bool fail_requests = false;
|
|
|
| ActiveEntry* entry = NULL;
|
| @@ -849,31 +984,31 @@
|
| // Anything after a Doom has to be restarted.
|
| fail_requests = true;
|
| } else if (item->IsValid()) {
|
| - key = new_entry->disk_entry->GetKey();
|
| - entry = ActivateEntry(key, new_entry->disk_entry);
|
| + key = pending_op->disk_entry->GetKey();
|
| + entry = ActivateEntry(key, pending_op->disk_entry);
|
| } else {
|
| // The writer transaction is gone.
|
| if (op == WI_CREATE_ENTRY)
|
| - new_entry->disk_entry->Doom();
|
| - new_entry->disk_entry->Close();
|
| + pending_op->disk_entry->Doom();
|
| + pending_op->disk_entry->Close();
|
| fail_requests = true;
|
| }
|
| }
|
|
|
| // We are about to notify a bunch of transactions, and they may decide to
|
| - // re-issue a request (or send a different one). If we don't delete new_entry,
|
| - // the new request will be appended to the end of the list, and we'll see it
|
| - // again from this point before it has a chance to complete (and we'll be
|
| - // messing out the request order). The down side is that if for some reason
|
| - // notifying request A ends up cancelling request B (for the same key), we
|
| - // won't find request B anywhere (because it would be in a local variable
|
| + // re-issue a request (or send a different one). If we don't delete
|
| + // pending_op, the new request will be appended to the end of the list, and
|
| + // we'll see it again from this point before it has a chance to complete (and
|
| + // we'll be messing out the request order). The down side is that if for some
|
| + // reason notifying request A ends up cancelling request B (for the same key),
|
| + // we won't find request B anywhere (because it would be in a local variable
|
| // here) and that's bad. If there is a chance for that to happen, we'll have
|
| // to move the callback used to be a CancelableCallback. By the way, for this
|
| // to happen the action (to cancel B) has to be synchronous to the
|
| // notification for request A.
|
| WorkItemList pending_items;
|
| - pending_items.swap(new_entry->pending_queue);
|
| - DeleteNewEntry(new_entry);
|
| + pending_items.swap(pending_op->pending_queue);
|
| + DeletePendingOp(pending_op);
|
|
|
| item->NotifyTransaction(result, entry);
|
|
|
| @@ -920,4 +1055,32 @@
|
| }
|
| }
|
|
|
| +void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
|
| + scoped_ptr<WorkItem> item(pending_op->writer);
|
| + WorkItemOperation op = item->operation();
|
| + DCHECK_EQ(WI_CREATE_BACKEND, op);
|
| +
|
| + if (type_ != MEMORY_CACHE)
|
| + disk_cache_dir_ = FilePath(); // Reclaim memory.
|
| +
|
| + if (result == OK)
|
| + disk_cache_.reset(temp_backend_);
|
| +
|
| + item->DoCallback(result, temp_backend_);
|
| +
|
| + // Notify and all callers and delete all pending work items.
|
| + while (!pending_op->pending_queue.empty()) {
|
| + scoped_ptr<WorkItem> pending_item(pending_op->pending_queue.front());
|
| + pending_op->pending_queue.pop_front();
|
| + DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
|
| +
|
| + // This could be an external caller or a transaction waiting on Start().
|
| + pending_item->DoCallback(result, temp_backend_);
|
| + pending_item->NotifyTransaction(result, NULL);
|
| + }
|
| +
|
| + DeletePendingOp(pending_op);
|
| + building_backend_ = false;
|
| +}
|
| +
|
| } // namespace net
|
|
|