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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/dom_storage/local_storage_context_mojo.h" 5 #include "content/browser/dom_storage/local_storage_context_mojo.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
9 #include "components/leveldb/public/cpp/util.h" 9 #include "components/leveldb/public/cpp/util.h"
10 #include "components/leveldb/public/interfaces/leveldb.mojom.h" 10 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
11 #include "content/browser/dom_storage/dom_storage_area.h"
12 #include "content/browser/dom_storage/dom_storage_database.h"
13 #include "content/browser/dom_storage/dom_storage_task_runner.h"
11 #include "content/browser/dom_storage/local_storage_database.pb.h" 14 #include "content/browser/dom_storage/local_storage_database.pb.h"
12 #include "content/browser/leveldb_wrapper_impl.h" 15 #include "content/browser/leveldb_wrapper_impl.h"
13 #include "content/common/dom_storage/dom_storage_types.h" 16 #include "content/common/dom_storage/dom_storage_types.h"
14 #include "content/public/browser/local_storage_usage_info.h" 17 #include "content/public/browser/local_storage_usage_info.h"
15 #include "services/file/public/interfaces/constants.mojom.h" 18 #include "services/file/public/interfaces/constants.mojom.h"
16 #include "services/service_manager/public/cpp/connection.h" 19 #include "services/service_manager/public/cpp/connection.h"
17 #include "services/service_manager/public/cpp/connector.h" 20 #include "services/service_manager/public/cpp/connector.h"
21 #include "sql/connection.h"
18 22
19 namespace content { 23 namespace content {
20 24
21 // LevelDB database schema 25 // LevelDB database schema
22 // ======================= 26 // =======================
23 // 27 //
24 // Version 1 (in sorted order): 28 // Version 1 (in sorted order):
25 // key: "VERSION" 29 // key: "VERSION"
26 // value: "1" 30 // value: "1"
27 // 31 //
(...skipping 16 matching lines...) Expand all
44 auto serialized_origin = leveldb::StdStringToUint8Vector(origin.Serialize()); 48 auto serialized_origin = leveldb::StdStringToUint8Vector(origin.Serialize());
45 std::vector<uint8_t> key; 49 std::vector<uint8_t> key;
46 key.reserve(arraysize(kMetaPrefix) + serialized_origin.size()); 50 key.reserve(arraysize(kMetaPrefix) + serialized_origin.size());
47 key.insert(key.end(), kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)); 51 key.insert(key.end(), kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix));
48 key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); 52 key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
49 return key; 53 return key;
50 } 54 }
51 55
52 void NoOpSuccess(bool success) {} 56 void NoOpSuccess(bool success) {}
53 57
58 std::vector<uint8_t> String16ToUint8Vector(const base::string16& input) {
59 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data());
60 return std::vector<uint8_t>(data, data + input.size() * sizeof(base::char16));
61 }
62
63 void MigrateStorageHelper(
64 base::FilePath db_path,
65 const scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
66 base::Callback<void(std::unique_ptr<LevelDBWrapperImpl::ValueMap>)>
67 callback) {
68 DOMStorageDatabase db(db_path);
69 DOMStorageValuesMap map;
70 db.ReadAllValues(&map);
71 auto values = base::MakeUnique<LevelDBWrapperImpl::ValueMap>();
72 for (const auto& it : map) {
73 (*values)[String16ToUint8Vector(it.first)] =
74 String16ToUint8Vector(it.second.string());
75 }
76 reply_task_runner->PostTask(FROM_HERE,
77 base::Bind(callback, base::Passed(&values)));
78 }
79
80 // Helper to convert from OnceCallback to Callback.
81 void CallMigrationCalback(LevelDBWrapperImpl::ValueMapCallback callback,
82 std::unique_ptr<LevelDBWrapperImpl::ValueMap> data) {
83 std::move(callback).Run(std::move(data));
84 }
85
54 } // namespace 86 } // namespace
55 87
88 class LocalStorageContextMojo::LevelDBWrapperHolder
89 : public LevelDBWrapperImpl::Delegate {
90 public:
91 LevelDBWrapperHolder(LocalStorageContextMojo* context,
92 const url::Origin& origin)
93 : context_(context), origin_(origin) {
94 // Delay for a moment after a value is set in anticipation
95 // of other values being set, so changes are batched.
96 const int kCommitDefaultDelaySecs = 5;
97
98 // To avoid excessive IO we apply limits to the amount of data being written
99 // and the frequency of writes.
100 const int kMaxBytesPerHour = kPerStorageAreaQuota;
101 const int kMaxCommitsPerHour = 60;
102
103 level_db_wrapper_ = base::MakeUnique<LevelDBWrapperImpl>(
104 context_->database_.get(),
105 kDataPrefix + origin_.Serialize() + kOriginSeparator,
106 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
107 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour,
108 kMaxCommitsPerHour, this);
109 level_db_wrapper_ptr_ = level_db_wrapper_.get();
110 }
111
112 LevelDBWrapperImpl* level_db_wrapper() { return level_db_wrapper_ptr_; }
113
114 void OnNoBindings() override {
115 // Will delete |this|.
116 DCHECK(context_->level_db_wrappers_.find(origin_) !=
117 context_->level_db_wrappers_.end());
118 context_->level_db_wrappers_.erase(origin_);
119 }
120
121 std::vector<leveldb::mojom::BatchedOperationPtr> PrepareToCommit() override {
122 std::vector<leveldb::mojom::BatchedOperationPtr> operations;
123
124 // Write schema version if not already done so before.
125 if (!context_->database_initialized_) {
126 leveldb::mojom::BatchedOperationPtr item =
127 leveldb::mojom::BatchedOperation::New();
128 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
129 item->key = leveldb::StdStringToUint8Vector(kVersionKey);
130 item->value = leveldb::StdStringToUint8Vector(
131 base::Int64ToString(kCurrentSchemaVersion));
132 operations.push_back(std::move(item));
133 context_->database_initialized_ = true;
134 }
135
136 leveldb::mojom::BatchedOperationPtr item =
137 leveldb::mojom::BatchedOperation::New();
138 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
139 item->key = CreateMetaDataKey(origin_);
140 if (level_db_wrapper()->empty()) {
141 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
142 } else {
143 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
144 LocalStorageOriginMetaData data;
145 data.set_last_modified(base::Time::Now().ToInternalValue());
146 data.set_size_bytes(level_db_wrapper()->bytes_used());
147 item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString());
148 }
149 operations.push_back(std::move(item));
150
151 return operations;
152 }
153
154 void DidCommit(leveldb::mojom::DatabaseError error) override {
155 // Delete any old database that might still exist if we successfully wrote
156 // data to LevelDB, and our LevelDB is actually disk backed.
157 if (error == leveldb::mojom::DatabaseError::OK && !deleted_old_data_ &&
158 !context_->subdirectory_.empty() && context_->task_runner_ &&
159 !context_->old_localstorage_path_.empty()) {
160 deleted_old_data_ = true;
161 context_->task_runner_->PostShutdownBlockingTask(
162 FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
163 base::Bind(base::IgnoreResult(&sql::Connection::Delete),
164 sql_db_path()));
165 }
166 }
167
168 void MigrateData(LevelDBWrapperImpl::ValueMapCallback callback) override {
169 if (context_->task_runner_ && !context_->old_localstorage_path_.empty()) {
170 context_->task_runner_->PostShutdownBlockingTask(
171 FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
172 base::Bind(
173 &MigrateStorageHelper, sql_db_path(),
174 base::ThreadTaskRunnerHandle::Get(),
175 base::Bind(&CallMigrationCalback, base::Passed(&callback))));
176 return;
177 }
178 std::move(callback).Run(nullptr);
179 }
180
181 private:
182 base::FilePath sql_db_path() const {
183 if (context_->old_localstorage_path_.empty())
184 return base::FilePath();
185 return context_->old_localstorage_path_.Append(
186 DOMStorageArea::DatabaseFileNameFromOrigin(origin_.GetURL()));
187 }
188
189 LocalStorageContextMojo* context_;
190 url::Origin origin_;
191 std::unique_ptr<LevelDBWrapperImpl> level_db_wrapper_;
192 // Holds the same value as |level_db_wrapper_|. The reason for this is that
193 // during destruction of the LevelDBWrapperImpl instance we might still get
194 // called and need access to the LevelDBWrapperImpl instance. The unique_ptr
195 // could already be null, but this field should still be valid.
196 LevelDBWrapperImpl* level_db_wrapper_ptr_;
197 bool deleted_old_data_ = false;
198 };
199
56 LocalStorageContextMojo::LocalStorageContextMojo( 200 LocalStorageContextMojo::LocalStorageContextMojo(
57 service_manager::Connector* connector, 201 service_manager::Connector* connector,
202 scoped_refptr<DOMStorageTaskRunner> task_runner,
203 const base::FilePath& old_localstorage_path,
58 const base::FilePath& subdirectory) 204 const base::FilePath& subdirectory)
59 : connector_(connector), 205 : connector_(connector),
60 subdirectory_(subdirectory), 206 subdirectory_(subdirectory),
207 task_runner_(std::move(task_runner)),
208 old_localstorage_path_(old_localstorage_path),
61 weak_ptr_factory_(this) {} 209 weak_ptr_factory_(this) {}
62 210
63 LocalStorageContextMojo::~LocalStorageContextMojo() {} 211 LocalStorageContextMojo::~LocalStorageContextMojo() {}
64 212
65 void LocalStorageContextMojo::OpenLocalStorage( 213 void LocalStorageContextMojo::OpenLocalStorage(
66 const url::Origin& origin, 214 const url::Origin& origin,
67 mojom::LevelDBWrapperRequest request) { 215 mojom::LevelDBWrapperRequest request) {
68 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, 216 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage,
69 weak_ptr_factory_.GetWeakPtr(), origin, 217 weak_ptr_factory_.GetWeakPtr(), origin,
70 std::move(request))); 218 std::move(request)));
(...skipping 22 matching lines...) Expand all
93 241
94 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin( 242 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin(
95 const url::Origin& origin) { 243 const url::Origin& origin) {
96 GetStorageUsage(base::BindOnce( 244 GetStorageUsage(base::BindOnce(
97 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin, 245 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin,
98 weak_ptr_factory_.GetWeakPtr(), origin)); 246 weak_ptr_factory_.GetWeakPtr(), origin));
99 } 247 }
100 248
101 void LocalStorageContextMojo::Flush() { 249 void LocalStorageContextMojo::Flush() {
102 for (const auto& it : level_db_wrappers_) 250 for (const auto& it : level_db_wrappers_)
103 it.second->ScheduleImmediateCommit(); 251 it.second->level_db_wrapper()->ScheduleImmediateCommit();
104 } 252 }
105 253
106 leveldb::mojom::LevelDBDatabaseAssociatedRequest 254 leveldb::mojom::LevelDBDatabaseAssociatedRequest
107 LocalStorageContextMojo::DatabaseRequestForTesting() { 255 LocalStorageContextMojo::DatabaseRequestForTesting() {
108 DCHECK_EQ(connection_state_, NO_CONNECTION); 256 DCHECK_EQ(connection_state_, NO_CONNECTION);
109 connection_state_ = CONNECTION_IN_PROGRESS; 257 connection_state_ = CONNECTION_IN_PROGRESS;
110 leveldb::mojom::LevelDBDatabaseAssociatedRequest request = 258 leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
111 MakeRequestForTesting(&database_); 259 MakeRequestForTesting(&database_);
112 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); 260 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK);
113 return request; 261 return request;
(...skipping 17 matching lines...) Expand all
131 279
132 if (connection_state_ == CONNECTION_IN_PROGRESS) { 280 if (connection_state_ == CONNECTION_IN_PROGRESS) {
133 // Queue this OpenLocalStorage call for when we have a level db pointer. 281 // Queue this OpenLocalStorage call for when we have a level db pointer.
134 on_database_opened_callbacks_.push_back(std::move(callback)); 282 on_database_opened_callbacks_.push_back(std::move(callback));
135 return; 283 return;
136 } 284 }
137 285
138 std::move(callback).Run(); 286 std::move(callback).Run();
139 } 287 }
140 288
141 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings(
142 const url::Origin& origin) {
143 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end());
144 level_db_wrappers_.erase(origin);
145 }
146
147 std::vector<leveldb::mojom::BatchedOperationPtr>
148 LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit(
149 const url::Origin& origin,
150 const LevelDBWrapperImpl& wrapper) {
151 // |wrapper| might not exist in |level_db_wrappers_| anymore at this point, as
152 // it is possible this commit was triggered by destruction.
153
154 std::vector<leveldb::mojom::BatchedOperationPtr> operations;
155
156 // Write schema version if not already done so before.
157 if (!database_initialized_) {
158 leveldb::mojom::BatchedOperationPtr item =
159 leveldb::mojom::BatchedOperation::New();
160 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
161 item->key = leveldb::StdStringToUint8Vector(kVersionKey);
162 item->value = leveldb::StdStringToUint8Vector(
163 base::Int64ToString(kCurrentSchemaVersion));
164 operations.push_back(std::move(item));
165 database_initialized_ = true;
166 }
167
168 leveldb::mojom::BatchedOperationPtr item =
169 leveldb::mojom::BatchedOperation::New();
170 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
171 item->key = CreateMetaDataKey(origin);
172 if (wrapper.bytes_used() == 0) {
173 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
174 } else {
175 item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
176 LocalStorageOriginMetaData data;
177 data.set_last_modified(base::Time::Now().ToInternalValue());
178 data.set_size_bytes(wrapper.bytes_used());
179 item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString());
180 }
181 operations.push_back(std::move(item));
182
183 return operations;
184 }
185
186 void LocalStorageContextMojo::OnUserServiceConnectionComplete() { 289 void LocalStorageContextMojo::OnUserServiceConnectionComplete() {
187 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED, 290 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED,
188 file_service_connection_->GetResult()); 291 file_service_connection_->GetResult());
189 } 292 }
190 293
191 void LocalStorageContextMojo::OnUserServiceConnectionError() { 294 void LocalStorageContextMojo::OnUserServiceConnectionError() {
192 CHECK(false); 295 CHECK(false);
193 } 296 }
194 297
195 void LocalStorageContextMojo::InitiateConnection(bool in_memory_only) { 298 void LocalStorageContextMojo::InitiateConnection(bool in_memory_only) {
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 const url::Origin& origin, 461 const url::Origin& origin,
359 mojom::LevelDBWrapperRequest request) { 462 mojom::LevelDBWrapperRequest request) {
360 GetOrCreateDBWrapper(origin)->Bind(std::move(request)); 463 GetOrCreateDBWrapper(origin)->Bind(std::move(request));
361 } 464 }
362 465
363 LevelDBWrapperImpl* LocalStorageContextMojo::GetOrCreateDBWrapper( 466 LevelDBWrapperImpl* LocalStorageContextMojo::GetOrCreateDBWrapper(
364 const url::Origin& origin) { 467 const url::Origin& origin) {
365 DCHECK_EQ(connection_state_, CONNECTION_FINISHED); 468 DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
366 auto found = level_db_wrappers_.find(origin); 469 auto found = level_db_wrappers_.find(origin);
367 if (found != level_db_wrappers_.end()) 470 if (found != level_db_wrappers_.end())
368 return found->second.get(); 471 return found->second->level_db_wrapper();
369 472
370 // Delay for a moment after a value is set in anticipation 473 auto holder = base::MakeUnique<LevelDBWrapperHolder>(this, origin);
371 // of other values being set, so changes are batched. 474 LevelDBWrapperImpl* wrapper_ptr = holder->level_db_wrapper();
372 const int kCommitDefaultDelaySecs = 5; 475 level_db_wrappers_[origin] = std::move(holder);
373
374 // To avoid excessive IO we apply limits to the amount of data being written
375 // and the frequency of writes.
376 const int kMaxBytesPerHour = kPerStorageAreaQuota;
377 const int kMaxCommitsPerHour = 60;
378
379 auto wrapper = base::MakeUnique<LevelDBWrapperImpl>(
380 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator,
381 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
382 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour,
383 kMaxCommitsPerHour,
384 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings,
385 base::Unretained(this), origin),
386 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit,
387 base::Unretained(this), origin));
388 LevelDBWrapperImpl* wrapper_ptr = wrapper.get();
389 level_db_wrappers_[origin] = std::move(wrapper);
390 return wrapper_ptr; 476 return wrapper_ptr;
391 } 477 }
392 478
393 void LocalStorageContextMojo::RetrieveStorageUsage( 479 void LocalStorageContextMojo::RetrieveStorageUsage(
394 GetStorageUsageCallback callback) { 480 GetStorageUsageCallback callback) {
395 database_->GetPrefixed( 481 database_->GetPrefixed(
396 std::vector<uint8_t>(kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)), 482 std::vector<uint8_t>(kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)),
397 base::Bind(&LocalStorageContextMojo::OnGotMetaData, 483 base::Bind(&LocalStorageContextMojo::OnGotMetaData,
398 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); 484 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
399 } 485 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 for (const auto& info : usage) { 517 for (const auto& info : usage) {
432 url::Origin origin_candidate(info.origin); 518 url::Origin origin_candidate(info.origin);
433 if (!origin_candidate.IsSameOriginWith(origin) && 519 if (!origin_candidate.IsSameOriginWith(origin) &&
434 origin_candidate.IsSamePhysicalOriginWith(origin)) 520 origin_candidate.IsSamePhysicalOriginWith(origin))
435 DeleteStorage(origin_candidate); 521 DeleteStorage(origin_candidate);
436 } 522 }
437 DeleteStorage(origin); 523 DeleteStorage(origin);
438 } 524 }
439 525
440 } // namespace content 526 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698