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

Side by Side Diff: webkit/dom_storage/dom_storage_area.cc

Issue 9963107: Persist sessionStorage on disk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: session only rules Created 8 years, 5 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "webkit/dom_storage/dom_storage_area.h" 5 #include "webkit/dom_storage/dom_storage_area.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/time.h" 10 #include "base/time.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" 11 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
12 #include "webkit/database/database_util.h" 12 #include "webkit/database/database_util.h"
13 #include "webkit/dom_storage/dom_storage_map.h" 13 #include "webkit/dom_storage/dom_storage_map.h"
14 #include "webkit/dom_storage/dom_storage_namespace.h" 14 #include "webkit/dom_storage/dom_storage_namespace.h"
15 #include "webkit/dom_storage/dom_storage_task_runner.h" 15 #include "webkit/dom_storage/dom_storage_task_runner.h"
16 #include "webkit/dom_storage/dom_storage_types.h" 16 #include "webkit/dom_storage/dom_storage_types.h"
17 #include "webkit/dom_storage/local_storage_database_adapter.h" 17 #include "webkit/dom_storage/local_storage_database_adapter.h"
18 #include "webkit/dom_storage/session_storage_database.h"
19 #include "webkit/dom_storage/session_storage_database_adapter.h"
18 #include "webkit/fileapi/file_system_util.h" 20 #include "webkit/fileapi/file_system_util.h"
19 #include "webkit/glue/webkit_glue.h" 21 #include "webkit/glue/webkit_glue.h"
20 22
21 using webkit_database::DatabaseUtil; 23 using webkit_database::DatabaseUtil;
22 24
23 namespace dom_storage { 25 namespace dom_storage {
24 26
25 static const int kCommitTimerSeconds = 1; 27 static const int kCommitTimerSeconds = 1;
26 28
27 DomStorageArea::CommitBatch::CommitBatch() 29 DomStorageArea::CommitBatch::CommitBatch()
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); 67 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
66 backing_.reset(new LocalStorageDatabaseAdapter(path)); 68 backing_.reset(new LocalStorageDatabaseAdapter(path));
67 is_initial_import_done_ = false; 69 is_initial_import_done_ = false;
68 } 70 }
69 } 71 }
70 72
71 DomStorageArea::DomStorageArea( 73 DomStorageArea::DomStorageArea(
72 int64 namespace_id, 74 int64 namespace_id,
73 const std::string& persistent_namespace_id, 75 const std::string& persistent_namespace_id,
74 const GURL& origin, 76 const GURL& origin,
77 SessionStorageDatabase* session_storage_backing,
75 DomStorageTaskRunner* task_runner) 78 DomStorageTaskRunner* task_runner)
76 : namespace_id_(namespace_id), 79 : namespace_id_(namespace_id),
77 persistent_namespace_id_(persistent_namespace_id), 80 persistent_namespace_id_(persistent_namespace_id),
78 origin_(origin), 81 origin_(origin),
79 task_runner_(task_runner), 82 task_runner_(task_runner),
80 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)), 83 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)),
84 session_storage_backing_(session_storage_backing),
81 is_initial_import_done_(true), 85 is_initial_import_done_(true),
82 is_shutdown_(false), 86 is_shutdown_(false),
83 commit_batches_in_flight_(0) { 87 commit_batches_in_flight_(0) {
84 DCHECK(namespace_id != kLocalStorageNamespaceId); 88 DCHECK(namespace_id != kLocalStorageNamespaceId);
89 if (session_storage_backing) {
90 backing_.reset(new SessionStorageDatabaseAdapter(
91 session_storage_backing, persistent_namespace_id, origin));
92 is_initial_import_done_ = false;
93 }
85 } 94 }
86 95
87 DomStorageArea::~DomStorageArea() { 96 DomStorageArea::~DomStorageArea() {
88 } 97 }
89 98
90 void DomStorageArea::ExtractValues(ValuesMap* map) { 99 void DomStorageArea::ExtractValues(ValuesMap* map) {
91 if (is_shutdown_) 100 if (is_shutdown_)
92 return; 101 return;
93 InitialImportIfNeeded(); 102 InitialImportIfNeeded();
94 map_->ExtractValues(map); 103 map_->ExtractValues(map);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 } 170 }
162 171
163 return true; 172 return true;
164 } 173 }
165 174
166 DomStorageArea* DomStorageArea::ShallowCopy( 175 DomStorageArea* DomStorageArea::ShallowCopy(
167 int64 destination_namespace_id, 176 int64 destination_namespace_id,
168 const std::string& destination_persistent_namespace_id) { 177 const std::string& destination_persistent_namespace_id) {
169 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_); 178 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
170 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); 179 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
171 DCHECK(!backing_.get()); // SessionNamespaces aren't stored on disk.
172 180
173 DomStorageArea* copy = new DomStorageArea( 181 DomStorageArea* copy = new DomStorageArea(
174 destination_namespace_id, destination_persistent_namespace_id, origin_, 182 destination_namespace_id, destination_persistent_namespace_id, origin_,
175 task_runner_); 183 session_storage_backing_, task_runner_);
176 copy->map_ = map_; 184 copy->map_ = map_;
177 copy->is_shutdown_ = is_shutdown_; 185 copy->is_shutdown_ = is_shutdown_;
michaeln 2012/06/26 06:15:12 since map_ is populated, should we set is_initial_
marja 2012/06/26 14:18:05 Done.
186
187 // All the uncommitted changes to this area need to happen before the actual
188 // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer
189 // call might be in the event queue at this point, but it's handled gracefully
190 // when it fires.
191 if (commit_batch_.get())
192 OnCommitTimer();
178 return copy; 193 return copy;
179 } 194 }
180 195
181 bool DomStorageArea::HasUncommittedChanges() const { 196 bool DomStorageArea::HasUncommittedChanges() const {
182 DCHECK(!is_shutdown_); 197 DCHECK(!is_shutdown_);
183 return commit_batch_.get() || commit_batches_in_flight_; 198 return commit_batch_.get() || commit_batches_in_flight_;
184 } 199 }
185 200
186 void DomStorageArea::DeleteOrigin() { 201 void DomStorageArea::DeleteOrigin() {
187 DCHECK(!is_shutdown_); 202 DCHECK(!is_shutdown_);
188 if (HasUncommittedChanges()) { 203 if (HasUncommittedChanges()) {
189 // TODO(michaeln): This logically deletes the data immediately, 204 // TODO(michaeln): This logically deletes the data immediately,
190 // and in a matter of a second, deletes the rows from the backing 205 // and in a matter of a second, deletes the rows from the backing
191 // database file, but the file itself will linger until shutdown 206 // database file, but the file itself will linger until shutdown
192 // or purge time. Ideally, this should delete the file more 207 // or purge time. Ideally, this should delete the file more
193 // quickly. 208 // quickly.
194 Clear(); 209 Clear();
195 return; 210 return;
196 } 211 }
197 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); 212 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance);
198 if (backing_.get()) { 213 if (backing_.get() && !session_storage_backing_.get()) {
214 // This is localStorage.
199 is_initial_import_done_ = false; 215 is_initial_import_done_ = false;
200 backing_->Reset(); 216 backing_->Reset();
201 backing_->DeleteFiles(); 217 backing_->DeleteFiles();
218 } else if (session_storage_backing_.get()) {
219 // No need to read the data (there will be no data), also, the
220 // PRIMARY_SEQUENCE thread shouldn't try to read the data while
221 // SessionStorageDatabase::DeleteArea is in progress.
222 is_initial_import_done_ = true;
223 task_runner_->PostShutdownBlockingTask(
224 FROM_HERE,
225 DomStorageTaskRunner::COMMIT_SEQUENCE,
226 base::Bind(base::IgnoreResult(&SessionStorageDatabase::DeleteArea),
227 session_storage_backing_.get(),
228 persistent_namespace_id_, origin_));
202 } 229 }
203 } 230 }
204 231
205 void DomStorageArea::PurgeMemory() { 232 void DomStorageArea::PurgeMemory() {
206 DCHECK(!is_shutdown_); 233 DCHECK(!is_shutdown_);
207 if (!is_initial_import_done_ || // We're not using any memory. 234 if (!is_initial_import_done_ || // We're not using any memory.
208 !backing_.get() || // We can't purge anything. 235 !backing_.get() || // We can't purge anything.
209 HasUncommittedChanges()) // We leave things alone with changes pending. 236 HasUncommittedChanges()) // We leave things alone with changes pending.
210 return; 237 return;
211 238
(...skipping 17 matching lines...) Expand all
229 FROM_HERE, 256 FROM_HERE,
230 DomStorageTaskRunner::COMMIT_SEQUENCE, 257 DomStorageTaskRunner::COMMIT_SEQUENCE,
231 base::Bind(&DomStorageArea::ShutdownInCommitSequence, this)); 258 base::Bind(&DomStorageArea::ShutdownInCommitSequence, this));
232 DCHECK(success); 259 DCHECK(success);
233 } 260 }
234 261
235 void DomStorageArea::InitialImportIfNeeded() { 262 void DomStorageArea::InitialImportIfNeeded() {
236 if (is_initial_import_done_) 263 if (is_initial_import_done_)
237 return; 264 return;
238 265
239 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
240 DCHECK(backing_.get()); 266 DCHECK(backing_.get());
241 267
242 ValuesMap initial_values; 268 ValuesMap initial_values;
243 backing_->ReadAllValues(&initial_values); 269 backing_->ReadAllValues(&initial_values);
244 map_->SwapValues(&initial_values); 270 map_->SwapValues(&initial_values);
245 is_initial_import_done_ = true; 271 is_initial_import_done_ = true;
246 } 272 }
247 273
248 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { 274 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() {
249 DCHECK(!is_shutdown_); 275 DCHECK(!is_shutdown_);
250 if (!commit_batch_.get()) { 276 if (!commit_batch_.get()) {
251 commit_batch_.reset(new CommitBatch()); 277 commit_batch_.reset(new CommitBatch());
252 278
253 // Start a timer to commit any changes that accrue in the batch, but only if 279 // Start a timer to commit any changes that accrue in the batch, but only if
254 // no commits are currently in flight. In that case the timer will be 280 // no commits are currently in flight. In that case the timer will be
255 // started after the commits have happened. 281 // started after the commits have happened.
256 if (!commit_batches_in_flight_) { 282 if (!commit_batches_in_flight_) {
257 task_runner_->PostDelayedTask( 283 task_runner_->PostDelayedTask(
258 FROM_HERE, 284 FROM_HERE,
259 base::Bind(&DomStorageArea::OnCommitTimer, this), 285 base::Bind(&DomStorageArea::OnCommitTimer, this),
260 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); 286 base::TimeDelta::FromSeconds(kCommitTimerSeconds));
261 } 287 }
262 } 288 }
263 return commit_batch_.get(); 289 return commit_batch_.get();
264 } 290 }
265 291
266 void DomStorageArea::OnCommitTimer() { 292 void DomStorageArea::OnCommitTimer() {
267 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
268 if (is_shutdown_) 293 if (is_shutdown_)
269 return; 294 return;
270 295
271 DCHECK(backing_.get()); 296 DCHECK(backing_.get());
272 DCHECK(commit_batch_.get()); 297
273 DCHECK(!commit_batches_in_flight_); 298 // It's possible that there is nothing to commit, since a shallow copy occured
299 // before the timer fired.
300 if (!commit_batch_.get())
301 return;
274 302
275 // This method executes on the primary sequence, we schedule 303 // This method executes on the primary sequence, we schedule
276 // a task for immediate execution on the commit sequence. 304 // a task for immediate execution on the commit sequence.
277 DCHECK(task_runner_->IsRunningOnPrimarySequence()); 305 DCHECK(task_runner_->IsRunningOnPrimarySequence());
278 bool success = task_runner_->PostShutdownBlockingTask( 306 bool success = task_runner_->PostShutdownBlockingTask(
279 FROM_HERE, 307 FROM_HERE,
280 DomStorageTaskRunner::COMMIT_SEQUENCE, 308 DomStorageTaskRunner::COMMIT_SEQUENCE,
281 base::Bind(&DomStorageArea::CommitChanges, this, 309 base::Bind(&DomStorageArea::CommitChanges, this,
282 base::Owned(commit_batch_.release()))); 310 base::Owned(commit_batch_.release())));
283 ++commit_batches_in_flight_; 311 ++commit_batches_in_flight_;
284 DCHECK(success); 312 DCHECK(success);
285 } 313 }
286 314
287 void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) { 315 void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) {
288 // This method executes on the commit sequence. 316 // This method executes on the commit sequence.
289 DCHECK(task_runner_->IsRunningOnCommitSequence()); 317 DCHECK(task_runner_->IsRunningOnCommitSequence());
290 bool success = backing_->CommitChanges(commit_batch->clear_all_first, 318 bool success = backing_->CommitChanges(commit_batch->clear_all_first,
291 commit_batch->changed_values); 319 commit_batch->changed_values);
292 DCHECK(success); // TODO(michaeln): what if it fails? 320 DCHECK(success); // TODO(michaeln): what if it fails?
293 task_runner_->PostTask( 321 task_runner_->PostTask(
294 FROM_HERE, 322 FROM_HERE,
295 base::Bind(&DomStorageArea::OnCommitComplete, this)); 323 base::Bind(&DomStorageArea::OnCommitComplete, this));
296 } 324 }
297 325
298 void DomStorageArea::OnCommitComplete() { 326 void DomStorageArea::OnCommitComplete() {
299 // We're back on the primary sequence in this method. 327 // We're back on the primary sequence in this method.
300 DCHECK(task_runner_->IsRunningOnPrimarySequence()); 328 DCHECK(task_runner_->IsRunningOnPrimarySequence());
329 --commit_batches_in_flight_;
301 if (is_shutdown_) 330 if (is_shutdown_)
302 return; 331 return;
303 --commit_batches_in_flight_;
304 if (commit_batch_.get() && !commit_batches_in_flight_) { 332 if (commit_batch_.get() && !commit_batches_in_flight_) {
305 // More changes have accrued, restart the timer. 333 // More changes have accrued, restart the timer.
306 task_runner_->PostDelayedTask( 334 task_runner_->PostDelayedTask(
307 FROM_HERE, 335 FROM_HERE,
308 base::Bind(&DomStorageArea::OnCommitTimer, this), 336 base::Bind(&DomStorageArea::OnCommitTimer, this),
309 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); 337 base::TimeDelta::FromSeconds(kCommitTimerSeconds));
310 } 338 }
311 } 339 }
312 340
313 void DomStorageArea::ShutdownInCommitSequence() { 341 void DomStorageArea::ShutdownInCommitSequence() {
314 // This method executes on the commit sequence. 342 // This method executes on the commit sequence.
315 DCHECK(task_runner_->IsRunningOnCommitSequence()); 343 DCHECK(task_runner_->IsRunningOnCommitSequence());
316 DCHECK(backing_.get()); 344 DCHECK(backing_.get());
317 if (commit_batch_.get()) { 345 if (commit_batch_.get()) {
318 // Commit any changes that accrued prior to the timer firing. 346 // Commit any changes that accrued prior to the timer firing.
319 bool success = backing_->CommitChanges( 347 bool success = backing_->CommitChanges(
320 commit_batch_->clear_all_first, 348 commit_batch_->clear_all_first,
321 commit_batch_->changed_values); 349 commit_batch_->changed_values);
322 DCHECK(success); 350 DCHECK(success);
323 } 351 }
324 commit_batch_.reset(); 352 commit_batch_.reset();
325 backing_.reset(); 353 backing_.reset();
354 session_storage_backing_ = NULL;
326 } 355 }
327 356
328 } // namespace dom_storage 357 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698