Home | History | Annotate | Download | only in dom_storage
      1 // Copyright 2013 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 "content/browser/dom_storage/dom_storage_namespace.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/location.h"
     10 #include "base/logging.h"
     11 #include "content/browser/dom_storage/dom_storage_area.h"
     12 #include "content/browser/dom_storage/dom_storage_task_runner.h"
     13 #include "content/browser/dom_storage/session_storage_database.h"
     14 #include "content/common/dom_storage/dom_storage_types.h"
     15 
     16 namespace content {
     17 
     18 DOMStorageNamespace::DOMStorageNamespace(
     19     const base::FilePath& directory,
     20     DOMStorageTaskRunner* task_runner)
     21     : namespace_id_(kLocalStorageNamespaceId),
     22       directory_(directory),
     23       task_runner_(task_runner) {
     24 }
     25 
     26 DOMStorageNamespace::DOMStorageNamespace(
     27     int64 namespace_id,
     28     const std::string& persistent_namespace_id,
     29     SessionStorageDatabase* session_storage_database,
     30     DOMStorageTaskRunner* task_runner)
     31     : namespace_id_(namespace_id),
     32       persistent_namespace_id_(persistent_namespace_id),
     33       task_runner_(task_runner),
     34       session_storage_database_(session_storage_database) {
     35   DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
     36 }
     37 
     38 DOMStorageNamespace::~DOMStorageNamespace() {
     39 }
     40 
     41 DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
     42   if (AreaHolder* holder = GetAreaHolder(origin)) {
     43     ++(holder->open_count_);
     44     return holder->area_.get();
     45   }
     46   DOMStorageArea* area;
     47   if (namespace_id_ == kLocalStorageNamespaceId) {
     48     area = new DOMStorageArea(origin, directory_, task_runner_.get());
     49   } else {
     50     area = new DOMStorageArea(
     51         namespace_id_, persistent_namespace_id_, origin,
     52         session_storage_database_.get(), task_runner_.get());
     53   }
     54   areas_[origin] = AreaHolder(area, 1);
     55   return area;
     56 }
     57 
     58 void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
     59   AreaHolder* holder = GetAreaHolder(area->origin());
     60   DCHECK(holder);
     61   DCHECK_EQ(holder->area_.get(), area);
     62   --(holder->open_count_);
     63   // TODO(michaeln): Clean up areas that aren't needed in memory anymore.
     64   // The in-process-webkit based impl didn't do this either, but would be nice.
     65 }
     66 
     67 DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
     68   AreaHolder* holder = GetAreaHolder(origin);
     69   if (holder && holder->open_count_)
     70     return holder->area_.get();
     71   return NULL;
     72 }
     73 
     74 DOMStorageNamespace* DOMStorageNamespace::Clone(
     75     int64 clone_namespace_id,
     76     const std::string& clone_persistent_namespace_id) {
     77   DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
     78   DCHECK_NE(kLocalStorageNamespaceId, clone_namespace_id);
     79   DOMStorageNamespace* clone = new DOMStorageNamespace(
     80       clone_namespace_id, clone_persistent_namespace_id,
     81       session_storage_database_.get(), task_runner_.get());
     82   AreaMap::const_iterator it = areas_.begin();
     83   // Clone the in-memory structures.
     84   for (; it != areas_.end(); ++it) {
     85     DOMStorageArea* area = it->second.area_->ShallowCopy(
     86         clone_namespace_id, clone_persistent_namespace_id);
     87     clone->areas_[it->first] = AreaHolder(area, 0);
     88   }
     89   // And clone the on-disk structures, too.
     90   if (session_storage_database_.get()) {
     91     task_runner_->PostShutdownBlockingTask(
     92         FROM_HERE,
     93         DOMStorageTaskRunner::COMMIT_SEQUENCE,
     94         base::Bind(base::IgnoreResult(&SessionStorageDatabase::CloneNamespace),
     95                    session_storage_database_.get(), persistent_namespace_id_,
     96                    clone_persistent_namespace_id));
     97   }
     98   return clone;
     99 }
    100 
    101 void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
    102   DCHECK(!session_storage_database_.get());
    103   AreaHolder* holder = GetAreaHolder(origin);
    104   if (holder) {
    105     holder->area_->DeleteOrigin();
    106     return;
    107   }
    108   if (!directory_.empty()) {
    109     scoped_refptr<DOMStorageArea> area =
    110         new DOMStorageArea(origin, directory_, task_runner_.get());
    111     area->DeleteOrigin();
    112   }
    113 }
    114 
    115 void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
    116   DOMStorageArea* area = OpenStorageArea(origin);
    117   area->FastClear();
    118   CloseStorageArea(area);
    119 }
    120 
    121 void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
    122   if (directory_.empty())
    123     return;  // We can't purge w/o backing on disk.
    124   AreaMap::iterator it = areas_.begin();
    125   while (it != areas_.end()) {
    126     // Leave it alone if changes are pending
    127     if (it->second.area_->HasUncommittedChanges()) {
    128       ++it;
    129       continue;
    130     }
    131 
    132     // If not in use, we can shut it down and remove
    133     // it from our collection entirely.
    134     if (it->second.open_count_ == 0) {
    135       it->second.area_->Shutdown();
    136       areas_.erase(it++);
    137       continue;
    138     }
    139 
    140     if (option == PURGE_AGGRESSIVE) {
    141       // If aggressive is true, we clear caches and such
    142       // for opened areas.
    143       it->second.area_->PurgeMemory();
    144     }
    145 
    146     ++it;
    147   }
    148 }
    149 
    150 void DOMStorageNamespace::Shutdown() {
    151   AreaMap::const_iterator it = areas_.begin();
    152   for (; it != areas_.end(); ++it)
    153     it->second.area_->Shutdown();
    154 }
    155 
    156 unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
    157   unsigned int area_count = 0;
    158   for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
    159     if (it->second.area_->IsLoadedInMemory())
    160       ++area_count;
    161   }
    162   return area_count;
    163 }
    164 
    165 DOMStorageNamespace::AreaHolder*
    166 DOMStorageNamespace::GetAreaHolder(const GURL& origin) {
    167   AreaMap::iterator found = areas_.find(origin);
    168   if (found == areas_.end())
    169     return NULL;
    170   return &(found->second);
    171 }
    172 
    173 // AreaHolder
    174 
    175 DOMStorageNamespace::AreaHolder::AreaHolder()
    176     : open_count_(0) {
    177 }
    178 
    179 DOMStorageNamespace::AreaHolder::AreaHolder(
    180     DOMStorageArea* area, int count)
    181     : area_(area), open_count_(count) {
    182 }
    183 
    184 DOMStorageNamespace::AreaHolder::~AreaHolder() {
    185 }
    186 
    187 }  // namespace content
    188