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

Side by Side Diff: content/browser/dom_storage/local_storage_context_mojo.cc

Issue 2607493003: Store a version number in the localstorage database. (Closed)
Patch Set: 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"
9 #include "components/leveldb/public/cpp/util.h"
8 #include "content/browser/leveldb_wrapper_impl.h" 10 #include "content/browser/leveldb_wrapper_impl.h"
9 #include "content/common/dom_storage/dom_storage_types.h" 11 #include "content/common/dom_storage/dom_storage_types.h"
10 #include "services/file/public/interfaces/constants.mojom.h" 12 #include "services/file/public/interfaces/constants.mojom.h"
11 #include "services/service_manager/public/cpp/connection.h" 13 #include "services/service_manager/public/cpp/connection.h"
12 #include "services/service_manager/public/cpp/connector.h" 14 #include "services/service_manager/public/cpp/connector.h"
13 15
14 namespace content { 16 namespace content {
15 17
18 // LevelDB database schema
19 // =======================
20 //
21 // Version 1 (in sorted order):
22 // key: "VERSION"
23 // value: "1"
24 //
25 // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key>
26 // value: <script controlled value>
27
16 namespace { 28 namespace {
29 const char kVersionKey[] = "VERSION";
17 const char kOriginSeparator = '\x00'; 30 const char kOriginSeparator = '\x00';
31 const char kDataPrefix[] = "_";
32 const int64_t kMinSchemaVersion = 1;
33 const int64_t kCurrentSchemaVersion = 1;
34
35 void NoOpResult(leveldb::mojom::DatabaseError status) {}
18 } 36 }
19 37
20 LocalStorageContextMojo::LocalStorageContextMojo( 38 LocalStorageContextMojo::LocalStorageContextMojo(
21 service_manager::Connector* connector, 39 service_manager::Connector* connector,
22 const base::FilePath& subdirectory) 40 const base::FilePath& subdirectory)
23 : connector_(connector), 41 : connector_(connector),
24 subdirectory_(subdirectory), 42 subdirectory_(subdirectory),
25 weak_ptr_factory_(this) {} 43 weak_ptr_factory_(this) {}
26 44
27 LocalStorageContextMojo::~LocalStorageContextMojo() {} 45 LocalStorageContextMojo::~LocalStorageContextMojo() {}
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 &LocalStorageContextMojo::BindLocalStorage, 83 &LocalStorageContextMojo::BindLocalStorage,
66 weak_ptr_factory_.GetWeakPtr(), origin, base::Passed(&request))); 84 weak_ptr_factory_.GetWeakPtr(), origin, base::Passed(&request)));
67 return; 85 return;
68 } 86 }
69 87
70 BindLocalStorage(origin, std::move(request)); 88 BindLocalStorage(origin, std::move(request));
71 } 89 }
72 90
73 void LocalStorageContextMojo::SetDatabaseForTesting( 91 void LocalStorageContextMojo::SetDatabaseForTesting(
74 leveldb::mojom::LevelDBDatabasePtr database) { 92 leveldb::mojom::LevelDBDatabasePtr database) {
93 DCHECK_EQ(connection_state_, NO_CONNECTION);
94 connection_state_ = CONNECTION_IN_PROGRESS;
75 database_ = std::move(database); 95 database_ = std::move(database);
76 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); 96 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK);
77 } 97 }
78 98
79 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( 99 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings(
80 const url::Origin& origin) { 100 const url::Origin& origin) {
81 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); 101 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end());
82 level_db_wrappers_.erase(origin); 102 level_db_wrappers_.erase(origin);
83 } 103 }
84 104
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 // null pointers to our wrappers. 138 // null pointers to our wrappers.
119 database_.reset(); 139 database_.reset();
120 leveldb_service_.reset(); 140 leveldb_service_.reset();
121 } 141 }
122 142
123 // We no longer need the file service; we've either transferred |directory_| 143 // We no longer need the file service; we've either transferred |directory_|
124 // to the leveldb service, or we got a file error and no more is possible. 144 // to the leveldb service, or we got a file error and no more is possible.
125 directory_.reset(); 145 directory_.reset();
126 file_system_.reset(); 146 file_system_.reset();
127 147
128 // |leveldb_| should be known to either be valid or invalid by now. Run our 148 // Verify DB schema version.
149 if (database_) {
150 database_->Get(leveldb::StdStringToUint8Vector(kVersionKey),
151 base::Bind(&LocalStorageContextMojo::OnGotDatabaseVersion,
152 weak_ptr_factory_.GetWeakPtr()));
153 return;
154 }
155
156 OnGotDatabaseVersion(leveldb::mojom::DatabaseError::IO_ERROR,
157 std::vector<uint8_t>());
158 }
159
160 void LocalStorageContextMojo::OnGotDatabaseVersion(
161 leveldb::mojom::DatabaseError status,
162 const std::vector<uint8_t>& value) {
163 if (status == leveldb::mojom::DatabaseError::NOT_FOUND) {
164 // New database, write current version and continue.
165 // TODO(mek): Delay writing version until first actual data gets committed.
166 database_->Put(leveldb::StdStringToUint8Vector(kVersionKey),
167 leveldb::StdStringToUint8Vector(
168 base::Int64ToString(kCurrentSchemaVersion)),
169 base::Bind(&NoOpResult));
170 // new database
171 } else if (status == leveldb::mojom::DatabaseError::OK) {
172 // Existing database, check if version number matches current schema
173 // version.
174 int64_t db_version;
175 if (!base::StringToInt64(leveldb::Uint8VectorToStdString(value),
176 &db_version) ||
177 db_version < kMinSchemaVersion || db_version > kCurrentSchemaVersion) {
178 // TODO(mek): delete and recreate database, rather than failing outright.
179 database_ = nullptr;
180 }
181 } else {
182 // Other read error. Possibly database corruption.
183 // TODO(mek): delete and recreate database, rather than failing outright.
184 database_ = nullptr;
185 }
186
187 // |database_| should be known to either be valid or invalid by now. Run our
129 // delayed bindings. 188 // delayed bindings.
130 connection_state_ = CONNECTION_FINISHED; 189 connection_state_ = CONNECTION_FINISHED;
131 for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i) 190 for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i)
132 on_database_opened_callbacks_[i].Run(); 191 on_database_opened_callbacks_[i].Run();
133 on_database_opened_callbacks_.clear(); 192 on_database_opened_callbacks_.clear();
134 } 193 }
135 194
136 // The (possibly delayed) implementation of OpenLocalStorage(). Can be called 195 // The (possibly delayed) implementation of OpenLocalStorage(). Can be called
137 // directly from that function, or through |on_database_open_callbacks_|. 196 // directly from that function, or through |on_database_open_callbacks_|.
138 void LocalStorageContextMojo::BindLocalStorage( 197 void LocalStorageContextMojo::BindLocalStorage(
139 const url::Origin& origin, 198 const url::Origin& origin,
140 mojom::LevelDBWrapperRequest request) { 199 mojom::LevelDBWrapperRequest request) {
141 // Delay for a moment after a value is set in anticipation 200 // Delay for a moment after a value is set in anticipation
142 // of other values being set, so changes are batched. 201 // of other values being set, so changes are batched.
143 const int kCommitDefaultDelaySecs = 5; 202 const int kCommitDefaultDelaySecs = 5;
144 203
145 // To avoid excessive IO we apply limits to the amount of data being written 204 // To avoid excessive IO we apply limits to the amount of data being written
146 // and the frequency of writes. 205 // and the frequency of writes.
147 const int kMaxBytesPerHour = kPerStorageAreaQuota; 206 const int kMaxBytesPerHour = kPerStorageAreaQuota;
148 const int kMaxCommitsPerHour = 60; 207 const int kMaxCommitsPerHour = 60;
149 208
150 auto found = level_db_wrappers_.find(origin); 209 auto found = level_db_wrappers_.find(origin);
151 if (found == level_db_wrappers_.end()) { 210 if (found == level_db_wrappers_.end()) {
152 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>( 211 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>(
153 database_.get(), origin.Serialize() + kOriginSeparator, 212 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator,
154 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance, 213 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
155 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour, 214 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour,
156 kMaxCommitsPerHour, 215 kMaxCommitsPerHour,
157 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, 216 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings,
158 base::Unretained(this), origin)); 217 base::Unretained(this), origin));
159 found = level_db_wrappers_.find(origin); 218 found = level_db_wrappers_.find(origin);
160 } 219 }
161 220
162 found->second->Bind(std::move(request)); 221 found->second->Bind(std::move(request));
163 } 222 }
164 223
165 } // namespace content 224 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698