Commit 951d071c authored by Adrienne Walker's avatar Adrienne Walker Committed by Commit Bot

indexeddb: add blob write failure reason to message

This is a little bit awkward for native file system handles, which
aren't related to blob writing failures.  However, these are already
returned as "failure to write blobs", so it's not too far afield.

Bug: 1144131
Change-Id: I800445b39a93e7fda9d36480092d2cff55760f94
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2538155
Commit-Queue: enne <enne@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Auto-Submit: enne <enne@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827874}
parent 7d7dc643
...@@ -3289,7 +3289,8 @@ Status IndexedDBBackingStore::Transaction::CommitPhaseOne( ...@@ -3289,7 +3289,8 @@ Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
return WriteNewBlobs(std::move(callback)); return WriteNewBlobs(std::move(callback));
} else { } else {
return std::move(callback).Run( return std::move(callback).Run(
BlobWriteResult::kRunPhaseTwoAndReturnResult); BlobWriteResult::kRunPhaseTwoAndReturnResult,
storage::mojom::WriteBlobToFileResult::kSuccess);
} }
} }
...@@ -3455,7 +3456,8 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs( ...@@ -3455,7 +3456,8 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
} }
if (num_objects_to_write == 0) { if (num_objects_to_write == 0) {
return std::move(callback).Run( return std::move(callback).Run(
BlobWriteResult::kRunPhaseTwoAndReturnResult); BlobWriteResult::kRunPhaseTwoAndReturnResult,
storage::mojom::WriteBlobToFileResult::kSuccess);
} }
write_state_.emplace(num_objects_to_write, std::move(callback)); write_state_.emplace(num_objects_to_write, std::move(callback));
...@@ -3464,7 +3466,8 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs( ...@@ -3464,7 +3466,8 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
backing_store_->blob_storage_context_; backing_store_->blob_storage_context_;
auto write_result_callback = base::BindRepeating( auto write_result_callback = base::BindRepeating(
[](base::WeakPtr<Transaction> transaction, bool success) { [](base::WeakPtr<Transaction> transaction,
storage::mojom::WriteBlobToFileResult result) {
if (!transaction) if (!transaction)
return; return;
// This can be null if Rollback() is called. // This can be null if Rollback() is called.
...@@ -3472,28 +3475,22 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs( ...@@ -3472,28 +3475,22 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
return; return;
auto& write_state = transaction->write_state_.value(); auto& write_state = transaction->write_state_.value();
DCHECK(!write_state.on_complete.is_null()); DCHECK(!write_state.on_complete.is_null());
if (!success) { if (result != storage::mojom::WriteBlobToFileResult::kSuccess) {
auto on_complete = std::move(write_state.on_complete); auto on_complete = std::move(write_state.on_complete);
transaction->write_state_.reset(); transaction->write_state_.reset();
std::move(on_complete).Run(BlobWriteResult::kFailure); std::move(on_complete).Run(BlobWriteResult::kFailure, result);
return; return;
} }
--(write_state.calls_left); --(write_state.calls_left);
if (write_state.calls_left == 0) { if (write_state.calls_left == 0) {
auto on_complete = std::move(write_state.on_complete); auto on_complete = std::move(write_state.on_complete);
transaction->write_state_.reset(); transaction->write_state_.reset();
std::move(on_complete).Run(BlobWriteResult::kRunPhaseTwoAsync); std::move(on_complete)
.Run(BlobWriteResult::kRunPhaseTwoAsync, result);
} }
}, },
ptr_factory_.GetWeakPtr()); ptr_factory_.GetWeakPtr());
auto blob_write_result_callback = base::BindRepeating(
[](const base::RepeatingCallback<void(bool success)>& callback,
storage::mojom::WriteBlobToFileResult result) {
callback.Run(result == storage::mojom::WriteBlobToFileResult::kSuccess);
},
write_result_callback);
for (auto& iter : external_object_change_map_) { for (auto& iter : external_object_change_map_) {
for (auto& entry : iter.second->mutable_external_objects()) { for (auto& entry : iter.second->mutable_external_objects()) {
switch (entry.object_type()) { switch (entry.object_type()) {
...@@ -3526,7 +3523,7 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs( ...@@ -3526,7 +3523,7 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
backing_store_->GetBlobFileName(database_id_, backing_store_->GetBlobFileName(database_id_,
entry.blob_number()), entry.blob_number()),
IndexedDBBackingStore::ShouldSyncOnCommit(durability_), IndexedDBBackingStore::ShouldSyncOnCommit(durability_),
last_modified, blob_write_result_callback); last_modified, write_result_callback);
break; break;
} }
case IndexedDBExternalObject::ObjectType::kNativeFileSystemHandle: { case IndexedDBExternalObject::ObjectType::kNativeFileSystemHandle: {
...@@ -3545,18 +3542,21 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs( ...@@ -3545,18 +3542,21 @@ leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
base::BindOnce( base::BindOnce(
[](base::WeakPtr<Transaction> transaction, [](base::WeakPtr<Transaction> transaction,
IndexedDBExternalObject* object, IndexedDBExternalObject* object,
base::OnceCallback<void(bool success)> callback, base::OnceCallback<void(
storage::mojom::WriteBlobToFileResult)> callback,
const std::vector<uint8_t>& serialized_token) { const std::vector<uint8_t>& serialized_token) {
// |object| is owned by |transaction|, so make sure // |object| is owned by |transaction|, so make sure
// |transaction| is still valid before doing anything else. // |transaction| is still valid before doing anything else.
if (!transaction) if (!transaction)
return; return;
if (serialized_token.empty()) { if (serialized_token.empty()) {
std::move(callback).Run(/*success=*/false); std::move(callback).Run(
storage::mojom::WriteBlobToFileResult::kError);
return; return;
} }
object->set_native_file_system_token(serialized_token); object->set_native_file_system_token(serialized_token);
std::move(callback).Run(/*success=*/true); std::move(callback).Run(
storage::mojom::WriteBlobToFileResult::kSuccess);
}, },
ptr_factory_.GetWeakPtr(), &entry, write_result_callback)); ptr_factory_.GetWeakPtr(), &entry, write_result_callback));
break; break;
......
...@@ -770,13 +770,15 @@ BlobWriteCallback CreateBlobWriteCallback( ...@@ -770,13 +770,15 @@ BlobWriteCallback CreateBlobWriteCallback(
base::OnceClosure on_done = base::OnceClosure()) { base::OnceClosure on_done = base::OnceClosure()) {
*succeeded = false; *succeeded = false;
return base::BindOnce( return base::BindOnce(
[](bool* succeeded, base::OnceClosure on_done, BlobWriteResult result) { [](bool* succeeded, base::OnceClosure on_done, BlobWriteResult result,
storage::mojom::WriteBlobToFileResult error) {
switch (result) { switch (result) {
case BlobWriteResult::kFailure: case BlobWriteResult::kFailure:
NOTREACHED(); NOTREACHED();
break; break;
case BlobWriteResult::kRunPhaseTwoAsync: case BlobWriteResult::kRunPhaseTwoAsync:
case BlobWriteResult::kRunPhaseTwoAndReturnResult: case BlobWriteResult::kRunPhaseTwoAndReturnResult:
DCHECK_EQ(error, storage::mojom::WriteBlobToFileResult::kSuccess);
*succeeded = true; *succeeded = true;
break; break;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "content/browser/indexed_db/indexed_db_external_object.h" #include "content/browser/indexed_db/indexed_db_external_object.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h" #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "storage/common/file_system/file_system_mount_option.h" #include "storage/common/file_system/file_system_mount_option.h"
...@@ -40,8 +41,11 @@ enum class BlobWriteResult { ...@@ -40,8 +41,11 @@ enum class BlobWriteResult {
// BlobWriteResult signifies if the operation succeeded or not, and the returned // BlobWriteResult signifies if the operation succeeded or not, and the returned
// status is used to handle errors in the next part of the transcation commit // status is used to handle errors in the next part of the transcation commit
// lifecycle. Note: The returned status can only be used when the result is // lifecycle. Note: The returned status can only be used when the result is
// |kRunPhaseTwoAndReturnResult|. // |kRunPhaseTwoAndReturnResult|. The WriteBlobToFileResult is a more granular
using BlobWriteCallback = base::OnceCallback<leveldb::Status(BlobWriteResult)>; // error in the case something goes wrong.
using BlobWriteCallback =
base::OnceCallback<leveldb::Status(BlobWriteResult,
storage::mojom::WriteBlobToFileResult)>;
// This object represents a change in the database involving adding or removing // This object represents a change in the database involving adding or removing
// external objects. if external_objects() is empty, then objects are to be // external objects. if external_objects() is empty, then objects are to be
......
...@@ -193,7 +193,9 @@ void IndexedDBFakeBackingStore::FakeTransaction::Begin( ...@@ -193,7 +193,9 @@ void IndexedDBFakeBackingStore::FakeTransaction::Begin(
std::vector<ScopeLock> locks) {} std::vector<ScopeLock> locks) {}
leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseOne( leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseOne(
BlobWriteCallback callback) { BlobWriteCallback callback) {
return std::move(callback).Run(BlobWriteResult::kRunPhaseTwoAndReturnResult); return std::move(callback).Run(
BlobWriteResult::kRunPhaseTwoAndReturnResult,
storage::mojom::WriteBlobToFileResult::kSuccess);
} }
leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseTwo() { leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseTwo() {
return result_; return result_;
......
...@@ -28,6 +28,26 @@ namespace content { ...@@ -28,6 +28,26 @@ namespace content {
namespace { namespace {
std::string WriteBlobToFileResultToString(
storage::mojom::WriteBlobToFileResult result) {
switch (result) {
case storage::mojom::WriteBlobToFileResult::kError:
return "Error";
case storage::mojom::WriteBlobToFileResult::kBadPath:
return "BadPath";
case storage::mojom::WriteBlobToFileResult::kInvalidBlob:
return "InvalidBlob";
case storage::mojom::WriteBlobToFileResult::kIOError:
return "IOError";
case storage::mojom::WriteBlobToFileResult::kTimestampError:
return "TimestampError";
case storage::mojom::WriteBlobToFileResult::kSuccess:
return "Success";
}
NOTREACHED();
return "";
}
const int64_t kInactivityTimeoutPeriodSeconds = 60; const int64_t kInactivityTimeoutPeriodSeconds = 60;
// Used for UMA metrics - do not change values. // Used for UMA metrics - do not change values.
...@@ -266,7 +286,8 @@ void IndexedDBTransaction::EnsureBackingStoreTransactionBegun() { ...@@ -266,7 +286,8 @@ void IndexedDBTransaction::EnsureBackingStoreTransactionBegun() {
} }
leveldb::Status IndexedDBTransaction::BlobWriteComplete( leveldb::Status IndexedDBTransaction::BlobWriteComplete(
BlobWriteResult result) { BlobWriteResult result,
storage::mojom::WriteBlobToFileResult error) {
IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
if (state_ == FINISHED) // aborted if (state_ == FINISHED) // aborted
return leveldb::Status::OK(); return leveldb::Status::OK();
...@@ -275,7 +296,10 @@ leveldb::Status IndexedDBTransaction::BlobWriteComplete( ...@@ -275,7 +296,10 @@ leveldb::Status IndexedDBTransaction::BlobWriteComplete(
switch (result) { switch (result) {
case BlobWriteResult::kFailure: { case BlobWriteResult::kFailure: {
leveldb::Status status = Abort(IndexedDBDatabaseError( leveldb::Status status = Abort(IndexedDBDatabaseError(
blink::mojom::IDBException::kDataError, "Failed to write blobs.")); blink::mojom::IDBException::kDataError,
base::ASCIIToUTF16(base::StringPrintf(
"Failed to write blobs (%s)",
WriteBlobToFileResultToString(error).c_str()))));
if (!status.ok()) if (!status.ok())
tear_down_callback_.Run(status); tear_down_callback_.Run(status);
// The result is ignored. // The result is ignored.
...@@ -338,10 +362,11 @@ leveldb::Status IndexedDBTransaction::Commit() { ...@@ -338,10 +362,11 @@ leveldb::Status IndexedDBTransaction::Commit() {
// to write. // to write.
s = transaction_->CommitPhaseOne(base::BindOnce( s = transaction_->CommitPhaseOne(base::BindOnce(
[](base::WeakPtr<IndexedDBTransaction> transaction, [](base::WeakPtr<IndexedDBTransaction> transaction,
BlobWriteResult result) { BlobWriteResult result,
storage::mojom::WriteBlobToFileResult error) {
if (!transaction) if (!transaction)
return leveldb::Status::OK(); return leveldb::Status::OK();
return transaction->BlobWriteComplete(result); return transaction->BlobWriteComplete(result, error);
}, },
ptr_factory_.GetWeakPtr())); ptr_factory_.GetWeakPtr()));
} }
......
...@@ -211,7 +211,9 @@ class CONTENT_EXPORT IndexedDBTransaction { ...@@ -211,7 +211,9 @@ class CONTENT_EXPORT IndexedDBTransaction {
bool IsTaskQueueEmpty() const; bool IsTaskQueueEmpty() const;
bool HasPendingTasks() const; bool HasPendingTasks() const;
leveldb::Status BlobWriteComplete(BlobWriteResult result); leveldb::Status BlobWriteComplete(
BlobWriteResult result,
storage::mojom::WriteBlobToFileResult error);
void CloseOpenCursorBindings(); void CloseOpenCursorBindings();
void CloseOpenCursors(); void CloseOpenCursors();
leveldb::Status CommitPhaseTwo(); leveldb::Status CommitPhaseTwo();
......
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