Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1130)

Unified Diff: content/browser/dom_storage/local_storage_context_mojo.cc

Issue 2604273002: Migrate data from old localstorage format to new format. (Closed)
Patch Set: nit Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/dom_storage/local_storage_context_mojo.cc
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc
index c2317b97e12e3fe3685d38291ff46f2cb158c0ea..fb04ead586624912c3a70e38b7098b08ac9e119e 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -8,6 +8,9 @@
#include "base/strings/string_number_conversions.h"
#include "components/leveldb/public/cpp/util.h"
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/browser/dom_storage/local_storage_database.pb.h"
#include "content/browser/leveldb_wrapper_impl.h"
#include "content/common/dom_storage/dom_storage_types.h"
@@ -15,6 +18,7 @@
#include "services/file/public/interfaces/constants.mojom.h"
#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/connector.h"
+#include "sql/connection.h"
namespace content {
@@ -51,13 +55,157 @@ std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) {
void NoOpSuccess(bool success) {}
+std::vector<uint8_t> String16ToUint8Vector(const base::string16& input) {
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data());
+ return std::vector<uint8_t>(data, data + input.size() * sizeof(base::char16));
+}
+
+void MigrateStorageHelper(
+ base::FilePath db_path,
+ const scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
+ base::Callback<void(std::unique_ptr<LevelDBWrapperImpl::ValueMap>)>
+ callback) {
+ DOMStorageDatabase db(db_path);
+ DOMStorageValuesMap map;
+ db.ReadAllValues(&map);
+ auto values = base::MakeUnique<LevelDBWrapperImpl::ValueMap>();
+ for (const auto& it : map) {
+ (*values)[String16ToUint8Vector(it.first)] =
+ String16ToUint8Vector(it.second.string());
+ }
+ reply_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, base::Passed(&values)));
+}
+
+// Helper to convert from OnceCallback to Callback.
+void CallMigrationCalback(LevelDBWrapperImpl::ValueMapCallback callback,
+ std::unique_ptr<LevelDBWrapperImpl::ValueMap> data) {
+ std::move(callback).Run(std::move(data));
+}
+
} // namespace
+class LocalStorageContextMojo::LevelDBWrapperHolder
+ : public LevelDBWrapperImpl::Delegate {
+ public:
+ LevelDBWrapperHolder(LocalStorageContextMojo* context,
+ const url::Origin& origin)
+ : context_(context), origin_(origin) {
+ // Delay for a moment after a value is set in anticipation
+ // of other values being set, so changes are batched.
+ const int kCommitDefaultDelaySecs = 5;
+
+ // To avoid excessive IO we apply limits to the amount of data being written
+ // and the frequency of writes.
+ const int kMaxBytesPerHour = kPerStorageAreaQuota;
+ const int kMaxCommitsPerHour = 60;
+
+ level_db_wrapper_ = base::MakeUnique<LevelDBWrapperImpl>(
+ context_->database_.get(),
+ kDataPrefix + origin_.Serialize() + kOriginSeparator,
+ kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+ base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour,
+ kMaxCommitsPerHour, this);
+ level_db_wrapper_ptr_ = level_db_wrapper_.get();
+ }
+
+ LevelDBWrapperImpl* level_db_wrapper() { return level_db_wrapper_ptr_; }
+
+ void OnNoBindings() override {
+ // Will delete |this|.
+ DCHECK(context_->level_db_wrappers_.find(origin_) !=
+ context_->level_db_wrappers_.end());
+ context_->level_db_wrappers_.erase(origin_);
+ }
+
+ std::vector<leveldb::mojom::BatchedOperationPtr> PrepareToCommit() override {
+ std::vector<leveldb::mojom::BatchedOperationPtr> operations;
+
+ // Write schema version if not already done so before.
+ if (!context_->database_initialized_) {
+ leveldb::mojom::BatchedOperationPtr item =
+ leveldb::mojom::BatchedOperation::New();
+ item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
+ item->key = leveldb::StdStringToUint8Vector(kVersionKey);
+ item->value = leveldb::StdStringToUint8Vector(
+ base::Int64ToString(kCurrentSchemaVersion));
+ operations.push_back(std::move(item));
+ context_->database_initialized_ = true;
+ }
+
+ leveldb::mojom::BatchedOperationPtr item =
+ leveldb::mojom::BatchedOperation::New();
+ item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
+ item->key = CreateMetaDataKey(origin_);
+ if (level_db_wrapper()->empty()) {
+ item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
+ } else {
+ item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
+ LocalStorageOriginMetaData data;
+ data.set_last_modified(base::Time::Now().ToInternalValue());
+ data.set_size_bytes(level_db_wrapper()->bytes_used());
+ item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString());
+ }
+ operations.push_back(std::move(item));
+
+ return operations;
+ }
+
+ void DidCommit(leveldb::mojom::DatabaseError error) override {
+ // Delete any old database that might still exist if we successfully wrote
+ // data to LevelDB, and our LevelDB is actually disk backed.
+ if (error == leveldb::mojom::DatabaseError::OK && !deleted_old_data_ &&
+ !context_->subdirectory_.empty() && context_->task_runner_ &&
+ !context_->old_localstorage_path_.empty()) {
+ deleted_old_data_ = true;
+ context_->task_runner_->PostShutdownBlockingTask(
+ FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+ base::Bind(base::IgnoreResult(&sql::Connection::Delete),
+ sql_db_path()));
+ }
+ }
+
+ void MigrateData(LevelDBWrapperImpl::ValueMapCallback callback) override {
+ if (context_->task_runner_ && !context_->old_localstorage_path_.empty()) {
+ context_->task_runner_->PostShutdownBlockingTask(
+ FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+ base::Bind(
+ &MigrateStorageHelper, sql_db_path(),
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&CallMigrationCalback, base::Passed(&callback))));
+ return;
+ }
+ std::move(callback).Run(nullptr);
+ }
+
+ private:
+ base::FilePath sql_db_path() const {
+ if (context_->old_localstorage_path_.empty())
+ return base::FilePath();
+ return context_->old_localstorage_path_.Append(
+ DOMStorageArea::DatabaseFileNameFromOrigin(origin_.GetURL()));
+ }
+
+ LocalStorageContextMojo* context_;
+ url::Origin origin_;
+ std::unique_ptr<LevelDBWrapperImpl> level_db_wrapper_;
+ // Holds the same value as |level_db_wrapper_|. The reason for this is that
+ // during destruction of the LevelDBWrapperImpl instance we might still get
+ // called and need access to the LevelDBWrapperImpl instance. The unique_ptr
+ // could already be null, but this field should still be valid.
+ LevelDBWrapperImpl* level_db_wrapper_ptr_;
+ bool deleted_old_data_ = false;
+};
+
LocalStorageContextMojo::LocalStorageContextMojo(
service_manager::Connector* connector,
+ scoped_refptr<DOMStorageTaskRunner> task_runner,
+ const base::FilePath& old_localstorage_path,
const base::FilePath& subdirectory)
: connector_(connector),
subdirectory_(subdirectory),
+ task_runner_(std::move(task_runner)),
+ old_localstorage_path_(old_localstorage_path),
weak_ptr_factory_(this) {}
LocalStorageContextMojo::~LocalStorageContextMojo() {}
@@ -100,7 +248,7 @@ void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin(
void LocalStorageContextMojo::Flush() {
for (const auto& it : level_db_wrappers_)
- it.second->ScheduleImmediateCommit();
+ it.second->level_db_wrapper()->ScheduleImmediateCommit();
}
leveldb::mojom::LevelDBDatabaseAssociatedRequest
@@ -138,51 +286,6 @@ void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) {
std::move(callback).Run();
}
-void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings(
- const url::Origin& origin) {
- DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end());
- level_db_wrappers_.erase(origin);
-}
-
-std::vector<leveldb::mojom::BatchedOperationPtr>
-LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit(
- const url::Origin& origin,
- const LevelDBWrapperImpl& wrapper) {
- // |wrapper| might not exist in |level_db_wrappers_| anymore at this point, as
- // it is possible this commit was triggered by destruction.
-
- std::vector<leveldb::mojom::BatchedOperationPtr> operations;
-
- // Write schema version if not already done so before.
- if (!database_initialized_) {
- leveldb::mojom::BatchedOperationPtr item =
- leveldb::mojom::BatchedOperation::New();
- item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
- item->key = leveldb::StdStringToUint8Vector(kVersionKey);
- item->value = leveldb::StdStringToUint8Vector(
- base::Int64ToString(kCurrentSchemaVersion));
- operations.push_back(std::move(item));
- database_initialized_ = true;
- }
-
- leveldb::mojom::BatchedOperationPtr item =
- leveldb::mojom::BatchedOperation::New();
- item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
- item->key = CreateMetaDataKey(origin);
- if (wrapper.bytes_used() == 0) {
- item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
- } else {
- item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
- LocalStorageOriginMetaData data;
- data.set_last_modified(base::Time::Now().ToInternalValue());
- data.set_size_bytes(wrapper.bytes_used());
- item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString());
- }
- operations.push_back(std::move(item));
-
- return operations;
-}
-
void LocalStorageContextMojo::OnUserServiceConnectionComplete() {
CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED,
file_service_connection_->GetResult());
@@ -365,28 +468,11 @@ LevelDBWrapperImpl* LocalStorageContextMojo::GetOrCreateDBWrapper(
DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
auto found = level_db_wrappers_.find(origin);
if (found != level_db_wrappers_.end())
- return found->second.get();
-
- // Delay for a moment after a value is set in anticipation
- // of other values being set, so changes are batched.
- const int kCommitDefaultDelaySecs = 5;
-
- // To avoid excessive IO we apply limits to the amount of data being written
- // and the frequency of writes.
- const int kMaxBytesPerHour = kPerStorageAreaQuota;
- const int kMaxCommitsPerHour = 60;
-
- auto wrapper = base::MakeUnique<LevelDBWrapperImpl>(
- database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator,
- kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
- base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour,
- kMaxCommitsPerHour,
- base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings,
- base::Unretained(this), origin),
- base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit,
- base::Unretained(this), origin));
- LevelDBWrapperImpl* wrapper_ptr = wrapper.get();
- level_db_wrappers_[origin] = std::move(wrapper);
+ return found->second->level_db_wrapper();
+
+ auto holder = base::MakeUnique<LevelDBWrapperHolder>(this, origin);
+ LevelDBWrapperImpl* wrapper_ptr = holder->level_db_wrapper();
+ level_db_wrappers_[origin] = std::move(holder);
return wrapper_ptr;
}

Powered by Google App Engine
This is Rietveld 408576698