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/. */
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
;
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
)) {
36 aDatabaseBaseFilename
=
37 Substring(aFilename
, 0, aFilename
.Length() - sqlite
.Length());
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
)
49 Client::InitOrigin(PersistenceType aPersistenceType
, const nsACString
& aGroup
,
50 const nsACString
& aOrigin
, UsageInfo
* aUsageInfo
)
54 nsCOMPtr
<nsIFile
> directory
;
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
);
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
);
82 rv
= file
->GetLeafName(leafName
);
83 NS_ENSURE_SUCCESS(rv
, rv
);
85 if (StringEndsWith(leafName
, NS_LITERAL_STRING(".sqlite-journal"))) {
89 if (leafName
.EqualsLiteral(DSSTORE_FILE_NAME
)) {
94 rv
= file
->IsDirectory(&isDirectory
);
95 NS_ENSURE_SUCCESS(rv
, rv
);
98 if (!validSubdirs
.GetEntry(leafName
)) {
99 subdirsToProcess
.AppendElement(leafName
);
104 nsString dbBaseFilename
;
105 if (!GetDatabaseBaseFilename(leafName
, dbBaseFilename
)) {
106 unknownFiles
.AppendElement(file
);
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
,
119 NS_ENSURE_SUCCESS(rv
, rv
);
123 rv
= file
->GetFileSize(&fileSize
);
124 NS_ENSURE_SUCCESS(rv
, rv
);
126 NS_ASSERTION(fileSize
>= 0, "Negative size?!");
128 aUsageInfo
->AppendToDatabaseUsage(uint64_t(fileSize
));
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.
155 rv
= unknownFile
->Exists(&exists
);
156 NS_ENSURE_SUCCESS(rv
, rv
);
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
;
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
;
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
);
193 Client::OnOriginClearCompleted(PersistenceType aPersistenceType
,
194 const OriginOrPatternString
& aOriginOrPattern
)
196 AssertIsOnIOThread();
198 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::Get();
200 mgr
->InvalidateFileManagers(aPersistenceType
, aOriginOrPattern
);
205 Client::ReleaseIOThreadObjects()
207 AssertIsOnIOThread();
209 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::Get();
211 mgr
->InvalidateAllFileManagers();
216 Client::IsTransactionServiceActivated()
218 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
220 return !!TransactionThreadPool::Get();
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
]);
241 databases
.AppendElement(database
);
244 pool
->WaitForDatabasesToComplete(databases
, aCallback
);
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
);
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
);
277 Client::ShutdownTransactionService()
279 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
281 TransactionThreadPool::Shutdown();
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
);
306 Client::GetUsageForDirectoryInternal(nsIFile
* aDirectory
,
307 UsageInfo
* aUsageInfo
,
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
);
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!");
332 rv
= file
->IsDirectory(&isDirectory
);
333 NS_ENSURE_SUCCESS(rv
, rv
);
336 if (aDatabaseFiles
) {
337 rv
= GetUsageForDirectoryInternal(file
, aUsageInfo
, false);
338 NS_ENSURE_SUCCESS(rv
, rv
);
342 rv
= file
->GetLeafName(leafName
);
343 NS_ENSURE_SUCCESS(rv
, rv
);
345 if (!leafName
.EqualsLiteral(JOURNAL_DIRECTORY_NAME
)) {
346 NS_WARNING("Unknown directory found!");
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
));
363 aUsageInfo
->AppendToFileUsage(uint64_t(fileSize
));
366 NS_ENSURE_SUCCESS(rv
, rv
);