Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / indexedDB / Client.cpp
blob6157ed0d2605bfbfc4fb2658bccf1b7ae4af620b
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/. */
7 #include "Client.h"
9 #include "mozilla/dom/quota/QuotaManager.h"
10 #include "mozilla/dom/quota/UsageInfo.h"
11 #include "mozilla/dom/quota/Utilities.h"
13 #include "IDBDatabase.h"
14 #include "IndexedDatabaseManager.h"
15 #include "TransactionThreadPool.h"
16 #include "nsISimpleEnumerator.h"
18 USING_INDEXEDDB_NAMESPACE
19 using mozilla::dom::quota::AssertIsOnIOThread;
20 using mozilla::dom::quota::QuotaManager;
22 namespace {
24 bool
25 GetDatabaseBaseFilename(const nsAString& aFilename,
26 nsAString& aDatabaseBaseFilename)
28 NS_ASSERTION(!aFilename.IsEmpty(), "Bad argument!");
30 NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
32 if (!StringEndsWith(aFilename, sqlite)) {
33 return false;
36 aDatabaseBaseFilename =
37 Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
39 return true;
42 } // anonymous namespace
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)
48 nsresult
49 Client::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
50 const nsACString& aOrigin, UsageInfo* aUsageInfo)
52 AssertIsOnIOThread();
54 nsCOMPtr<nsIFile> directory;
55 nsresult rv =
56 GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
57 NS_ENSURE_SUCCESS(rv, rv);
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.
63 nsAutoTArray<nsString, 20> subdirsToProcess;
64 nsAutoTArray<nsCOMPtr<nsIFile>, 20> unknownFiles;
65 nsTHashtable<nsStringHashKey> validSubdirs(20);
67 nsCOMPtr<nsISimpleEnumerator> entries;
68 rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
69 NS_ENSURE_SUCCESS(rv, rv);
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);
78 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
79 NS_ENSURE_TRUE(file, NS_NOINTERFACE);
81 nsString leafName;
82 rv = file->GetLeafName(leafName);
83 NS_ENSURE_SUCCESS(rv, rv);
85 if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
86 continue;
89 if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
90 continue;
93 bool isDirectory;
94 rv = file->IsDirectory(&isDirectory);
95 NS_ENSURE_SUCCESS(rv, rv);
97 if (isDirectory) {
98 if (!validSubdirs.GetEntry(leafName)) {
99 subdirsToProcess.AppendElement(leafName);
101 continue;
104 nsString dbBaseFilename;
105 if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
106 unknownFiles.AppendElement(file);
107 continue;
110 nsCOMPtr<nsIFile> fmDirectory;
111 rv = directory->Clone(getter_AddRefs(fmDirectory));
112 NS_ENSURE_SUCCESS(rv, rv);
114 rv = fmDirectory->Append(dbBaseFilename);
115 NS_ENSURE_SUCCESS(rv, rv);
117 rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
118 aOrigin);
119 NS_ENSURE_SUCCESS(rv, rv);
121 if (aUsageInfo) {
122 int64_t fileSize;
123 rv = file->GetFileSize(&fileSize);
124 NS_ENSURE_SUCCESS(rv, rv);
126 NS_ASSERTION(fileSize >= 0, "Negative size?!");
128 aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
130 uint64_t usage;
131 rv = FileManager::GetUsage(fmDirectory, &usage);
132 NS_ENSURE_SUCCESS(rv, rv);
134 aUsageInfo->AppendToFileUsage(usage);
137 validSubdirs.PutEntry(dbBaseFilename);
139 NS_ENSURE_SUCCESS(rv, rv);
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;
149 for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
150 nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
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);
158 if (exists) {
159 nsString leafName;
160 unknownFile->GetLeafName(leafName);
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;
170 return NS_OK;
173 nsresult
174 Client::GetUsageForOrigin(PersistenceType aPersistenceType,
175 const nsACString& aGroup, const nsACString& aOrigin,
176 UsageInfo* aUsageInfo)
178 AssertIsOnIOThread();
179 NS_ASSERTION(aUsageInfo, "Null pointer!");
181 nsCOMPtr<nsIFile> directory;
182 nsresult rv =
183 GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
184 NS_ENSURE_SUCCESS(rv, rv);
186 rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
187 NS_ENSURE_SUCCESS(rv, rv);
189 return NS_OK;
192 void
193 Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
194 const OriginOrPatternString& aOriginOrPattern)
196 AssertIsOnIOThread();
198 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
199 if (mgr) {
200 mgr->InvalidateFileManagers(aPersistenceType, aOriginOrPattern);
204 void
205 Client::ReleaseIOThreadObjects()
207 AssertIsOnIOThread();
209 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
210 if (mgr) {
211 mgr->InvalidateAllFileManagers();
215 bool
216 Client::IsTransactionServiceActivated()
218 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
220 return !!TransactionThreadPool::Get();
223 void
224 Client::WaitForStoragesToComplete(nsTArray<nsIOfflineStorage*>& aStorages,
225 nsIRunnable* aCallback)
227 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
228 NS_ASSERTION(!aStorages.IsEmpty(), "No storages to wait on!");
229 NS_ASSERTION(aCallback, "Passed null callback!");
231 TransactionThreadPool* pool = TransactionThreadPool::Get();
232 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
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();
241 databases.AppendElement(database);
244 pool->WaitForDatabasesToComplete(databases, aCallback);
247 void
248 Client::AbortTransactionsForStorage(nsIOfflineStorage* aStorage)
250 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
251 NS_ASSERTION(aStorage, "Passed null storage!");
253 TransactionThreadPool* pool = TransactionThreadPool::Get();
254 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
256 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
257 NS_ASSERTION(database, "This shouldn't be null!");
259 pool->AbortTransactionsForDatabase(database);
262 bool
263 Client::HasTransactionsForStorage(nsIOfflineStorage* aStorage)
265 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
267 TransactionThreadPool* pool = TransactionThreadPool::Get();
268 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
270 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
271 NS_ASSERTION(database, "This shouldn't be null!");
273 return pool->HasTransactionsForDatabase(database);
276 void
277 Client::ShutdownTransactionService()
279 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
281 TransactionThreadPool::Shutdown();
284 nsresult
285 Client::GetDirectory(PersistenceType aPersistenceType,
286 const nsACString& aOrigin, nsIFile** aDirectory)
288 QuotaManager* quotaManager = QuotaManager::Get();
289 NS_ASSERTION(quotaManager, "This should never fail!");
291 nsCOMPtr<nsIFile> directory;
292 nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
293 getter_AddRefs(directory));
294 NS_ENSURE_SUCCESS(rv, rv);
296 NS_ASSERTION(directory, "What?");
298 rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
299 NS_ENSURE_SUCCESS(rv, rv);
301 directory.forget(aDirectory);
302 return NS_OK;
305 nsresult
306 Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
307 UsageInfo* aUsageInfo,
308 bool aDatabaseFiles)
310 NS_ASSERTION(aDirectory, "Null pointer!");
311 NS_ASSERTION(aUsageInfo, "Null pointer!");
313 nsCOMPtr<nsISimpleEnumerator> entries;
314 nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
315 NS_ENSURE_SUCCESS(rv, rv);
317 if (!entries) {
318 return NS_OK;
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);
328 nsCOMPtr<nsIFile> file(do_QueryInterface(entry));
329 NS_ASSERTION(file, "Don't know what this is!");
331 bool isDirectory;
332 rv = file->IsDirectory(&isDirectory);
333 NS_ENSURE_SUCCESS(rv, rv);
335 if (isDirectory) {
336 if (aDatabaseFiles) {
337 rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
338 NS_ENSURE_SUCCESS(rv, rv);
340 else {
341 nsString leafName;
342 rv = file->GetLeafName(leafName);
343 NS_ENSURE_SUCCESS(rv, rv);
345 if (!leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
346 NS_WARNING("Unknown directory found!");
350 continue;
353 int64_t fileSize;
354 rv = file->GetFileSize(&fileSize);
355 NS_ENSURE_SUCCESS(rv, rv);
357 NS_ASSERTION(fileSize >= 0, "Negative size?!");
359 if (aDatabaseFiles) {
360 aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
362 else {
363 aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
366 NS_ENSURE_SUCCESS(rv, rv);
368 return NS_OK;