dom/indexedDB/Client.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:8ec01ca85f16
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "Client.h"
8
9 #include "mozilla/dom/quota/QuotaManager.h"
10 #include "mozilla/dom/quota/UsageInfo.h"
11 #include "mozilla/dom/quota/Utilities.h"
12
13 #include "IDBDatabase.h"
14 #include "IndexedDatabaseManager.h"
15 #include "TransactionThreadPool.h"
16 #include "nsISimpleEnumerator.h"
17
18 USING_INDEXEDDB_NAMESPACE
19 using mozilla::dom::quota::AssertIsOnIOThread;
20 using mozilla::dom::quota::QuotaManager;
21
22 namespace {
23
24 bool
25 GetDatabaseBaseFilename(const nsAString& aFilename,
26 nsAString& aDatabaseBaseFilename)
27 {
28 NS_ASSERTION(!aFilename.IsEmpty(), "Bad argument!");
29
30 NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
31
32 if (!StringEndsWith(aFilename, sqlite)) {
33 return false;
34 }
35
36 aDatabaseBaseFilename =
37 Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
38
39 return true;
40 }
41
42 } // anonymous namespace
43
44 // This needs to be fully qualified to not confuse trace refcnt assertions.
45 NS_IMPL_ADDREF(mozilla::dom::indexedDB::Client)
46 NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client)
47
48 nsresult
49 Client::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
50 const nsACString& aOrigin, UsageInfo* aUsageInfo)
51 {
52 AssertIsOnIOThread();
53
54 nsCOMPtr<nsIFile> directory;
55 nsresult rv =
56 GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
57 NS_ENSURE_SUCCESS(rv, rv);
58
59 // We need to see if there are any files in the directory already. If they
60 // are database files then we need to cleanup stored files (if it's needed)
61 // and also get the usage.
62
63 nsAutoTArray<nsString, 20> subdirsToProcess;
64 nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
65 nsTHashtable<nsStringHashKey> validSubdirs(20);
66
67 nsCOMPtr<nsISimpleEnumerator> entries;
68 rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
69 NS_ENSURE_SUCCESS(rv, rv);
70
71 bool hasMore;
72 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
73 hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
74 nsCOMPtr<nsISupports> entry;
75 rv = entries->GetNext(getter_AddRefs(entry));
76 NS_ENSURE_SUCCESS(rv, rv);
77
78 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
79 NS_ENSURE_TRUE(file, NS_NOINTERFACE);
80
81 nsString leafName;
82 rv = file->GetLeafName(leafName);
83 NS_ENSURE_SUCCESS(rv, rv);
84
85 if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
86 continue;
87 }
88
89 if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
90 continue;
91 }
92
93 bool isDirectory;
94 rv = file->IsDirectory(&isDirectory);
95 NS_ENSURE_SUCCESS(rv, rv);
96
97 if (isDirectory) {
98 if (!validSubdirs.GetEntry(leafName)) {
99 subdirsToProcess.AppendElement(leafName);
100 }
101 continue;
102 }
103
104 nsString dbBaseFilename;
105 if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
106 unknownFiles.AppendElement(file);
107 continue;
108 }
109
110 nsCOMPtr<nsIFile> fmDirectory;
111 rv = directory->Clone(getter_AddRefs(fmDirectory));
112 NS_ENSURE_SUCCESS(rv, rv);
113
114 rv = fmDirectory->Append(dbBaseFilename);
115 NS_ENSURE_SUCCESS(rv, rv);
116
117 rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
118 aOrigin);
119 NS_ENSURE_SUCCESS(rv, rv);
120
121 if (aUsageInfo) {
122 int64_t fileSize;
123 rv = file->GetFileSize(&fileSize);
124 NS_ENSURE_SUCCESS(rv, rv);
125
126 NS_ASSERTION(fileSize >= 0, "Negative size?!");
127
128 aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
129
130 uint64_t usage;
131 rv = FileManager::GetUsage(fmDirectory, &usage);
132 NS_ENSURE_SUCCESS(rv, rv);
133
134 aUsageInfo->AppendToFileUsage(usage);
135 }
136
137 validSubdirs.PutEntry(dbBaseFilename);
138 }
139 NS_ENSURE_SUCCESS(rv, rv);
140
141 for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
142 const nsString& subdir = subdirsToProcess[i];
143 if (!validSubdirs.GetEntry(subdir)) {
144 NS_WARNING("Unknown subdirectory found!");
145 return NS_ERROR_UNEXPECTED;
146 }
147 }
148
149 for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
150 nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
151
152 // Some temporary SQLite files could disappear, so we have to check if the
153 // unknown file still exists.
154 bool exists;
155 rv = unknownFile->Exists(&exists);
156 NS_ENSURE_SUCCESS(rv, rv);
157
158 if (exists) {
159 nsString leafName;
160 unknownFile->GetLeafName(leafName);
161
162 // The journal file may exists even after db has been correctly opened.
163 if (!StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
164 NS_WARNING("Unknown file found!");
165 return NS_ERROR_UNEXPECTED;
166 }
167 }
168 }
169
170 return NS_OK;
171 }
172
173 nsresult
174 Client::GetUsageForOrigin(PersistenceType aPersistenceType,
175 const nsACString& aGroup, const nsACString& aOrigin,
176 UsageInfo* aUsageInfo)
177 {
178 AssertIsOnIOThread();
179 NS_ASSERTION(aUsageInfo, "Null pointer!");
180
181 nsCOMPtr<nsIFile> directory;
182 nsresult rv =
183 GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
184 NS_ENSURE_SUCCESS(rv, rv);
185
186 rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
187 NS_ENSURE_SUCCESS(rv, rv);
188
189 return NS_OK;
190 }
191
192 void
193 Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
194 const OriginOrPatternString& aOriginOrPattern)
195 {
196 AssertIsOnIOThread();
197
198 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
199 if (mgr) {
200 mgr->InvalidateFileManagers(aPersistenceType, aOriginOrPattern);
201 }
202 }
203
204 void
205 Client::ReleaseIOThreadObjects()
206 {
207 AssertIsOnIOThread();
208
209 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
210 if (mgr) {
211 mgr->InvalidateAllFileManagers();
212 }
213 }
214
215 bool
216 Client::IsTransactionServiceActivated()
217 {
218 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
219
220 return !!TransactionThreadPool::Get();
221 }
222
223 void
224 Client::WaitForStoragesToComplete(nsTArray<nsIOfflineStorage*>& aStorages,
225 nsIRunnable* aCallback)
226 {
227 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
228 NS_ASSERTION(!aStorages.IsEmpty(), "No storages to wait on!");
229 NS_ASSERTION(aCallback, "Passed null callback!");
230
231 TransactionThreadPool* pool = TransactionThreadPool::Get();
232 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
233
234 nsTArray<nsRefPtr<IDBDatabase> > databases(aStorages.Length());
235 for (uint32_t index = 0; index < aStorages.Length(); index++) {
236 IDBDatabase* database = IDBDatabase::FromStorage(aStorages[index]);
237 if (!database) {
238 MOZ_CRASH();
239 }
240
241 databases.AppendElement(database);
242 }
243
244 pool->WaitForDatabasesToComplete(databases, aCallback);
245 }
246
247 void
248 Client::AbortTransactionsForStorage(nsIOfflineStorage* aStorage)
249 {
250 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
251 NS_ASSERTION(aStorage, "Passed null storage!");
252
253 TransactionThreadPool* pool = TransactionThreadPool::Get();
254 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
255
256 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
257 NS_ASSERTION(database, "This shouldn't be null!");
258
259 pool->AbortTransactionsForDatabase(database);
260 }
261
262 bool
263 Client::HasTransactionsForStorage(nsIOfflineStorage* aStorage)
264 {
265 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
266
267 TransactionThreadPool* pool = TransactionThreadPool::Get();
268 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
269
270 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
271 NS_ASSERTION(database, "This shouldn't be null!");
272
273 return pool->HasTransactionsForDatabase(database);
274 }
275
276 void
277 Client::ShutdownTransactionService()
278 {
279 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
280
281 TransactionThreadPool::Shutdown();
282 }
283
284 nsresult
285 Client::GetDirectory(PersistenceType aPersistenceType,
286 const nsACString& aOrigin, nsIFile** aDirectory)
287 {
288 QuotaManager* quotaManager = QuotaManager::Get();
289 NS_ASSERTION(quotaManager, "This should never fail!");
290
291 nsCOMPtr<nsIFile> directory;
292 nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
293 getter_AddRefs(directory));
294 NS_ENSURE_SUCCESS(rv, rv);
295
296 NS_ASSERTION(directory, "What?");
297
298 rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
299 NS_ENSURE_SUCCESS(rv, rv);
300
301 directory.forget(aDirectory);
302 return NS_OK;
303 }
304
305 nsresult
306 Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
307 UsageInfo* aUsageInfo,
308 bool aDatabaseFiles)
309 {
310 NS_ASSERTION(aDirectory, "Null pointer!");
311 NS_ASSERTION(aUsageInfo, "Null pointer!");
312
313 nsCOMPtr<nsISimpleEnumerator> entries;
314 nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
315 NS_ENSURE_SUCCESS(rv, rv);
316
317 if (!entries) {
318 return NS_OK;
319 }
320
321 bool hasMore;
322 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
323 hasMore && !aUsageInfo->Canceled()) {
324 nsCOMPtr<nsISupports> entry;
325 rv = entries->GetNext(getter_AddRefs(entry));
326 NS_ENSURE_SUCCESS(rv, rv);
327
328 nsCOMPtr<nsIFile> file(do_QueryInterface(entry));
329 NS_ASSERTION(file, "Don't know what this is!");
330
331 bool isDirectory;
332 rv = file->IsDirectory(&isDirectory);
333 NS_ENSURE_SUCCESS(rv, rv);
334
335 if (isDirectory) {
336 if (aDatabaseFiles) {
337 rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
338 NS_ENSURE_SUCCESS(rv, rv);
339 }
340 else {
341 nsString leafName;
342 rv = file->GetLeafName(leafName);
343 NS_ENSURE_SUCCESS(rv, rv);
344
345 if (!leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
346 NS_WARNING("Unknown directory found!");
347 }
348 }
349
350 continue;
351 }
352
353 int64_t fileSize;
354 rv = file->GetFileSize(&fileSize);
355 NS_ENSURE_SUCCESS(rv, rv);
356
357 NS_ASSERTION(fileSize >= 0, "Negative size?!");
358
359 if (aDatabaseFiles) {
360 aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
361 }
362 else {
363 aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
364 }
365 }
366 NS_ENSURE_SUCCESS(rv, rv);
367
368 return NS_OK;
369 }

mercurial