Commit d90d3c63 authored by Jarryd's avatar Jarryd Committed by Commit Bot

CacheStorage: Notify Quota about write errors.

Adds calls to QuotaManagerProxy::NotifyWriteFailed() where write
errors might occur in Cache storage code. With this information, quota
can reasonably guess if the disk is out of space and decide if any
actions should be taken at that point.

Bug: 997258
Change-Id: I7e385b1b40c1ee1117d3964a77e589a29dcbd51c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2008286
Commit-Queue: Jarryd Goodman <jarrydg@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Reviewed-by: default avatarBen Kelly <wanderview@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738643}
parent 0c45050c
......@@ -13,17 +13,23 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/common/storage_histograms.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "url/origin.h"
namespace content {
const int CacheStorageBlobToDiskCache::kBufferSize = 1024 * 512;
CacheStorageBlobToDiskCache::CacheStorageBlobToDiskCache()
CacheStorageBlobToDiskCache::CacheStorageBlobToDiskCache(
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
const url::Origin& origin)
: handle_watcher_(FROM_HERE,
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
base::SequencedTaskRunnerHandle::Get()) {}
base::SequencedTaskRunnerHandle::Get()),
quota_manager_proxy_(std::move(quota_manager_proxy)),
origin_(origin) {}
CacheStorageBlobToDiskCache::~CacheStorageBlobToDiskCache() = default;
......@@ -92,6 +98,7 @@ void CacheStorageBlobToDiskCache::ReadFromBlob() {
void CacheStorageBlobToDiskCache::DidWriteDataToEntry(int expected_bytes,
int rv) {
if (rv != expected_bytes) {
quota_manager_proxy_->NotifyWriteFailed(origin_);
RunCallback(false /* success */);
return;
}
......
......@@ -17,6 +17,11 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/cpp/net_adapters.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "url/origin.h"
namespace storage {
class QuotaManagerProxy;
}
namespace content {
......@@ -30,7 +35,9 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
// The buffer size used for reading from blobs and writing to disk cache.
static const int kBufferSize;
CacheStorageBlobToDiskCache();
CacheStorageBlobToDiskCache(
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
const url::Origin& origin);
~CacheStorageBlobToDiskCache() override;
// Writes the body of |blob_remote| to |entry| with index
......@@ -50,9 +57,10 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
protected:
// Virtual for testing.
virtual void ReadFromBlob();
void DidWriteDataToEntry(int expected_bytes, int rv);
const url::Origin& origin() const { return origin_; }
private:
void DidWriteDataToEntry(int expected_bytes, int rv);
void RunCallback(bool success);
void OnDataPipeReadable(MojoResult result);
......@@ -72,6 +80,9 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
uint64_t expected_total_size_ = 0;
bool data_pipe_closed_ = false;
const scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
const url::Origin origin_;
base::WeakPtrFactory<CacheStorageBlobToDiskCache> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CacheStorageBlobToDiskCache);
......
......@@ -4,6 +4,7 @@
#include "content/browser/cache_storage/cache_storage_blob_to_disk_cache.h"
#include <memory>
#include <string>
#include <utility>
......@@ -11,6 +12,7 @@
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/null_task_runner.h"
......@@ -26,6 +28,8 @@
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/test/mock_quota_manager.h"
#include "storage/browser/test/mock_quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
......@@ -39,13 +43,22 @@ const int kCacheEntryIndex = 1;
// A CacheStorageBlobToDiskCache that can delay reading from blobs.
class TestCacheStorageBlobToDiskCache : public CacheStorageBlobToDiskCache {
public:
TestCacheStorageBlobToDiskCache() {}
~TestCacheStorageBlobToDiskCache() override {}
explicit TestCacheStorageBlobToDiskCache(
scoped_refptr<QuotaManagerProxy> quota_manager_proxy)
: CacheStorageBlobToDiskCache(quota_manager_proxy, url::Origin()) {}
~TestCacheStorageBlobToDiskCache() override = default;
void ContinueReadFromBlob() { CacheStorageBlobToDiskCache::ReadFromBlob(); }
void set_delay_blob_reads(bool delay) { delay_blob_reads_ = delay; }
void DidWriteDataToEntry(int expected_bytes, int rv) {
CacheStorageBlobToDiskCache::DidWriteDataToEntry(expected_bytes, rv);
}
const url::Origin& origin() { return CacheStorageBlobToDiskCache::origin(); }
protected:
void ReadFromBlob() override {
if (delay_blob_reads_)
......@@ -64,8 +77,6 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
CacheStorageBlobToDiskCacheTest()
: task_environment_(BrowserTaskEnvironment::IO_MAINLOOP),
browser_context_(new TestBrowserContext()),
cache_storage_blob_to_disk_cache_(
new TestCacheStorageBlobToDiskCache()),
data_(kTestData),
callback_success_(false),
callback_called_(false) {}
......@@ -74,6 +85,17 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
InitBlobStorage();
InitBlob();
InitCache();
InitQuotaManager();
cache_storage_blob_to_disk_cache_ =
std::make_unique<TestCacheStorageBlobToDiskCache>(
quota_manager_proxy());
}
void TearDown() override {
quota_manager_proxy()->SimulateQuotaManagerDestroyed();
quota_manager_ = nullptr;
quota_manager_proxy_ = nullptr;
}
void InitBlobStorage() {
......@@ -107,6 +129,17 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
disk_cache_entry_.reset(result.ReleaseEntry());
}
void InitQuotaManager() {
EXPECT_TRUE(base_.CreateUniqueTempDir());
base::FilePath base_dir = base_.GetPath().AppendASCII("filesystem");
quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
false /* is_incognito */, base_dir,
base::ThreadTaskRunnerHandle::Get().get(),
nullptr /* special storage policy */);
quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>(
quota_manager(), base::ThreadTaskRunnerHandle::Get().get());
}
std::string ReadCacheContent() {
int bytes_to_read = disk_cache_entry_->GetDataSize(kCacheEntryIndex);
scoped_refptr<net::IOBufferWithSize> buffer =
......@@ -142,6 +175,14 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
callback_called_ = true;
}
MockQuotaManager* quota_manager() {
return static_cast<MockQuotaManager*>(quota_manager_.get());
}
MockQuotaManagerProxy* quota_manager_proxy() {
return static_cast<MockQuotaManagerProxy*>(quota_manager_proxy_.get());
}
BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestBrowserContext> browser_context_;
storage::BlobStorageContext* blob_storage_context_;
......@@ -154,6 +195,11 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
bool callback_success_;
bool callback_called_;
private:
scoped_refptr<storage::QuotaManager> quota_manager_;
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
base::ScopedTempDir base_;
};
TEST_F(CacheStorageBlobToDiskCacheTest, Stream) {
......@@ -199,6 +245,15 @@ TEST_F(CacheStorageBlobToDiskCacheTest, DeleteMidStream) {
EXPECT_FALSE(callback_called_);
}
TEST_F(CacheStorageBlobToDiskCacheTest, NotifyQuotaAboutWriteErrors) {
cache_storage_blob_to_disk_cache_->DidWriteDataToEntry(5, 2);
auto write_error_tracker = quota_manager()->write_error_tracker();
EXPECT_EQ(1U, write_error_tracker.size());
auto write_error_log =
write_error_tracker.find(cache_storage_blob_to_disk_cache_->origin());
EXPECT_NE(write_error_tracker.end(), write_error_log);
EXPECT_EQ(1, write_error_log->second);
}
} // namespace
} // namespace content
......@@ -222,6 +222,159 @@ class DelayableBackend : public disk_cache::Backend {
base::OnceClosure open_entry_started_callback_;
};
class FailableCacheEntry : public disk_cache::Entry {
public:
explicit FailableCacheEntry(disk_cache::Entry* entry) : entry_(entry) {}
void Doom() override { entry_->Doom(); }
void Close() override { entry_->Close(); }
std::string GetKey() const override { return entry_->GetKey(); }
base::Time GetLastUsed() const override { return entry_->GetLastUsed(); }
base::Time GetLastModified() const override {
return entry_->GetLastModified();
}
int32_t GetDataSize(int index) const override {
return entry_->GetDataSize(index);
}
int ReadData(int index,
int offset,
IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback) override {
return entry_->ReadData(index, offset, buf, buf_len, std::move(callback));
}
int WriteData(int index,
int offset,
IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback,
bool truncate) override {
std::move(callback).Run(net::ERR_FAILED);
return net::ERR_IO_PENDING;
}
int ReadSparseData(int64_t offset,
IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback) override {
return entry_->ReadSparseData(offset, buf, buf_len, std::move(callback));
}
int WriteSparseData(int64_t offset,
IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback) override {
return entry_->WriteSparseData(offset, buf, buf_len, std::move(callback));
}
int GetAvailableRange(int64_t offset,
int len,
int64_t* start,
CompletionOnceCallback callback) override {
return entry_->GetAvailableRange(offset, len, start, std::move(callback));
}
bool CouldBeSparse() const override { return entry_->CouldBeSparse(); }
void CancelSparseIO() override { entry_->CancelSparseIO(); }
net::Error ReadyForSparseIO(CompletionOnceCallback callback) override {
return entry_->ReadyForSparseIO(std::move(callback));
}
void SetLastUsedTimeForTest(base::Time time) override {
entry_->SetLastUsedTimeForTest(time);
}
private:
disk_cache::Entry* const entry_;
};
class FailableBackend : public disk_cache::Backend {
public:
enum class FailureStage { CREATE_ENTRY = 0, WRITE_HEADERS = 1 };
explicit FailableBackend(std::unique_ptr<disk_cache::Backend> backend,
FailureStage stage)
: Backend(backend->GetCacheType()),
backend_(std::move(backend)),
stage_(stage) {}
// disk_cache::Backend overrides
int32_t GetEntryCount() const override { return backend_->GetEntryCount(); }
EntryResult OpenOrCreateEntry(const std::string& key,
net::RequestPriority request_priority,
EntryResultCallback callback) override {
if (stage_ == FailureStage::CREATE_ENTRY) {
return EntryResult::MakeError(net::ERR_FILE_NO_SPACE);
} else if (stage_ == FailureStage::WRITE_HEADERS) {
return backend_->OpenOrCreateEntry(
key, request_priority,
base::BindOnce(
[](EntryResultCallback callback, disk_cache::EntryResult result) {
FailableCacheEntry failable_entry(result.ReleaseEntry());
EntryResult failable_result =
EntryResult::MakeCreated(&failable_entry);
std::move(callback).Run(std::move(failable_result));
},
std::move(callback)));
} else {
return backend_->OpenOrCreateEntry(key, request_priority,
std::move(callback));
}
}
EntryResult OpenEntry(const std::string& key,
net::RequestPriority request_priority,
EntryResultCallback callback) override {
return backend_->OpenEntry(key, request_priority, std::move(callback));
}
EntryResult CreateEntry(const std::string& key,
net::RequestPriority request_priority,
EntryResultCallback callback) override {
return backend_->CreateEntry(key, request_priority, std::move(callback));
}
net::Error DoomEntry(const std::string& key,
net::RequestPriority request_priority,
CompletionOnceCallback callback) override {
return backend_->DoomEntry(key, request_priority, std::move(callback));
}
net::Error DoomAllEntries(CompletionOnceCallback callback) override {
return backend_->DoomAllEntries(std::move(callback));
}
net::Error DoomEntriesBetween(base::Time initial_time,
base::Time end_time,
CompletionOnceCallback callback) override {
return backend_->DoomEntriesBetween(initial_time, end_time,
std::move(callback));
}
net::Error DoomEntriesSince(base::Time initial_time,
CompletionOnceCallback callback) override {
return backend_->DoomEntriesSince(initial_time, std::move(callback));
}
int64_t CalculateSizeOfAllEntries(
Int64CompletionOnceCallback callback) override {
return backend_->CalculateSizeOfAllEntries(std::move(callback));
}
std::unique_ptr<Iterator> CreateIterator() override {
return backend_->CreateIterator();
}
void GetStats(base::StringPairs* stats) override {
return backend_->GetStats(stats);
}
void OnExternalCacheHit(const std::string& key) override {
return backend_->OnExternalCacheHit(key);
}
size_t DumpMemoryStats(
base::trace_event::ProcessMemoryDump* pmd,
const std::string& parent_absolute_name) const override {
NOTREACHED();
return 0u;
}
int64_t MaxFileSize() const override { return backend_->MaxFileSize(); }
private:
std::unique_ptr<disk_cache::Backend> backend_;
FailureStage stage_;
};
std::string CopySideData(blink::mojom::Blob* actual_blob) {
std::string output;
base::RunLoop loop;
......@@ -351,6 +504,13 @@ class TestCacheStorageCache : public LegacyCacheStorageCache {
return delayable_backend;
}
void UseFailableBackend(FailableBackend::FailureStage stage) {
EXPECT_TRUE(backend_);
auto failable_backend =
std::make_unique<FailableBackend>(std::move(backend_), stage);
backend_ = std::move(failable_backend);
}
void Init() { InitBackend(); }
base::CheckedNumeric<uint64_t> GetRequiredSafeSpaceForRequest(
......@@ -2597,6 +2757,73 @@ TEST_P(CacheStorageCacheTestP, SelfRefsDuringPut) {
EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
}
TEST_P(CacheStorageCacheTestP, PutFailCreateEntry) {
// Open the backend.
EXPECT_TRUE(Keys());
std::unique_ptr<base::RunLoop> run_loop;
cache_->UseFailableBackend(FailableBackend::FailureStage::CREATE_ENTRY);
cache_->Put(
BackgroundFetchSettledFetch::CloneRequest(body_request_),
CreateBlobBodyResponse(), /* trace_id = */ 0,
base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
base::Unretained(this), base::Unretained(run_loop.get())));
// Blocks on opening the cache entry.
base::RunLoop().RunUntilIdle();
// The operation should fail.
EXPECT_EQ(CacheStorageError::kErrorExists, callback_error_);
// QuotaManager should have been notified of write failures.
ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
EXPECT_EQ(1,
/*error_count*/ mock_quota_manager_->write_error_tracker()
.begin()
->second);
EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
EXPECT_EQ(2,
/*error_count*/ mock_quota_manager_->write_error_tracker()
.begin()
->second);
}
TEST_P(CacheStorageCacheTestP, PutFailWriteHeaders) {
// Only interested in quota being notified for disk write errors
// as opposed to errors from a memory only scenario.
if (MemoryOnly()) {
return;
}
// Open the backend.
EXPECT_TRUE(Keys());
std::unique_ptr<base::RunLoop> run_loop;
cache_->UseFailableBackend(FailableBackend::FailureStage::WRITE_HEADERS);
EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
// Blocks on opening the cache entry.
base::RunLoop().RunUntilIdle();
// The operation should fail.
EXPECT_EQ(CacheStorageError::kErrorStorage, callback_error_);
// QuotaManager should have been notified of write failures.
ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
EXPECT_EQ(1,
/*error_count*/ mock_quota_manager_->write_error_tracker()
.begin()
->second);
EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
EXPECT_EQ(2,
/*error_count*/ mock_quota_manager_->write_error_tracker()
.begin()
->second);
}
INSTANTIATE_TEST_SUITE_P(CacheStorageCacheTest,
CacheStorageCacheTestP,
::testing::Values(false, true));
......
......@@ -22,6 +22,7 @@
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/sequenced_task_runner.h"
......@@ -94,14 +95,14 @@ class LegacyCacheStorage::CacheLoader {
CacheLoader(base::SequencedTaskRunner* cache_task_runner,
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
storage::QuotaManagerProxy* quota_manager_proxy,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
LegacyCacheStorage* cache_storage,
const url::Origin& origin,
CacheStorageOwner owner)
: cache_task_runner_(cache_task_runner),
scheduler_task_runner_(std::move(scheduler_task_runner)),
quota_manager_proxy_(quota_manager_proxy),
quota_manager_proxy_(std::move(quota_manager_proxy)),
blob_storage_context_(std::move(blob_storage_context)),
cache_storage_(cache_storage),
origin_(origin),
......@@ -147,8 +148,9 @@ class LegacyCacheStorage::CacheLoader {
const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_;
// Owned by CacheStorage which owns this.
storage::QuotaManagerProxy* quota_manager_proxy_;
// Owned by CacheStorage which owns this. This is guaranteed to outlive
// CacheLoader, but we store a reference to keep it alive for callbacks.
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
......@@ -168,14 +170,14 @@ class LegacyCacheStorage::MemoryLoader
public:
MemoryLoader(base::SequencedTaskRunner* cache_task_runner,
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
storage::QuotaManagerProxy* quota_manager_proxy,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
LegacyCacheStorage* cache_storage,
const url::Origin& origin,
CacheStorageOwner owner)
: CacheLoader(cache_task_runner,
std::move(scheduler_task_runner),
quota_manager_proxy,
std::move(quota_manager_proxy),
std::move(blob_storage_context),
cache_storage,
origin,
......@@ -240,14 +242,14 @@ class LegacyCacheStorage::SimpleCacheLoader
const base::FilePath& origin_path,
base::SequencedTaskRunner* cache_task_runner,
scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
storage::QuotaManagerProxy* quota_manager_proxy,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
LegacyCacheStorage* cache_storage,
const url::Origin& origin,
CacheStorageOwner owner)
: CacheLoader(cache_task_runner,
std::move(scheduler_task_runner),
quota_manager_proxy,
std::move(quota_manager_proxy),
std::move(blob_storage_context),
cache_storage,
origin,
......@@ -369,16 +371,21 @@ class LegacyCacheStorage::SimpleCacheLoader
PostTaskAndReplyWithResult(
cache_task_runner_.get(), FROM_HERE,
base::BindOnce(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
tmp_path, index_path, serialized),
tmp_path, index_path, serialized, quota_manager_proxy_,
origin_),
std::move(callback));
}
static bool WriteIndexWriteToFileInPool(const base::FilePath& tmp_path,
const base::FilePath& index_path,
const std::string& data) {
static bool WriteIndexWriteToFileInPool(
const base::FilePath& tmp_path,
const base::FilePath& index_path,
const std::string& data,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
const url::Origin& origin) {
int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
if (bytes_written != base::checked_cast<int>(data.size())) {
base::DeleteFile(tmp_path, /* recursive */ false);
quota_manager_proxy->NotifyWriteFailed(origin);
return false;
}
......@@ -392,7 +399,7 @@ class LegacyCacheStorage::SimpleCacheLoader
PostTaskAndReplyWithResult(
cache_task_runner_.get(), FROM_HERE,
base::BindOnce(&SimpleCacheLoader::ReadAndMigrateIndexInPool,
origin_path_),
origin_path_, quota_manager_proxy_, origin_),
base::BindOnce(&SimpleCacheLoader::LoadIndexDidReadIndex,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
......@@ -476,7 +483,9 @@ class LegacyCacheStorage::SimpleCacheLoader
// Runs on cache_task_runner_
static proto::CacheStorageIndex ReadAndMigrateIndexInPool(
const base::FilePath& origin_path) {
const base::FilePath& origin_path,
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
const url::Origin& origin) {
const base::FilePath index_path =
origin_path.AppendASCII(LegacyCacheStorage::kIndexFileName);
......@@ -536,7 +545,9 @@ class LegacyCacheStorage::SimpleCacheLoader
if (index_modified) {
base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp");
if (!index.SerializeToString(&body) ||
!WriteIndexWriteToFileInPool(tmp_path, index_path, body)) {
!WriteIndexWriteToFileInPool(tmp_path, index_path, body,
std::move(quota_manager_proxy),
origin)) {
return proto::CacheStorageIndex();
}
}
......@@ -578,13 +589,13 @@ LegacyCacheStorage::LegacyCacheStorage(
if (memory_only) {
cache_loader_.reset(new MemoryLoader(
cache_task_runner_.get(), std::move(scheduler_task_runner),
quota_manager_proxy.get(), blob_storage_context_, this, origin, owner));
quota_manager_proxy, blob_storage_context_, this, origin, owner));
return;
}
cache_loader_.reset(new SimpleCacheLoader(
origin_path_, cache_task_runner_.get(), std::move(scheduler_task_runner),
quota_manager_proxy.get(), blob_storage_context_, this, origin, owner));
quota_manager_proxy, blob_storage_context_, this, origin, owner));
#if defined(OS_ANDROID)
app_status_listener_ = base::android::ApplicationStatusListener::New(
......
......@@ -1686,6 +1686,7 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
base::UmaHistogramSparse("ServiceWorkerCache.DiskCacheCreateEntryResult",
std::abs(rv));
if (rv != net::OK) {
quota_manager_proxy_->NotifyWriteFailed(origin_);
PutComplete(std::move(put_context), CacheStorageError::kErrorExists);
return;
}
......@@ -1767,6 +1768,7 @@ void LegacyCacheStorageCache::PutDidWriteHeaders(
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
if (rv != expected_bytes) {
quota_manager_proxy_->NotifyWriteFailed(origin_);
PutComplete(
std::move(put_context),
MakeErrorStorage(ErrorStorageType::kPutDidWriteHeadersWrongBytes));
......@@ -1849,7 +1851,8 @@ void LegacyCacheStorageCache::PutWriteBlobToCache(
// We have real data, so stream it into the entry. This will overwrite
// any existing data.
auto blob_to_cache = std::make_unique<CacheStorageBlobToDiskCache>();
auto blob_to_cache = std::make_unique<CacheStorageBlobToDiskCache>(
quota_manager_proxy_, origin_);
CacheStorageBlobToDiskCache* blob_to_cache_raw = blob_to_cache.get();
BlobToDiskCacheIDMap::KeyType blob_to_cache_key =
active_blob_to_disk_cache_writers_.Add(std::move(blob_to_cache));
......
......@@ -181,10 +181,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManager
int64_t delta);
// Called by clients via proxy.
// This method is declared as virtual to allow test code to override it.
//
// Client storage must call this method whenever they run into disk
// write errors. Used as a hint to determine if the storage partition is out
// of space, and trigger actions if deemed appropriate.
void NotifyWriteFailed(const url::Origin& origin);
virtual void NotifyWriteFailed(const url::Origin& origin);
// Used to avoid evicting origins with open pages.
// A call to NotifyOriginInUse must be balanced by a later call
......
......@@ -111,6 +111,12 @@ void MockQuotaManager::DeleteOriginData(const url::Origin& origin,
blink::mojom::QuotaStatusCode::kOk));
}
void MockQuotaManager::NotifyWriteFailed(const url::Origin& origin) {
auto origin_error_log =
write_error_tracker_.insert(std::pair<url::Origin, int>(origin, 0)).first;
++origin_error_log->second;
}
MockQuotaManager::~MockQuotaManager() = default;
void MockQuotaManager::UpdateUsage(const url::Origin& origin,
......
......@@ -73,6 +73,10 @@ class MockQuotaManager : public QuotaManager {
int quota_client_mask,
StatusCallback callback) override;
// Overrides QuotaManager's implementation so that tests can observe
// calls to this function.
void NotifyWriteFailed(const url::Origin& origin) override;
// Helper method for updating internal quota info.
void SetQuota(const url::Origin& origin, StorageType type, int64_t quota);
......@@ -94,6 +98,10 @@ class MockQuotaManager : public QuotaManager {
StorageType type,
QuotaClient::ID quota_client) const;
std::map<const url::Origin, int> write_error_tracker() const {
return write_error_tracker_;
}
protected:
~MockQuotaManager() override;
......@@ -140,6 +148,10 @@ class MockQuotaManager : public QuotaManager {
std::vector<OriginInfo> origins_;
std::map<std::pair<url::Origin, StorageType>, StorageInfo>
usage_and_quota_map_;
// Tracks number of times NotifyFailedWrite has been called per origin.
std::map<const url::Origin, int> write_error_tracker_;
base::WeakPtrFactory<MockQuotaManager> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(MockQuotaManager);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment