1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_area.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_namespace.h"
14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_task_runner.h"
15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/local_storage_database_adapter.h"
16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/session_storage_database.h"
17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/session_storage_database_adapter.h"
18bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/common/dom_storage/dom_storage_map.h"
19bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/common/dom_storage/dom_storage_types.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/database/database_util.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/database/database_identifier.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/fileapi/file_system_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using storage::DatabaseUtil;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace content {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCommitTimerSeconds = 1;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::CommitBatch::CommitBatch()
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : clear_all_first(false) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
33bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::CommitBatch::~CommitBatch() {}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochconst base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL(".localstorage");
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbase::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) {
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string filename = storage::GetIdentifierFromOrigin(origin);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // There is no base::FilePath.AppendExtension() method, so start with just the
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extension as the filename, and then InsertBeforeExtension the desired
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // name.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath().Append(kDatabaseFileExtension).
477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      InsertBeforeExtensionASCII(filename);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochGURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(name.MatchesExtension(kDatabaseFileExtension));
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string origin_id =
547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      name.BaseName().RemoveExtension().MaybeAsASCII();
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return storage::GetOriginFromIdentifier(origin_id);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::DOMStorageArea(
59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const GURL& origin, const base::FilePath& directory,
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    DOMStorageTaskRunner* task_runner)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : namespace_id_(kLocalStorageNamespaceId), origin_(origin),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      directory_(directory),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_(task_runner),
64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      map_(new DOMStorageMap(kPerStorageAreaQuota +
65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                             kPerStorageAreaOverQuotaAllowance)),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_initial_import_done_(true),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_shutdown_(false),
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      commit_batches_in_flight_(0) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!directory.empty()) {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backing_.reset(new LocalStorageDatabaseAdapter(path));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_initial_import_done_ = false;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::DOMStorageArea(
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 namespace_id,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& persistent_namespace_id,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionStorageDatabase* session_storage_backing,
81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    DOMStorageTaskRunner* task_runner)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : namespace_id_(namespace_id),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      persistent_namespace_id_(persistent_namespace_id),
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      origin_(origin),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_(task_runner),
86bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      map_(new DOMStorageMap(kPerStorageAreaQuota +
87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                             kPerStorageAreaOverQuotaAllowance)),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      session_storage_backing_(session_storage_backing),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_initial_import_done_(true),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_shutdown_(false),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      commit_batches_in_flight_(0) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(namespace_id != kLocalStorageNamespaceId);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (session_storage_backing) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backing_.reset(new SessionStorageDatabaseAdapter(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        session_storage_backing, persistent_namespace_id, origin));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_initial_import_done_ = false;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
100bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::~DOMStorageArea() {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::ExtractValues(DOMStorageValuesMap* map) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  map_->ExtractValues(map);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
110bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochunsigned DOMStorageArea::Length() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return map_->Length();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbase::NullableString16 DOMStorageArea::Key(unsigned index) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return base::NullableString16();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return map_->Key(index);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
124bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbase::NullableString16 DOMStorageArea::GetItem(const base::string16& key) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return base::NullableString16();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return map_->GetItem(key);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageArea::SetItem(const base::string16& key,
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             const base::string16& value,
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                             base::NullableString16* old_value) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!map_->HasOneRef())
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_ = map_->DeepCopy();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = map_->SetItem(key, value, old_value);
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (success && backing_) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    commit_batch->changed_values[key] = base::NullableString16(value, false);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
147bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageArea::RemoveItem(const base::string16& key,
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                base::string16* old_value) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!map_->HasOneRef())
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_ = map_->DeepCopy();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = map_->RemoveItem(key, old_value);
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (success && backing_) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    commit_batch->changed_values[key] = base::NullableString16();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
162bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageArea::Clear() {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitialImportIfNeeded();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (map_->Length() == 0)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  map_ = new DOMStorageMap(kPerStorageAreaQuota +
170bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                           kPerStorageAreaOverQuotaAllowance);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (backing_) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commit_batch->clear_all_first = true;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commit_batch->changed_values.clear();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
181bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::FastClear() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(marja): Unify clearing localStorage and sessionStorage. The problem is
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to make the following 3 to work together: 1) FastClear, 2) PurgeMemory and
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3) not creating events when clearing an empty area.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
188bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  map_ = new DOMStorageMap(kPerStorageAreaQuota +
189bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                           kPerStorageAreaOverQuotaAllowance);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This ensures no import will happen while we're waiting to clear the data
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the database. This mechanism fails if PurgeMemory is called.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initial_import_done_ = true;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (backing_) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commit_batch->clear_all_first = true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commit_batch->changed_values.clear();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
201bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea* DOMStorageArea::ShallowCopy(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 destination_namespace_id,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& destination_persistent_namespace_id) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DOMStorageArea* copy = new DOMStorageArea(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      destination_namespace_id, destination_persistent_namespace_id, origin_,
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      session_storage_backing_.get(), task_runner_.get());
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->map_ = map_;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->is_shutdown_ = is_shutdown_;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->is_initial_import_done_ = true;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All the uncommitted changes to this area need to happen before the actual
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // call might be in the event queue at this point, but it's handled gracefully
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when it fires.
218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (commit_batch_)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnCommitTimer();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return copy;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
223bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageArea::HasUncommittedChanges() const {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_shutdown_);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return commit_batch_.get() || commit_batches_in_flight_;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
228bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::DeleteOrigin() {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_shutdown_);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function shouldn't be called for sessionStorage.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!session_storage_backing_.get());
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasUncommittedChanges()) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(michaeln): This logically deletes the data immediately,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and in a matter of a second, deletes the rows from the backing
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // database file, but the file itself will linger until shutdown
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // or purge time. Ideally, this should delete the file more
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // quickly.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Clear();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
241bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  map_ = new DOMStorageMap(kPerStorageAreaQuota +
242bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                           kPerStorageAreaOverQuotaAllowance);
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (backing_) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_initial_import_done_ = false;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backing_->Reset();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    backing_->DeleteFiles();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
250bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::PurgeMemory() {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_shutdown_);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Purging sessionStorage is not supported; it won't work with FastClear.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!session_storage_backing_.get());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_initial_import_done_ ||  // We're not using any memory.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !backing_.get() ||  // We can't purge anything.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HasUncommittedChanges())  // We leave things alone with changes pending.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the in memory cache, we'll reload when needed.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initial_import_done_ = false;
261bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  map_ = new DOMStorageMap(kPerStorageAreaQuota +
262bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                           kPerStorageAreaOverQuotaAllowance);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Recreate the database object, this frees up the open sqlite connection
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and its page cache.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backing_->Reset();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
269bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::Shutdown() {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_shutdown_);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_shutdown_ = true;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  map_ = NULL;
273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!backing_)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = task_runner_->PostShutdownBlockingTask(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
278bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      DOMStorageTaskRunner::COMMIT_SEQUENCE,
279bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::Bind(&DOMStorageArea::ShutdownInCommitSequence, this));
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(success);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::InitialImportIfNeeded() {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_initial_import_done_)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backing_.get());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks before = base::TimeTicks::Now();
290bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DOMStorageValuesMap initial_values;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backing_->ReadAllValues(&initial_values);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  map_->SwapValues(&initial_values);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initial_import_done_ = true;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta time_to_import = base::TimeTicks::Now() - before;
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage",
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      time_to_import);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t local_storage_size_kb = map_->bytes_used() / 1024;
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Track localStorage size, from 0-6MB. Note that the maximum size should be
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 5MB, but we add some slop since we want to make sure the max size is always
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // above what we see in practice, since histograms can't change.
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.BrowserLocalStorageSizeInKB",
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              local_storage_size_kb,
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              0, 6 * 1024, 50);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (local_storage_size_kb < 100) {
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_TIMES(
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "LocalStorage.BrowserTimeToPrimeLocalStorageUnder100KB",
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        time_to_import);
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (local_storage_size_kb < 1000) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_TIMES(
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "LocalStorage.BrowserTimeToPrimeLocalStorage100KBTo1MB",
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        time_to_import);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_TIMES(
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "LocalStorage.BrowserTimeToPrimeLocalStorage1MBTo5MB",
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        time_to_import);
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
320bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_shutdown_);
322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!commit_batch_) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commit_batch_.reset(new CommitBatch());
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Start a timer to commit any changes that accrue in the batch, but only if
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // no commits are currently in flight. In that case the timer will be
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // started after the commits have happened.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!commit_batches_in_flight_) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_->PostDelayedTask(
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
331bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          base::Bind(&DOMStorageArea::OnCommitTimer, this),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromSeconds(kCommitTimerSeconds));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return commit_batch_.get();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
338bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::OnCommitTimer() {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backing_.get());
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It's possible that there is nothing to commit, since a shallow copy occured
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // before the timer fired.
346b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!commit_batch_)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method executes on the primary sequence, we schedule
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a task for immediate execution on the commit sequence.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->IsRunningOnPrimarySequence());
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = task_runner_->PostShutdownBlockingTask(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
354bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      DOMStorageTaskRunner::COMMIT_SEQUENCE,
355bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::Bind(&DOMStorageArea::CommitChanges, this,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Owned(commit_batch_.release())));
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++commit_batches_in_flight_;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(success);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
361bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method executes on the commit sequence.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->IsRunningOnCommitSequence());
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  backing_->CommitChanges(commit_batch->clear_all_first,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         commit_batch->changed_values);
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(michaeln): what if CommitChanges returns false (e.g., we're trying to
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // commit to a DB which is in an inconsistent state?)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  task_runner_->PostTask(
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
370bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::Bind(&DOMStorageArea::OnCommitComplete, this));
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
373bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::OnCommitComplete() {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're back on the primary sequence in this method.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->IsRunningOnPrimarySequence());
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --commit_batches_in_flight_;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_shutdown_)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (commit_batch_.get() && !commit_batches_in_flight_) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // More changes have accrued, restart the timer.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    task_runner_->PostDelayedTask(
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
383bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        base::Bind(&DOMStorageArea::OnCommitTimer, this),
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromSeconds(kCommitTimerSeconds));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
388bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageArea::ShutdownInCommitSequence() {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method executes on the commit sequence.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->IsRunningOnCommitSequence());
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backing_.get());
392b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (commit_batch_) {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit any changes that accrued prior to the timer firing.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success = backing_->CommitChanges(
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        commit_batch_->clear_all_first,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        commit_batch_->changed_values);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(success);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commit_batch_.reset();
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backing_.reset();
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_storage_backing_ = NULL;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
404bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace content
405