| Index: content/browser/cache_storage/cache_storage_cache.cc
|
| diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
|
| index cbe1889d4e69d42b0874f8113200fe07e31149bf..cc3c37ae35f46c6ac69b8ddbf1bfc4d3b812ec6c 100644
|
| --- a/content/browser/cache_storage/cache_storage_cache.cc
|
| +++ b/content/browser/cache_storage/cache_storage_cache.cc
|
| @@ -275,7 +275,6 @@ struct CacheStorageCache::PutContext {
|
| scoped_ptr<storage::BlobDataHandle> blob_data_handle;
|
| CacheStorageCache::ErrorCallback callback;
|
| disk_cache::ScopedEntryPtr cache_entry;
|
| - int64_t available_bytes = 0;
|
|
|
| private:
|
| DISALLOW_COPY_AND_ASSIGN(PutContext);
|
| @@ -356,7 +355,51 @@ void CacheStorageCache::BatchOperation(
|
| const std::vector<CacheStorageBatchOperation>& operations,
|
| const ErrorCallback& callback) {
|
| if (!LazyInitialize()) {
|
| - callback.Run(CACHE_STORAGE_ERROR_STORAGE);
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_STORAGE));
|
| + return;
|
| + }
|
| +
|
| + // Estimate the required size of the put operations. The size of the deletes
|
| + // is unknown and not considered.
|
| + int64_t space_required = 0;
|
| + for (const auto& operation : operations) {
|
| + if (operation.operation_type == CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT) {
|
| + space_required +=
|
| + operation.request.blob_size + operation.response.blob_size;
|
| + }
|
| + }
|
| + if (space_required > 0) {
|
| + // GetUsageAndQuota is called before entering a scheduled operation since it
|
| + // can call Size, another scheduled operation. This is racy. The decision
|
| + // to commit is made before the scheduled Put operation runs. By the time
|
| + // Put runs, the cache might already be full and the origin will be larger
|
| + // than it's supposed to be.
|
| + quota_manager_proxy_->GetUsageAndQuota(
|
| + base::ThreadTaskRunnerHandle::Get().get(), origin_,
|
| + storage::kStorageTypeTemporary,
|
| + base::Bind(&CacheStorageCache::BatchDidGetUsageAndQuota,
|
| + weak_ptr_factory_.GetWeakPtr(), operations, callback,
|
| + space_required));
|
| + return;
|
| + }
|
| +
|
| + BatchDidGetUsageAndQuota(operations, callback, 0 /* space_required */,
|
| + storage::kQuotaStatusOk, 0 /* usage */,
|
| + 0 /* quota */);
|
| +}
|
| +
|
| +void CacheStorageCache::BatchDidGetUsageAndQuota(
|
| + const std::vector<CacheStorageBatchOperation>& operations,
|
| + const ErrorCallback& callback,
|
| + int64_t space_required,
|
| + storage::QuotaStatusCode status_code,
|
| + int64_t usage,
|
| + int64_t quota) {
|
| + if (status_code != storage::kQuotaStatusOk ||
|
| + space_required > quota - usage) {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_QUOTA_EXCEEDED));
|
| return;
|
| }
|
|
|
| @@ -445,16 +488,13 @@ void CacheStorageCache::Size(const SizeCallback& callback) {
|
| return;
|
| }
|
|
|
| - if (initializing_) {
|
| - // Note that Size doesn't use the scheduler, see header comments for why.
|
| - pending_size_callbacks_.push_back(callback);
|
| - return;
|
| - }
|
| + SizeCallback pending_callback =
|
| + base::Bind(&CacheStorageCache::PendingSizeCallback,
|
| + weak_ptr_factory_.GetWeakPtr(), callback);
|
|
|
| - // Run immediately so that we don't deadlock on
|
| - // CacheStorageCache::PutDidDelete's call to
|
| - // quota_manager_proxy_->GetUsageAndQuota.
|
| - SizeImpl(callback);
|
| + scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::SizeImpl,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + pending_callback));
|
| }
|
|
|
| void CacheStorageCache::GetSizeThenClose(const SizeCallback& callback) {
|
| @@ -830,33 +870,8 @@ void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
|
| put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
|
| return;
|
| }
|
| -
|
| - quota_manager_proxy_->GetUsageAndQuota(
|
| - base::ThreadTaskRunnerHandle::Get().get(), origin_,
|
| - storage::kStorageTypeTemporary,
|
| - base::Bind(&CacheStorageCache::PutDidGetUsageAndQuota,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - base::Passed(std::move(put_context))));
|
| -}
|
| -
|
| -void CacheStorageCache::PutDidGetUsageAndQuota(
|
| - scoped_ptr<PutContext> put_context,
|
| - storage::QuotaStatusCode status_code,
|
| - int64_t usage,
|
| - int64_t quota) {
|
| - if (backend_state_ != BACKEND_OPEN) {
|
| - put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
|
| - return;
|
| - }
|
| -
|
| - if (status_code != storage::kQuotaStatusOk) {
|
| - put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
|
| - return;
|
| - }
|
| -
|
| - put_context->available_bytes = quota - usage;
|
| -
|
| - scoped_ptr<disk_cache::Entry*> scoped_entry_ptr(new disk_cache::Entry*());
|
| + std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr(
|
| + new disk_cache::Entry*());
|
| disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
|
| ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
|
| disk_cache::Backend* backend_ptr = backend_.get();
|
| @@ -924,12 +939,6 @@ void CacheStorageCache::PutDidCreateEntry(
|
| scoped_refptr<net::StringIOBuffer> buffer(
|
| new net::StringIOBuffer(std::move(serialized)));
|
|
|
| - int64_t bytes_to_write = buffer->size() + put_context->response->blob_size;
|
| - if (put_context->available_bytes < bytes_to_write) {
|
| - put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
|
| - return;
|
| - }
|
| -
|
| // Get a temporary copy of the entry pointer before passing it in base::Bind.
|
| disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get();
|
|
|
| @@ -1303,10 +1312,6 @@ void CacheStorageCache::InitGotCacheSize(CacheStorageError cache_create_error,
|
| ? BACKEND_OPEN
|
| : BACKEND_CLOSED;
|
|
|
| - for (const SizeCallback& callback : pending_size_callbacks_)
|
| - SizeImpl(callback);
|
| - pending_size_callbacks_.clear();
|
| -
|
| UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult",
|
| cache_create_error, CACHE_STORAGE_ERROR_LAST + 1);
|
|
|
|
|