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

Side by Side Diff: webkit/browser/dom_storage/session_storage_database.cc

Issue 22297005: Move webkit/{browser,common}/dom_storage into content/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "webkit/browser/dom_storage/session_storage_database.h"
6
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "third_party/leveldatabase/src/include/leveldb/db.h"
14 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
15 #include "third_party/leveldatabase/src/include/leveldb/options.h"
16 #include "third_party/leveldatabase/src/include/leveldb/status.h"
17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
18 #include "url/gurl.h"
19
20
21 namespace {
22
23 const char session_storage_uma_name[] = "SessionStorageDatabase.Open";
24
25 enum SessionStorageUMA {
26 SESSION_STORAGE_UMA_SUCCESS,
27 SESSION_STORAGE_UMA_RECREATED,
28 SESSION_STORAGE_UMA_FAIL,
29 SESSION_STORAGE_UMA_MAX
30 };
31
32 } // namespace
33
34 // Layout of the database:
35 // | key | value |
36 // -----------------------------------------------------------------------
37 // | map-1- | 2 (refcount, start of map-1-* keys)|
38 // | map-1-a | b (a = b in map 1) |
39 // | ... | |
40 // | namespace- | dummy (start of namespace-* keys) |
41 // | namespace-1- (1 = namespace id)| dummy (start of namespace-1-* keys)|
42 // | namespace-1-origin1 | 1 (mapid) |
43 // | namespace-1-origin2 | 2 |
44 // | namespace-2- | dummy |
45 // | namespace-2-origin1 | 1 (shallow copy) |
46 // | namespace-2-origin2 | 2 (shallow copy) |
47 // | namespace-3- | dummy |
48 // | namespace-3-origin1 | 3 (deep copy) |
49 // | namespace-3-origin2 | 2 (shallow copy) |
50 // | next-map-id | 4 |
51
52 namespace dom_storage {
53
54 SessionStorageDatabase::SessionStorageDatabase(const base::FilePath& file_path)
55 : file_path_(file_path),
56 db_error_(false),
57 is_inconsistent_(false) {
58 }
59
60 SessionStorageDatabase::~SessionStorageDatabase() {
61 }
62
63 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id,
64 const GURL& origin,
65 ValuesMap* result) {
66 // We don't create a database if it doesn't exist. In that case, there is
67 // nothing to be added to the result.
68 if (!LazyOpen(false))
69 return;
70
71 // While ReadAreaValues is in progress, another thread can call
72 // CommitAreaChanges. CommitAreaChanges might update map ref count key while
73 // this thread is iterating over the map ref count key. To protect the reading
74 // operation, create a snapshot and read from it.
75 leveldb::ReadOptions options;
76 options.snapshot = db_->GetSnapshot();
77
78 std::string map_id;
79 bool exists;
80 if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) &&
81 exists)
82 ReadMap(map_id, options, result, false);
83 db_->ReleaseSnapshot(options.snapshot);
84 }
85
86 bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id,
87 const GURL& origin,
88 bool clear_all_first,
89 const ValuesMap& changes) {
90 // Even if |changes| is empty, we need to write the appropriate placeholders
91 // in the database, so that it can be later shallow-copied succssfully.
92 if (!LazyOpen(true))
93 return false;
94
95 leveldb::WriteBatch batch;
96 // Ensure that the keys "namespace-" "namespace-N" (see the schema above)
97 // exist.
98 const bool kOkIfExists = true;
99 if (!CreateNamespace(namespace_id, kOkIfExists, &batch))
100 return false;
101
102 std::string map_id;
103 bool exists;
104 if (!GetMapForArea(namespace_id, origin.spec(), leveldb::ReadOptions(),
105 &exists, &map_id))
106 return false;
107 if (exists) {
108 int64 ref_count;
109 if (!GetMapRefCount(map_id, &ref_count))
110 return false;
111 if (ref_count > 1) {
112 if (!DeepCopyArea(namespace_id, origin, !clear_all_first,
113 &map_id, &batch))
114 return false;
115 }
116 else if (clear_all_first) {
117 if (!ClearMap(map_id, &batch))
118 return false;
119 }
120 } else {
121 // Map doesn't exist, create it now if needed.
122 if (!changes.empty()) {
123 if (!CreateMapForArea(namespace_id, origin, &map_id, &batch))
124 return false;
125 }
126 }
127
128 WriteValuesToMap(map_id, changes, &batch);
129
130 leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch);
131 return DatabaseErrorCheck(s.ok());
132 }
133
134 bool SessionStorageDatabase::CloneNamespace(
135 const std::string& namespace_id, const std::string& new_namespace_id) {
136 // Go through all origins in the namespace |namespace_id|, create placeholders
137 // for them in |new_namespace_id|, and associate them with the existing maps.
138
139 // Example, data before shallow copy:
140 // | map-1- | 1 (refcount) |
141 // | map-1-a | b |
142 // | namespace-1- (1 = namespace id)| dummy |
143 // | namespace-1-origin1 | 1 (mapid) |
144
145 // Example, data after shallow copy:
146 // | map-1- | 2 (inc. refcount) |
147 // | map-1-a | b |
148 // | namespace-1-(1 = namespace id) | dummy |
149 // | namespace-1-origin1 | 1 (mapid) |
150 // | namespace-2- | dummy |
151 // | namespace-2-origin1 | 1 (mapid) << references the same map
152
153 if (!LazyOpen(true))
154 return false;
155
156 leveldb::WriteBatch batch;
157 const bool kOkIfExists = false;
158 if (!CreateNamespace(new_namespace_id, kOkIfExists, &batch))
159 return false;
160
161 std::map<std::string, std::string> areas;
162 if (!GetAreasInNamespace(namespace_id, &areas))
163 return false;
164
165 for (std::map<std::string, std::string>::const_iterator it = areas.begin();
166 it != areas.end(); ++it) {
167 const std::string& origin = it->first;
168 const std::string& map_id = it->second;
169 if (!IncreaseMapRefCount(map_id, &batch))
170 return false;
171 AddAreaToNamespace(new_namespace_id, origin, map_id, &batch);
172 }
173 leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch);
174 return DatabaseErrorCheck(s.ok());
175 }
176
177 bool SessionStorageDatabase::DeleteArea(const std::string& namespace_id,
178 const GURL& origin) {
179 if (!LazyOpen(false)) {
180 // No need to create the database if it doesn't exist.
181 return true;
182 }
183 leveldb::WriteBatch batch;
184 if (!DeleteAreaHelper(namespace_id, origin.spec(), &batch))
185 return false;
186 leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch);
187 return DatabaseErrorCheck(s.ok());
188 }
189
190 bool SessionStorageDatabase::DeleteNamespace(const std::string& namespace_id) {
191 if (!LazyOpen(false)) {
192 // No need to create the database if it doesn't exist.
193 return true;
194 }
195 // Itereate through the areas in the namespace.
196 leveldb::WriteBatch batch;
197 std::map<std::string, std::string> areas;
198 if (!GetAreasInNamespace(namespace_id, &areas))
199 return false;
200 for (std::map<std::string, std::string>::const_iterator it = areas.begin();
201 it != areas.end(); ++it) {
202 const std::string& origin = it->first;
203 if (!DeleteAreaHelper(namespace_id, origin, &batch))
204 return false;
205 }
206 batch.Delete(NamespaceStartKey(namespace_id));
207 leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch);
208 return DatabaseErrorCheck(s.ok());
209 }
210
211 bool SessionStorageDatabase::ReadNamespacesAndOrigins(
212 std::map<std::string, std::vector<GURL> >* namespaces_and_origins) {
213 if (!LazyOpen(true))
214 return false;
215
216 // While ReadNamespacesAndOrigins is in progress, another thread can call
217 // CommitAreaChanges. To protect the reading operation, create a snapshot and
218 // read from it.
219 leveldb::ReadOptions options;
220 options.snapshot = db_->GetSnapshot();
221
222 std::string namespace_prefix = NamespacePrefix();
223 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
224 it->Seek(namespace_prefix);
225 // If the key is not found, the status of the iterator won't be IsNotFound(),
226 // but the iterator will be invalid.
227 if (!it->Valid()) {
228 db_->ReleaseSnapshot(options.snapshot);
229 return true;
230 }
231
232 if (!DatabaseErrorCheck(it->status().ok())) {
233 db_->ReleaseSnapshot(options.snapshot);
234 return false;
235 }
236
237 // Skip the dummy entry "namespace-" and iterate the namespaces.
238 std::string current_namespace_start_key;
239 std::string current_namespace_id;
240 for (it->Next(); it->Valid(); it->Next()) {
241 std::string key = it->key().ToString();
242 if (key.find(namespace_prefix) != 0) {
243 // Iterated past the "namespace-" keys.
244 break;
245 }
246 // For each namespace, the first key is "namespace-<namespaceid>-", and the
247 // subsequent keys are "namespace-<namespaceid>-<origin>". Read the unique
248 // "<namespaceid>" parts from the keys.
249 if (current_namespace_start_key.empty() ||
250 key.substr(0, current_namespace_start_key.length()) !=
251 current_namespace_start_key) {
252 // The key is of the form "namespace-<namespaceid>-" for a new
253 // <namespaceid>.
254 current_namespace_start_key = key;
255 current_namespace_id =
256 key.substr(namespace_prefix.length(),
257 key.length() - namespace_prefix.length() - 1);
258 // Ensure that we keep track of the namespace even if it doesn't contain
259 // any origins.
260 namespaces_and_origins->insert(
261 std::make_pair(current_namespace_id, std::vector<GURL>()));
262 } else {
263 // The key is of the form "namespace-<namespaceid>-<origin>".
264 std::string origin = key.substr(current_namespace_start_key.length());
265 (*namespaces_and_origins)[current_namespace_id].push_back(GURL(origin));
266 }
267 }
268 db_->ReleaseSnapshot(options.snapshot);
269 return true;
270 }
271
272 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
273 base::AutoLock auto_lock(db_lock_);
274 if (db_error_ || is_inconsistent_) {
275 // Don't try to open a database that we know has failed already.
276 return false;
277 }
278 if (IsOpen())
279 return true;
280
281 if (!create_if_needed &&
282 (!base::PathExists(file_path_) ||
283 file_util::IsDirectoryEmpty(file_path_))) {
284 // If the directory doesn't exist already and we haven't been asked to
285 // create a file on disk, then we don't bother opening the database. This
286 // means we wait until we absolutely need to put something onto disk before
287 // we do so.
288 return false;
289 }
290
291 leveldb::DB* db;
292 leveldb::Status s = TryToOpen(&db);
293 if (!s.ok()) {
294 LOG(WARNING) << "Failed to open leveldb in " << file_path_.value()
295 << ", error: " << s.ToString();
296 DCHECK(db == NULL);
297
298 // Clear the directory and try again.
299 base::DeleteFile(file_path_, true);
300 s = TryToOpen(&db);
301 if (!s.ok()) {
302 LOG(WARNING) << "Failed to open leveldb in " << file_path_.value()
303 << ", error: " << s.ToString();
304 UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name,
305 SESSION_STORAGE_UMA_FAIL,
306 SESSION_STORAGE_UMA_MAX);
307 DCHECK(db == NULL);
308 db_error_ = true;
309 return false;
310 }
311 UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name,
312 SESSION_STORAGE_UMA_RECREATED,
313 SESSION_STORAGE_UMA_MAX);
314 } else {
315 UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name,
316 SESSION_STORAGE_UMA_SUCCESS,
317 SESSION_STORAGE_UMA_MAX);
318 }
319 db_.reset(db);
320 return true;
321 }
322
323 leveldb::Status SessionStorageDatabase::TryToOpen(leveldb::DB** db) {
324 leveldb::Options options;
325 // The directory exists but a valid leveldb database might not exist inside it
326 // (e.g., a subset of the needed files might be missing). Handle this
327 // situation gracefully by creating the database now.
328 options.max_open_files = 0; // Use minimum.
329 options.create_if_missing = true;
330 #if defined(OS_WIN)
331 return leveldb::DB::Open(options, WideToUTF8(file_path_.value()), db);
332 #elif defined(OS_POSIX)
333 return leveldb::DB::Open(options, file_path_.value(), db);
334 #endif
335 }
336
337 bool SessionStorageDatabase::IsOpen() const {
338 return db_.get() != NULL;
339 }
340
341 bool SessionStorageDatabase::CallerErrorCheck(bool ok) const {
342 DCHECK(ok);
343 return ok;
344 }
345
346 bool SessionStorageDatabase::ConsistencyCheck(bool ok) {
347 if (ok)
348 return true;
349 base::AutoLock auto_lock(db_lock_);
350 DCHECK(false);
351 is_inconsistent_ = true;
352 // We cannot recover the database during this run, e.g., the upper layer can
353 // have a different understanding of the database state (shallow and deep
354 // copies).
355 // TODO(marja): Error handling.
356 return false;
357 }
358
359 bool SessionStorageDatabase::DatabaseErrorCheck(bool ok) {
360 if (ok)
361 return true;
362 base::AutoLock auto_lock(db_lock_);
363 db_error_ = true;
364 // TODO(marja): Error handling.
365 return false;
366 }
367
368 bool SessionStorageDatabase::CreateNamespace(const std::string& namespace_id,
369 bool ok_if_exists,
370 leveldb::WriteBatch* batch) {
371 leveldb::Slice namespace_prefix = NamespacePrefix();
372 std::string dummy;
373 leveldb::Status s = db_->Get(leveldb::ReadOptions(), namespace_prefix,
374 &dummy);
375 if (!DatabaseErrorCheck(s.ok() || s.IsNotFound()))
376 return false;
377 if (s.IsNotFound())
378 batch->Put(namespace_prefix, "");
379
380 std::string namespace_start_key = NamespaceStartKey(namespace_id);
381 s = db_->Get(leveldb::ReadOptions(), namespace_start_key, &dummy);
382 if (!DatabaseErrorCheck(s.ok() || s.IsNotFound()))
383 return false;
384 if (s.IsNotFound()) {
385 batch->Put(namespace_start_key, "");
386 return true;
387 }
388 return CallerErrorCheck(ok_if_exists);
389 }
390
391 bool SessionStorageDatabase::GetAreasInNamespace(
392 const std::string& namespace_id,
393 std::map<std::string, std::string>* areas) {
394 std::string namespace_start_key = NamespaceStartKey(namespace_id);
395 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
396 it->Seek(namespace_start_key);
397 // If the key is not found, the status of the iterator won't be IsNotFound(),
398 // but the iterator will be invalid.
399 if (!it->Valid()) {
400 // The namespace_start_key is not found when the namespace doesn't contain
401 // any areas. We don't need to do anything.
402 return true;
403 }
404 if (!DatabaseErrorCheck(it->status().ok()))
405 return false;
406
407 // Skip the dummy entry "namespace-<namespaceid>-" and iterate the origins.
408 for (it->Next(); it->Valid(); it->Next()) {
409 std::string key = it->key().ToString();
410 if (key.find(namespace_start_key) != 0) {
411 // Iterated past the origins for this namespace.
412 break;
413 }
414 std::string origin = key.substr(namespace_start_key.length());
415 std::string map_id = it->value().ToString();
416 (*areas)[origin] = map_id;
417 }
418 return true;
419 }
420
421 void SessionStorageDatabase::AddAreaToNamespace(const std::string& namespace_id,
422 const std::string& origin,
423 const std::string& map_id,
424 leveldb::WriteBatch* batch) {
425 std::string namespace_key = NamespaceKey(namespace_id, origin);
426 batch->Put(namespace_key, map_id);
427 }
428
429 bool SessionStorageDatabase::DeleteAreaHelper(
430 const std::string& namespace_id,
431 const std::string& origin,
432 leveldb::WriteBatch* batch) {
433 std::string map_id;
434 bool exists;
435 if (!GetMapForArea(namespace_id, origin, leveldb::ReadOptions(), &exists,
436 &map_id))
437 return false;
438 if (!exists)
439 return true; // Nothing to delete.
440 if (!DecreaseMapRefCount(map_id, 1, batch))
441 return false;
442 std::string namespace_key = NamespaceKey(namespace_id, origin);
443 batch->Delete(namespace_key);
444
445 // If this was the only area in the namespace, delete the namespace start key,
446 // too.
447 std::string namespace_start_key = NamespaceStartKey(namespace_id);
448 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
449 it->Seek(namespace_start_key);
450 if (!ConsistencyCheck(it->Valid()))
451 return false;
452 // Advance the iterator 2 times (we still haven't really deleted
453 // namespace_key).
454 it->Next();
455 if (!ConsistencyCheck(it->Valid()))
456 return false;
457 it->Next();
458 if (!it->Valid())
459 return true;
460 std::string key = it->key().ToString();
461 if (key.find(namespace_start_key) != 0)
462 batch->Delete(namespace_start_key);
463 return true;
464 }
465
466 bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id,
467 const std::string& origin,
468 const leveldb::ReadOptions& options,
469 bool* exists, std::string* map_id) {
470 std::string namespace_key = NamespaceKey(namespace_id, origin);
471 leveldb::Status s = db_->Get(options, namespace_key, map_id);
472 if (s.IsNotFound()) {
473 *exists = false;
474 return true;
475 }
476 *exists = true;
477 return DatabaseErrorCheck(s.ok());
478 }
479
480 bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id,
481 const GURL& origin,
482 std::string* map_id,
483 leveldb::WriteBatch* batch) {
484 leveldb::Slice next_map_id_key = NextMapIdKey();
485 leveldb::Status s = db_->Get(leveldb::ReadOptions(), next_map_id_key, map_id);
486 if (!DatabaseErrorCheck(s.ok() || s.IsNotFound()))
487 return false;
488 int64 next_map_id = 0;
489 if (s.IsNotFound()) {
490 *map_id = "0";
491 } else {
492 bool conversion_ok = base::StringToInt64(*map_id, &next_map_id);
493 if (!ConsistencyCheck(conversion_ok))
494 return false;
495 }
496 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id));
497 std::string namespace_key = NamespaceKey(namespace_id, origin.spec());
498 batch->Put(namespace_key, *map_id);
499 batch->Put(MapRefCountKey(*map_id), "1");
500 return true;
501 }
502
503 bool SessionStorageDatabase::ReadMap(const std::string& map_id,
504 const leveldb::ReadOptions& options,
505 ValuesMap* result,
506 bool only_keys) {
507 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
508 std::string map_start_key = MapRefCountKey(map_id);
509 it->Seek(map_start_key);
510 // If the key is not found, the status of the iterator won't be IsNotFound(),
511 // but the iterator will be invalid. The map needs to exist, otherwise we have
512 // a stale map_id in the database.
513 if (!ConsistencyCheck(it->Valid()))
514 return false;
515 if (!DatabaseErrorCheck(it->status().ok()))
516 return false;
517 // Skip the dummy entry "map-<mapid>-".
518 for (it->Next(); it->Valid(); it->Next()) {
519 std::string key = it->key().ToString();
520 if (key.find(map_start_key) != 0) {
521 // Iterated past the keys in this map.
522 break;
523 }
524 // Key is of the form "map-<mapid>-<key>".
525 base::string16 key16 = UTF8ToUTF16(key.substr(map_start_key.length()));
526 if (only_keys) {
527 (*result)[key16] = base::NullableString16();
528 } else {
529 // Convert the raw data stored in std::string (it->value()) to raw data
530 // stored in base::string16.
531 size_t len = it->value().size() / sizeof(char16);
532 const char16* data_ptr =
533 reinterpret_cast<const char16*>(it->value().data());
534 (*result)[key16] =
535 base::NullableString16(base::string16(data_ptr, len), false);
536 }
537 }
538 return true;
539 }
540
541 void SessionStorageDatabase::WriteValuesToMap(const std::string& map_id,
542 const ValuesMap& values,
543 leveldb::WriteBatch* batch) {
544 for (ValuesMap::const_iterator it = values.begin(); it != values.end();
545 ++it) {
546 base::NullableString16 value = it->second;
547 std::string key = MapKey(map_id, UTF16ToUTF8(it->first));
548 if (value.is_null()) {
549 batch->Delete(key);
550 } else {
551 // Convert the raw data stored in base::string16 to raw data stored in
552 // std::string.
553 const char* data = reinterpret_cast<const char*>(value.string().data());
554 size_t size = value.string().size() * 2;
555 batch->Put(key, leveldb::Slice(data, size));
556 }
557 }
558 }
559
560 bool SessionStorageDatabase::GetMapRefCount(const std::string& map_id,
561 int64* ref_count) {
562 std::string ref_count_string;
563 leveldb::Status s = db_->Get(leveldb::ReadOptions(),
564 MapRefCountKey(map_id), &ref_count_string);
565 if (!ConsistencyCheck(s.ok()))
566 return false;
567 bool conversion_ok = base::StringToInt64(ref_count_string, ref_count);
568 return ConsistencyCheck(conversion_ok);
569 }
570
571 bool SessionStorageDatabase::IncreaseMapRefCount(const std::string& map_id,
572 leveldb::WriteBatch* batch) {
573 // Increase the ref count for the map.
574 int64 old_ref_count;
575 if (!GetMapRefCount(map_id, &old_ref_count))
576 return false;
577 batch->Put(MapRefCountKey(map_id), base::Int64ToString(++old_ref_count));
578 return true;
579 }
580
581 bool SessionStorageDatabase::DecreaseMapRefCount(const std::string& map_id,
582 int decrease,
583 leveldb::WriteBatch* batch) {
584 // Decrease the ref count for the map.
585 int64 ref_count;
586 if (!GetMapRefCount(map_id, &ref_count))
587 return false;
588 if (!ConsistencyCheck(decrease <= ref_count))
589 return false;
590 ref_count -= decrease;
591 if (ref_count > 0) {
592 batch->Put(MapRefCountKey(map_id), base::Int64ToString(ref_count));
593 } else {
594 // Clear all keys in the map.
595 if (!ClearMap(map_id, batch))
596 return false;
597 batch->Delete(MapRefCountKey(map_id));
598 }
599 return true;
600 }
601
602 bool SessionStorageDatabase::ClearMap(const std::string& map_id,
603 leveldb::WriteBatch* batch) {
604 ValuesMap values;
605 if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true))
606 return false;
607 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it)
608 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first)));
609 return true;
610 }
611
612 bool SessionStorageDatabase::DeepCopyArea(
613 const std::string& namespace_id, const GURL& origin, bool copy_data,
614 std::string* map_id, leveldb::WriteBatch* batch) {
615 // Example, data before deep copy:
616 // | namespace-1- (1 = namespace id)| dummy |
617 // | namespace-1-origin1 | 1 (mapid) |
618 // | namespace-2- | dummy |
619 // | namespace-2-origin1 | 1 (mapid) << references the same map
620 // | map-1- | 2 (refcount) |
621 // | map-1-a | b |
622
623 // Example, data after deep copy copy:
624 // | namespace-1-(1 = namespace id) | dummy |
625 // | namespace-1-origin1 | 1 (mapid) |
626 // | namespace-2- | dummy |
627 // | namespace-2-origin1 | 2 (mapid) << references the new map
628 // | map-1- | 1 (dec. refcount) |
629 // | map-1-a | b |
630 // | map-2- | 1 (refcount) |
631 // | map-2-a | b |
632
633 // Read the values from the old map here. If we don't need to copy the data,
634 // this can stay empty.
635 ValuesMap values;
636 if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false))
637 return false;
638 if (!DecreaseMapRefCount(*map_id, 1, batch))
639 return false;
640 // Create a new map (this will also break the association to the old map) and
641 // write the old data into it. This will write the id of the created map into
642 // |map_id|.
643 if (!CreateMapForArea(namespace_id, origin, map_id, batch))
644 return false;
645 WriteValuesToMap(*map_id, values, batch);
646 return true;
647 }
648
649 std::string SessionStorageDatabase::NamespaceStartKey(
650 const std::string& namespace_id) {
651 return base::StringPrintf("namespace-%s-", namespace_id.c_str());
652 }
653
654 std::string SessionStorageDatabase::NamespaceKey(
655 const std::string& namespace_id, const std::string& origin) {
656 return base::StringPrintf("namespace-%s-%s", namespace_id.c_str(),
657 origin.c_str());
658 }
659
660 const char* SessionStorageDatabase::NamespacePrefix() {
661 return "namespace-";
662 }
663
664 std::string SessionStorageDatabase::MapRefCountKey(const std::string& map_id) {
665 return base::StringPrintf("map-%s-", map_id.c_str());
666 }
667
668 std::string SessionStorageDatabase::MapKey(const std::string& map_id,
669 const std::string& key) {
670 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str());
671 }
672
673 const char* SessionStorageDatabase::NextMapIdKey() {
674 return "next-map-id";
675 }
676
677 } // namespace dom_storage
OLDNEW
« no previous file with comments | « webkit/browser/dom_storage/session_storage_database.h ('k') | webkit/browser/dom_storage/session_storage_database_adapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698