Chromium Code Reviews| Index: content/browser/service_worker/service_worker_cache.cc |
| diff --git a/content/browser/service_worker/service_worker_cache.cc b/content/browser/service_worker/service_worker_cache.cc |
| index 3011356f4f17f3b81f8ae0867ae561e265da2fd2..0fe4c9e656aa8db9841708ce76e0b647410cbbaf 100644 |
| --- a/content/browser/service_worker/service_worker_cache.cc |
| +++ b/content/browser/service_worker/service_worker_cache.cc |
| @@ -428,29 +428,27 @@ base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { |
| void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request, |
| scoped_ptr<ServiceWorkerResponse> response, |
| const ResponseCallback& callback) { |
| - IncPendingOps(); |
| - ResponseCallback pending_callback = |
| - base::Bind(&ServiceWorkerCache::PendingResponseCallback, |
| - weak_ptr_factory_.GetWeakPtr(), callback); |
| scoped_ptr<storage::BlobDataHandle> blob_data_handle; |
| if (!response->blob_uuid.empty()) { |
| if (!blob_storage_context_) { |
| - pending_callback.Run(ErrorTypeStorage, |
| - scoped_ptr<ServiceWorkerResponse>(), |
| - scoped_ptr<storage::BlobDataHandle>()); |
| + callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(), |
| + scoped_ptr<storage::BlobDataHandle>()); |
| return; |
| } |
| blob_data_handle = |
| blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); |
| if (!blob_data_handle) { |
| - pending_callback.Run(ErrorTypeStorage, |
| - scoped_ptr<ServiceWorkerResponse>(), |
| - scoped_ptr<storage::BlobDataHandle>()); |
| + callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(), |
| + scoped_ptr<storage::BlobDataHandle>()); |
| return; |
| } |
| } |
| + ResponseCallback pending_callback = |
| + base::Bind(&ServiceWorkerCache::PendingResponseCallback, |
| + weak_ptr_factory_.GetWeakPtr(), callback); |
| + |
| scoped_ptr<PutContext> put_context(new PutContext( |
| origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(), |
| pending_callback, request_context_, quota_manager_proxy_)); |
| @@ -462,30 +460,30 @@ void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request, |
| put_context->response->blob_uuid); |
| } |
| - base::Closure continuation = |
| - base::Bind(&ServiceWorkerCache::PutImpl, weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(put_context.Pass())); |
| + pending_operations_.push_back(base::Bind(&ServiceWorkerCache::PutImpl, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(put_context.Pass()))); |
| if (backend_state_ == BACKEND_UNINITIALIZED) { |
| - InitBackend(continuation); |
| + InitBackend(pending_operations_.back()); |
| return; |
| } |
| - continuation.Run(); |
| + RunOperationIfIdle(); |
| } |
| void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request, |
| const ResponseCallback& callback) { |
| - IncPendingOps(); |
| ResponseCallback pending_callback = |
| base::Bind(&ServiceWorkerCache::PendingResponseCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| + pending_operations_.push_back( |
| + base::Bind(&ServiceWorkerCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(request.Pass()), pending_callback)); |
| switch (backend_state_) { |
| case BACKEND_UNINITIALIZED: |
| - InitBackend(base::Bind(&ServiceWorkerCache::Match, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(request.Pass()), pending_callback)); |
| + InitBackend(pending_operations_.back()); |
| return; |
| case BACKEND_CLOSED: |
| pending_callback.Run(ErrorTypeStorage, |
| @@ -494,106 +492,57 @@ void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request, |
| return; |
| case BACKEND_OPEN: |
| DCHECK(backend_); |
| - break; |
| + RunOperationIfIdle(); |
| + return; |
| } |
| - |
| - scoped_ptr<MatchContext> match_context(new MatchContext( |
| - request.Pass(), pending_callback, blob_storage_context_)); |
| - |
| - disk_cache::Entry** entry_ptr = &match_context->entry; |
| - ServiceWorkerFetchRequest* request_ptr = match_context->request.get(); |
| - |
| - net::CompletionCallback open_entry_callback = base::Bind( |
| - &ServiceWorkerCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(match_context.Pass())); |
| - |
| - int rv = backend_->OpenEntry( |
| - request_ptr->url.spec(), entry_ptr, open_entry_callback); |
| - if (rv != net::ERR_IO_PENDING) |
| - open_entry_callback.Run(rv); |
| + NOTREACHED(); |
| } |
| void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request, |
| const ErrorCallback& callback) { |
| - IncPendingOps(); |
| ErrorCallback pending_callback = |
| base::Bind(&ServiceWorkerCache::PendingErrorCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| + pending_operations_.push_back(base::Bind( |
| + &ServiceWorkerCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(request.Pass()), pending_callback)); |
| switch (backend_state_) { |
| case BACKEND_UNINITIALIZED: |
| - InitBackend(base::Bind(&ServiceWorkerCache::Delete, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(request.Pass()), pending_callback)); |
| + InitBackend(pending_operations_.back()); |
| return; |
| case BACKEND_CLOSED: |
| pending_callback.Run(ErrorTypeStorage); |
| return; |
| case BACKEND_OPEN: |
| DCHECK(backend_); |
| - break; |
| + RunOperationIfIdle(); |
| + return; |
| } |
| - |
| - scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
| - |
| - disk_cache::Entry** entry_ptr = entry.get(); |
| - |
| - ServiceWorkerFetchRequest* request_ptr = request.get(); |
| - |
| - net::CompletionCallback open_entry_callback = base::Bind( |
| - &ServiceWorkerCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(), |
| - origin_, base::Passed(request.Pass()), pending_callback, |
| - base::Passed(entry.Pass()), quota_manager_proxy_); |
| - |
| - int rv = backend_->OpenEntry( |
| - request_ptr->url.spec(), entry_ptr, open_entry_callback); |
| - if (rv != net::ERR_IO_PENDING) |
| - open_entry_callback.Run(rv); |
| + NOTREACHED(); |
| } |
| void ServiceWorkerCache::Keys(const RequestsCallback& callback) { |
| - IncPendingOps(); |
| RequestsCallback pending_callback = |
| base::Bind(&ServiceWorkerCache::PendingRequestsCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| + pending_operations_.push_back(base::Bind(&ServiceWorkerCache::KeysImpl, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + pending_callback)); |
| switch (backend_state_) { |
| case BACKEND_UNINITIALIZED: |
| - InitBackend(base::Bind(&ServiceWorkerCache::Keys, |
| - weak_ptr_factory_.GetWeakPtr(), pending_callback)); |
| + InitBackend(pending_operations_.back()); |
| return; |
| case BACKEND_CLOSED: |
| pending_callback.Run(ErrorTypeStorage, scoped_ptr<Requests>()); |
| return; |
| case BACKEND_OPEN: |
| DCHECK(backend_); |
| - break; |
| + RunOperationIfIdle(); |
| + return; |
| } |
| - |
| - // 1. Iterate through all of the entries, open them, and add them to a vector. |
| - // 2. For each open entry: |
| - // 2.1. Read the headers into a protobuf. |
| - // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key"). |
| - // 2.3. Push the response into a vector of requests to be returned. |
| - // 3. Return the vector of requests (keys). |
| - |
| - // The entries have to be loaded into a vector first because enumeration loops |
| - // forever if you read data from a cache entry while enumerating. |
| - |
| - scoped_ptr<KeysContext> keys_context(new KeysContext(pending_callback)); |
| - |
| - keys_context->backend_iterator = backend_->CreateIterator(); |
| - disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator; |
| - disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry; |
| - |
| - net::CompletionCallback open_entry_callback = base::Bind( |
| - &ServiceWorkerCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(keys_context.Pass())); |
| - |
| - int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback); |
| - |
| - if (rv != net::ERR_IO_PENDING) |
| - open_entry_callback.Run(rv); |
| + NOTREACHED(); |
| } |
| void ServiceWorkerCache::Close(const base::Closure& callback) { |
| @@ -601,15 +550,14 @@ void ServiceWorkerCache::Close(const base::Closure& callback) { |
| << "Don't call ServiceWorkerCache::Close() twice."; |
| backend_state_ = BACKEND_CLOSED; |
| - if (pending_ops_ > 0) { |
| - DCHECK(ops_complete_callback_.is_null()); |
| - ops_complete_callback_ = |
| - base::Bind(&ServiceWorkerCache::CloseImpl, |
| - weak_ptr_factory_.GetWeakPtr(), callback); |
| - return; |
| - } |
| + base::Closure pending_callback = |
| + base::Bind(&ServiceWorkerCache::PendingClosure, |
| + weak_ptr_factory_.GetWeakPtr(), callback); |
| - CloseImpl(callback); |
| + pending_operations_.push_back(base::Bind(&ServiceWorkerCache::CloseImpl, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + pending_callback)); |
| + RunOperationIfIdle(); |
| } |
| int64 ServiceWorkerCache::MemoryBackedSize() const { |
| @@ -652,11 +600,37 @@ ServiceWorkerCache::ServiceWorkerCache( |
| quota_manager_proxy_(quota_manager_proxy), |
| blob_storage_context_(blob_context), |
| backend_state_(BACKEND_UNINITIALIZED), |
| + initializing_(false), |
| memory_only_(path.empty()), |
| - pending_ops_(0), |
| weak_ptr_factory_(this) { |
| } |
| +void ServiceWorkerCache::MatchImpl( |
| + scoped_ptr<ServiceWorkerFetchRequest> request, |
| + const ResponseCallback& callback) { |
| + DCHECK(backend_state_ != BACKEND_UNINITIALIZED); |
| + if (backend_state_ != BACKEND_OPEN) { |
| + callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(), |
| + scoped_ptr<storage::BlobDataHandle>()); |
| + return; |
| + } |
| + |
| + scoped_ptr<MatchContext> match_context( |
| + new MatchContext(request.Pass(), callback, blob_storage_context_)); |
| + |
| + disk_cache::Entry** entry_ptr = &match_context->entry; |
| + ServiceWorkerFetchRequest* request_ptr = match_context->request.get(); |
| + |
| + net::CompletionCallback open_entry_callback = base::Bind( |
| + &ServiceWorkerCache::MatchDidOpenEntry, weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(match_context.Pass())); |
| + |
| + int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr, |
| + open_entry_callback); |
| + if (rv != net::ERR_IO_PENDING) |
| + open_entry_callback.Run(rv); |
| +} |
| + |
| void ServiceWorkerCache::MatchDidOpenEntry( |
| scoped_ptr<MatchContext> match_context, |
| int rv) { |
| @@ -818,6 +792,7 @@ void ServiceWorkerCache::MatchDoneWithBody( |
| } |
| void ServiceWorkerCache::PutImpl(scoped_ptr<PutContext> put_context) { |
| + DCHECK(backend_state_ != BACKEND_UNINITIALIZED); |
| if (backend_state_ != BACKEND_OPEN) { |
| put_context->callback.Run(ErrorTypeStorage, |
| scoped_ptr<ServiceWorkerResponse>(), |
| @@ -828,9 +803,9 @@ void ServiceWorkerCache::PutImpl(scoped_ptr<PutContext> put_context) { |
| scoped_ptr<ServiceWorkerFetchRequest> request_copy( |
| new ServiceWorkerFetchRequest(*put_context->request)); |
| - Delete(request_copy.Pass(), base::Bind(&ServiceWorkerCache::PutDidDelete, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - base::Passed(put_context.Pass()))); |
| + DeleteImpl(request_copy.Pass(), base::Bind(&ServiceWorkerCache::PutDidDelete, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(put_context.Pass()))); |
| } |
| void ServiceWorkerCache::PutDidDelete(scoped_ptr<PutContext> put_context, |
| @@ -1003,6 +978,31 @@ void ServiceWorkerCache::PutDidWriteBlobToCache( |
| put_context->out_blob_data_handle.Pass()); |
| } |
| +void ServiceWorkerCache::DeleteImpl( |
| + scoped_ptr<ServiceWorkerFetchRequest> request, |
| + const ErrorCallback& callback) { |
| + DCHECK(backend_state_ != BACKEND_UNINITIALIZED); |
| + if (backend_state_ != BACKEND_OPEN) { |
| + callback.Run(ErrorTypeStorage); |
| + return; |
| + } |
| + scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
| + |
| + disk_cache::Entry** entry_ptr = entry.get(); |
| + |
| + ServiceWorkerFetchRequest* request_ptr = request.get(); |
| + |
| + net::CompletionCallback open_entry_callback = base::Bind( |
| + &ServiceWorkerCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(), |
| + origin_, base::Passed(request.Pass()), callback, |
| + base::Passed(entry.Pass()), quota_manager_proxy_); |
| + |
| + int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr, |
| + open_entry_callback); |
| + if (rv != net::ERR_IO_PENDING) |
| + open_entry_callback.Run(rv); |
| +} |
| + |
| void ServiceWorkerCache::DeleteDidOpenEntry( |
| const GURL& origin, |
| scoped_ptr<ServiceWorkerFetchRequest> request, |
| @@ -1030,6 +1030,39 @@ void ServiceWorkerCache::DeleteDidOpenEntry( |
| callback.Run(ServiceWorkerCache::ErrorTypeOK); |
| } |
| +void ServiceWorkerCache::KeysImpl(const RequestsCallback& callback) { |
| + DCHECK(backend_state_ != BACKEND_UNINITIALIZED); |
| + if (backend_state_ != BACKEND_OPEN) { |
| + callback.Run(ErrorTypeStorage, scoped_ptr<Requests>()); |
| + return; |
| + } |
| + |
| + // 1. Iterate through all of the entries, open them, and add them to a vector. |
| + // 2. For each open entry: |
| + // 2.1. Read the headers into a protobuf. |
| + // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key"). |
| + // 2.3. Push the response into a vector of requests to be returned. |
| + // 3. Return the vector of requests (keys). |
| + |
| + // The entries have to be loaded into a vector first because enumeration loops |
| + // forever if you read data from a cache entry while enumerating. |
| + |
| + scoped_ptr<KeysContext> keys_context(new KeysContext(callback)); |
| + |
| + keys_context->backend_iterator = backend_->CreateIterator(); |
| + disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator; |
| + disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry; |
| + |
| + net::CompletionCallback open_entry_callback = base::Bind( |
| + &ServiceWorkerCache::KeysDidOpenNextEntry, weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(keys_context.Pass())); |
| + |
| + int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback); |
| + |
| + if (rv != net::ERR_IO_PENDING) |
| + open_entry_callback.Run(rv); |
| +} |
| + |
| void ServiceWorkerCache::KeysDidOpenNextEntry( |
| scoped_ptr<KeysContext> keys_context, |
| int rv) { |
| @@ -1115,6 +1148,7 @@ void ServiceWorkerCache::KeysDidReadMetadata( |
| void ServiceWorkerCache::CloseImpl(const base::Closure& callback) { |
| DCHECK(backend_state_ == BACKEND_CLOSED); |
| + DCHECK(pending_operations_.size() == 1u); |
| backend_.reset(); |
| callback.Run(); |
| } |
| @@ -1166,42 +1200,51 @@ void ServiceWorkerCache::CreateBackendDidCreate( |
| void ServiceWorkerCache::InitBackend(const base::Closure& callback) { |
|
michaeln
2015/01/23 00:55:25
The contract is a little odd, the 'callback' provi
jkarlin
2015/01/23 18:13:42
Done.
|
| DCHECK(backend_state_ == BACKEND_UNINITIALIZED); |
| - init_callbacks_.push_back(callback); |
| - // If this isn't the first call to Init then return as the initialization |
| - // has already started. |
| - if (init_callbacks_.size() > 1u) |
| + if (initializing_) |
| return; |
| + initializing_ = true; |
| CreateBackend(base::Bind(&ServiceWorkerCache::InitDone, |
| - weak_ptr_factory_.GetWeakPtr())); |
| + weak_ptr_factory_.GetWeakPtr(), callback)); |
| } |
| -void ServiceWorkerCache::InitDone(ErrorType error) { |
| +void ServiceWorkerCache::InitDone(const base::Closure& callback, |
| + ErrorType error) { |
| + initializing_ = false; |
| backend_state_ = (error == ErrorTypeOK && backend_ && |
| backend_state_ == BACKEND_UNINITIALIZED) |
| ? BACKEND_OPEN |
| : BACKEND_CLOSED; |
| - for (std::vector<base::Closure>::iterator it = init_callbacks_.begin(); |
| - it != init_callbacks_.end(); ++it) { |
| - it->Run(); |
| - } |
| - init_callbacks_.clear(); |
| + callback.Run(); |
| } |
| -void ServiceWorkerCache::DecPendingOps() { |
| - DCHECK(pending_ops_ > 0); |
| - pending_ops_--; |
| - if (pending_ops_ == 0 && !ops_complete_callback_.is_null()) { |
| - ops_complete_callback_.Run(); |
| - ops_complete_callback_.Reset(); |
| - } |
| +void ServiceWorkerCache::CompleteOperationAndRunNext() { |
| + DCHECK(!pending_operations_.empty()); |
| + |
| + pending_operations_.pop_front(); |
| + |
| + // TODO(jkarlin): Run multiple operations in parallel where allowed (e.g., if |
| + // they're for different keys then they won't interfere). See |
| + // https://crbug.com/451174. |
| + if (!pending_operations_.empty()) |
| + pending_operations_.front().Run(); |
| +} |
| + |
| +void ServiceWorkerCache::RunOperationIfIdle() { |
|
michaeln
2015/01/23 00:55:25
nit: this method is a little dangerous, if called
jkarlin
2015/01/23 18:13:42
Done.
|
| + if (pending_operations_.size() == 1u) |
| + pending_operations_.front().Run(); |
| +} |
| + |
| +void ServiceWorkerCache::PendingClosure(const base::Closure& callback) { |
| + callback.Run(); |
| + CompleteOperationAndRunNext(); |
| } |
| void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback& callback, |
| ErrorType error) { |
| callback.Run(error); |
| - DecPendingOps(); |
| + CompleteOperationAndRunNext(); |
| } |
| void ServiceWorkerCache::PendingResponseCallback( |
| @@ -1210,7 +1253,7 @@ void ServiceWorkerCache::PendingResponseCallback( |
| scoped_ptr<ServiceWorkerResponse> response, |
| scoped_ptr<storage::BlobDataHandle> blob_data_handle) { |
| callback.Run(error, response.Pass(), blob_data_handle.Pass()); |
| - DecPendingOps(); |
| + CompleteOperationAndRunNext(); |
| } |
| void ServiceWorkerCache::PendingRequestsCallback( |
| @@ -1218,7 +1261,7 @@ void ServiceWorkerCache::PendingRequestsCallback( |
| ErrorType error, |
| scoped_ptr<Requests> requests) { |
| callback.Run(error, requests.Pass()); |
| - DecPendingOps(); |
| + CompleteOperationAndRunNext(); |
| } |
| } // namespace content |