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.
5 #include "content/browser/dom_storage/dom_storage_namespace.h"
7 #include "base/basictypes.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"
18 DOMStorageNamespace::DOMStorageNamespace(
19 const base::FilePath
& directory
,
20 DOMStorageTaskRunner
* task_runner
)
21 : namespace_id_(kLocalStorageNamespaceId
),
22 directory_(directory
),
23 task_runner_(task_runner
) {
26 DOMStorageNamespace::DOMStorageNamespace(
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
);
38 DOMStorageNamespace::~DOMStorageNamespace() {
41 DOMStorageArea
* DOMStorageNamespace::OpenStorageArea(const GURL
& origin
) {
42 if (AreaHolder
* holder
= GetAreaHolder(origin
)) {
43 ++(holder
->open_count_
);
44 return holder
->area_
.get();
47 if (namespace_id_
== kLocalStorageNamespaceId
) {
48 area
= new DOMStorageArea(origin
, directory_
, task_runner_
.get());
50 area
= new DOMStorageArea(
51 namespace_id_
, persistent_namespace_id_
, origin
,
52 session_storage_database_
.get(), task_runner_
.get());
54 areas_
[origin
] = AreaHolder(area
, 1);
58 void DOMStorageNamespace::CloseStorageArea(DOMStorageArea
* area
) {
59 AreaHolder
* holder
= GetAreaHolder(area
->origin());
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.
67 DOMStorageArea
* DOMStorageNamespace::GetOpenStorageArea(const GURL
& origin
) {
68 AreaHolder
* holder
= GetAreaHolder(origin
);
69 if (holder
&& holder
->open_count_
)
70 return holder
->area_
.get();
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);
89 // And clone the on-disk structures, too.
90 if (session_storage_database_
.get()) {
91 task_runner_
->PostShutdownBlockingTask(
93 DOMStorageTaskRunner::COMMIT_SEQUENCE
,
94 base::Bind(base::IgnoreResult(&SessionStorageDatabase::CloneNamespace
),
95 session_storage_database_
.get(), persistent_namespace_id_
,
96 clone_persistent_namespace_id
));
101 void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL
& origin
) {
102 DCHECK(!session_storage_database_
.get());
103 AreaHolder
* holder
= GetAreaHolder(origin
);
105 holder
->area_
->DeleteOrigin();
108 if (!directory_
.empty()) {
109 scoped_refptr
<DOMStorageArea
> area
=
110 new DOMStorageArea(origin
, directory_
, task_runner_
.get());
111 area
->DeleteOrigin();
115 void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL
& origin
) {
116 DOMStorageArea
* area
= OpenStorageArea(origin
);
118 CloseStorageArea(area
);
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 const AreaHolder
& holder
= it
->second
;
128 // We can't purge if there are changes pending.
129 if (holder
.area_
->HasUncommittedChanges()) {
130 if (holder
.open_count_
== 0) {
131 // Schedule an immediate commit so the next time we're asked to purge,
132 // we can drop it from memory.
133 holder
.area_
->ScheduleImmediateCommit();
139 // If not in use, we can shut it down and remove
140 // it from our collection entirely.
141 if (holder
.open_count_
== 0) {
142 holder
.area_
->Shutdown();
147 if (option
== PURGE_AGGRESSIVE
) {
148 // If aggressive is true, we clear caches and such
150 holder
.area_
->PurgeMemory();
157 void DOMStorageNamespace::Shutdown() {
158 AreaMap::const_iterator it
= areas_
.begin();
159 for (; it
!= areas_
.end(); ++it
)
160 it
->second
.area_
->Shutdown();
163 void DOMStorageNamespace::Flush() {
164 for (auto& entry
: areas_
) {
165 if (!entry
.second
.area_
->HasUncommittedChanges())
167 entry
.second
.area_
->ScheduleImmediateCommit();
171 unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
172 unsigned int area_count
= 0;
173 for (AreaMap::const_iterator it
= areas_
.begin(); it
!= areas_
.end(); ++it
) {
174 if (it
->second
.area_
->IsLoadedInMemory())
180 DOMStorageNamespace::AreaHolder
*
181 DOMStorageNamespace::GetAreaHolder(const GURL
& origin
) {
182 AreaMap::iterator found
= areas_
.find(origin
);
183 if (found
== areas_
.end())
185 return &(found
->second
);
190 DOMStorageNamespace::AreaHolder::AreaHolder()
194 DOMStorageNamespace::AreaHolder::AreaHolder(
195 DOMStorageArea
* area
, int count
)
196 : area_(area
), open_count_(count
) {
199 DOMStorageNamespace::AreaHolder::~AreaHolder() {
202 } // namespace content