1 // Copyright (c) 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/indexed_db/indexed_db_factory.h"
7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/time/time.h"
10 #include "content/browser/indexed_db/indexed_db_backing_store.h"
11 #include "content/browser/indexed_db/indexed_db_tracing.h"
12 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
13 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
17 const int64 kBackingStoreGracePeriodMs
= 2000;
19 static std::string
ComputeFileIdentifier(const std::string
& origin_identifier
) {
20 return origin_identifier
+ "@1";
23 IndexedDBFactory::IndexedDBFactory() {}
25 IndexedDBFactory::~IndexedDBFactory() {}
27 void IndexedDBFactory::ReleaseDatabase(
28 const IndexedDBDatabase::Identifier
& identifier
,
30 DCHECK(database_map_
.find(identifier
) != database_map_
.end());
31 std::string backing_store_identifier
=
32 database_map_
[identifier
]->backing_store()->identifier();
33 database_map_
.erase(identifier
);
35 // No grace period on a forced-close, as the initiator is
36 // assuming the backing store will be released once all
37 // connections are closed.
38 ReleaseBackingStore(backing_store_identifier
, forcedClose
);
41 void IndexedDBFactory::ReleaseBackingStore(const std::string
& identifier
,
43 // Only close if this is the last reference.
44 if (!HasLastBackingStoreReference(identifier
))
48 CloseBackingStore(identifier
);
52 DCHECK(!backing_store_map_
[identifier
]->close_timer()->IsRunning());
53 backing_store_map_
[identifier
]->close_timer()->Start(
55 base::TimeDelta::FromMilliseconds(kBackingStoreGracePeriodMs
),
56 base::Bind(&IndexedDBFactory::MaybeCloseBackingStore
, this, identifier
));
59 void IndexedDBFactory::MaybeCloseBackingStore(const std::string
& identifier
) {
60 // Another reference may have opened since the maybe-close was posted,
61 // so it is necessary to check again.
62 if (HasLastBackingStoreReference(identifier
))
63 CloseBackingStore(identifier
);
66 void IndexedDBFactory::CloseBackingStore(const std::string
& identifier
) {
67 backing_store_map_
.erase(identifier
);
70 bool IndexedDBFactory::HasLastBackingStoreReference(
71 const std::string
& identifier
) const {
72 IndexedDBBackingStore
* ptr
;
74 // Scope so that the implicit scoped_refptr<> is freed.
75 IndexedDBBackingStoreMap::const_iterator it
=
76 backing_store_map_
.find(identifier
);
77 DCHECK(it
!= backing_store_map_
.end());
78 ptr
= it
->second
.get();
80 return ptr
->HasOneRef();
83 void IndexedDBFactory::GetDatabaseNames(
84 scoped_refptr
<IndexedDBCallbacks
> callbacks
,
85 const std::string
& origin_identifier
,
86 const base::FilePath
& data_directory
) {
87 IDB_TRACE("IndexedDBFactory::GetDatabaseNames");
88 // TODO(dgrogan): Plumb data_loss back to script eventually?
89 WebKit::WebIDBCallbacks::DataLoss data_loss
;
91 scoped_refptr
<IndexedDBBackingStore
> backing_store
= OpenBackingStore(
92 origin_identifier
, data_directory
, &data_loss
, &disk_full
);
95 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError
,
96 "Internal error opening backing store for "
97 "indexedDB.webkitGetDatabaseNames."));
101 callbacks
->OnSuccess(backing_store
->GetDatabaseNames());
104 void IndexedDBFactory::DeleteDatabase(
105 const string16
& name
,
106 scoped_refptr
<IndexedDBCallbacks
> callbacks
,
107 const std::string
& origin_identifier
,
108 const base::FilePath
& data_directory
) {
109 IDB_TRACE("IndexedDBFactory::DeleteDatabase");
110 IndexedDBDatabase::Identifier
unique_identifier(origin_identifier
, name
);
111 IndexedDBDatabaseMap::iterator it
= database_map_
.find(unique_identifier
);
112 if (it
!= database_map_
.end()) {
113 // If there are any connections to the database, directly delete the
115 it
->second
->DeleteDatabase(callbacks
);
119 // TODO(dgrogan): Plumb data_loss back to script eventually?
120 WebKit::WebIDBCallbacks::DataLoss data_loss
;
121 bool disk_full
= false;
122 scoped_refptr
<IndexedDBBackingStore
> backing_store
= OpenBackingStore(
123 origin_identifier
, data_directory
, &data_loss
, &disk_full
);
124 if (!backing_store
) {
126 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError
,
128 "Internal error opening backing store "
129 "for indexedDB.deleteDatabase.")));
133 scoped_refptr
<IndexedDBDatabase
> database
=
134 IndexedDBDatabase::Create(name
, backing_store
, this, unique_identifier
);
136 callbacks
->OnError(IndexedDBDatabaseError(
137 WebKit::WebIDBDatabaseExceptionUnknownError
,
139 "Internal error creating database backend for "
140 "indexedDB.deleteDatabase.")));
144 database_map_
[unique_identifier
] = database
;
145 database
->DeleteDatabase(callbacks
);
146 database_map_
.erase(unique_identifier
);
149 scoped_refptr
<IndexedDBBackingStore
> IndexedDBFactory::OpenBackingStore(
150 const std::string
& origin_identifier
,
151 const base::FilePath
& data_directory
,
152 WebKit::WebIDBCallbacks::DataLoss
* data_loss
,
154 const std::string file_identifier
= ComputeFileIdentifier(origin_identifier
);
155 const bool open_in_memory
= data_directory
.empty();
157 IndexedDBBackingStoreMap::iterator it2
=
158 backing_store_map_
.find(file_identifier
);
159 if (it2
!= backing_store_map_
.end()) {
160 it2
->second
->close_timer()->Stop();
164 scoped_refptr
<IndexedDBBackingStore
> backing_store
;
165 if (open_in_memory
) {
166 backing_store
= IndexedDBBackingStore::OpenInMemory(file_identifier
);
168 backing_store
= IndexedDBBackingStore::Open(origin_identifier
,
175 if (backing_store
.get()) {
176 backing_store_map_
[file_identifier
] = backing_store
;
177 // If an in-memory database, bind lifetime to this factory instance.
179 session_only_backing_stores_
.insert(backing_store
);
181 // All backing stores associated with this factory should be of the same
183 DCHECK(session_only_backing_stores_
.empty() || open_in_memory
);
185 return backing_store
;
191 void IndexedDBFactory::Open(
192 const string16
& name
,
194 int64 transaction_id
,
195 scoped_refptr
<IndexedDBCallbacks
> callbacks
,
196 scoped_refptr
<IndexedDBDatabaseCallbacks
> database_callbacks
,
197 const std::string
& origin_identifier
,
198 const base::FilePath
& data_directory
) {
199 IDB_TRACE("IndexedDBFactory::Open");
200 scoped_refptr
<IndexedDBDatabase
> database
;
201 IndexedDBDatabase::Identifier
unique_identifier(origin_identifier
, name
);
202 IndexedDBDatabaseMap::iterator it
= database_map_
.find(unique_identifier
);
203 WebKit::WebIDBCallbacks::DataLoss data_loss
=
204 WebKit::WebIDBCallbacks::DataLossNone
;
205 bool disk_full
= false;
206 if (it
== database_map_
.end()) {
207 scoped_refptr
<IndexedDBBackingStore
> backing_store
= OpenBackingStore(
208 origin_identifier
, data_directory
, &data_loss
, &disk_full
);
209 if (!backing_store
) {
212 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionQuotaError
,
214 "Encountered full disk while opening "
215 "backing store for indexedDB.open.")));
218 callbacks
->OnError(IndexedDBDatabaseError(
219 WebKit::WebIDBDatabaseExceptionUnknownError
,
221 "Internal error opening backing store for indexedDB.open.")));
226 IndexedDBDatabase::Create(name
, backing_store
, this, unique_identifier
);
228 callbacks
->OnError(IndexedDBDatabaseError(
229 WebKit::WebIDBDatabaseExceptionUnknownError
,
231 "Internal error creating database backend for indexedDB.open.")));
235 database_map_
[unique_identifier
] = database
;
237 database
= it
->second
;
240 database
->OpenConnection(
241 callbacks
, database_callbacks
, transaction_id
, version
, data_loss
);
244 std::vector
<IndexedDBDatabase
*> IndexedDBFactory::GetOpenDatabasesForOrigin(
245 const std::string
& origin_identifier
) const {
246 std::vector
<IndexedDBDatabase
*> result
;
247 for (IndexedDBDatabaseMap::const_iterator it
= database_map_
.begin();
248 it
!= database_map_
.end();
250 if (it
->first
.first
== origin_identifier
)
251 result
.push_back(it
->second
.get());
256 } // namespace content