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