Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / indexedDB / IndexedDatabaseManager.cpp
blob3f4010d55767b704c278170c39dea2576d00b4d9
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "IndexedDatabaseManager.h"
9 #include "nsIConsoleService.h"
10 #include "nsIDiskSpaceWatcher.h"
11 #include "nsIFile.h"
12 #include "nsIObserverService.h"
13 #include "nsIScriptError.h"
15 #include "jsapi.h"
16 #include "mozilla/ClearOnShutdown.h"
17 #include "mozilla/CondVar.h"
18 #include "mozilla/ContentEvents.h"
19 #include "mozilla/dom/ErrorEventBinding.h"
20 #include "mozilla/dom/quota/OriginOrPatternString.h"
21 #include "mozilla/dom/quota/QuotaManager.h"
22 #include "mozilla/dom/quota/Utilities.h"
23 #include "mozilla/dom/TabContext.h"
24 #include "mozilla/EventDispatcher.h"
25 #include "mozilla/Services.h"
26 #include "mozilla/Preferences.h"
27 #include "mozilla/storage.h"
28 #include "nsContentUtils.h"
29 #include "nsThreadUtils.h"
31 #include "IDBEvents.h"
32 #include "IDBFactory.h"
33 #include "IDBKeyRange.h"
34 #include "IDBRequest.h"
36 // Bindings for ResolveConstructors
37 #include "mozilla/dom/IDBCursorBinding.h"
38 #include "mozilla/dom/IDBDatabaseBinding.h"
39 #include "mozilla/dom/IDBFactoryBinding.h"
40 #include "mozilla/dom/IDBIndexBinding.h"
41 #include "mozilla/dom/IDBKeyRangeBinding.h"
42 #include "mozilla/dom/IDBMutableFileBinding.h"
43 #include "mozilla/dom/IDBObjectStoreBinding.h"
44 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
45 #include "mozilla/dom/IDBRequestBinding.h"
46 #include "mozilla/dom/IDBTransactionBinding.h"
47 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
49 #define IDB_STR "indexedDB"
51 // The two possible values for the data argument when receiving the disk space
52 // observer notification.
53 #define LOW_DISK_SPACE_DATA_FULL "full"
54 #define LOW_DISK_SPACE_DATA_FREE "free"
56 USING_INDEXEDDB_NAMESPACE
57 using namespace mozilla;
58 using namespace mozilla::dom;
59 USING_QUOTA_NAMESPACE
61 BEGIN_INDEXEDDB_NAMESPACE
63 class FileManagerInfo
65 public:
66 already_AddRefed<FileManager>
67 GetFileManager(PersistenceType aPersistenceType,
68 const nsAString& aName) const;
70 void
71 AddFileManager(FileManager* aFileManager);
73 bool
74 HasFileManagers() const
76 AssertIsOnIOThread();
78 return !mPersistentStorageFileManagers.IsEmpty() ||
79 !mTemporaryStorageFileManagers.IsEmpty();
82 void
83 InvalidateAllFileManagers() const;
85 void
86 InvalidateAndRemoveFileManagers(PersistenceType aPersistenceType);
88 void
89 InvalidateAndRemoveFileManager(PersistenceType aPersistenceType,
90 const nsAString& aName);
92 private:
93 nsTArray<nsRefPtr<FileManager> >&
94 GetArray(PersistenceType aPersistenceType);
96 const nsTArray<nsRefPtr<FileManager> >&
97 GetImmutableArray(PersistenceType aPersistenceType) const
99 return const_cast<FileManagerInfo*>(this)->GetArray(aPersistenceType);
102 nsTArray<nsRefPtr<FileManager> > mPersistentStorageFileManagers;
103 nsTArray<nsRefPtr<FileManager> > mTemporaryStorageFileManagers;
106 END_INDEXEDDB_NAMESPACE
108 namespace {
110 mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager;
112 mozilla::Atomic<bool> gInitialized(false);
113 mozilla::Atomic<bool> gClosed(false);
115 class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
117 public:
118 NS_DECL_THREADSAFE_ISUPPORTS
119 NS_DECL_NSIRUNNABLE
121 AsyncDeleteFileRunnable(FileManager* aFileManager, int64_t aFileId);
123 private:
124 ~AsyncDeleteFileRunnable() {}
126 nsRefPtr<FileManager> mFileManager;
127 int64_t mFileId;
130 class GetFileReferencesHelper MOZ_FINAL : public nsIRunnable
132 public:
133 NS_DECL_THREADSAFE_ISUPPORTS
134 NS_DECL_NSIRUNNABLE
136 GetFileReferencesHelper(PersistenceType aPersistenceType,
137 const nsACString& aOrigin,
138 const nsAString& aDatabaseName,
139 int64_t aFileId)
140 : mPersistenceType(aPersistenceType),
141 mOrigin(aOrigin),
142 mDatabaseName(aDatabaseName),
143 mFileId(aFileId),
144 mMutex(IndexedDatabaseManager::FileMutex()),
145 mCondVar(mMutex, "GetFileReferencesHelper::mCondVar"),
146 mMemRefCnt(-1),
147 mDBRefCnt(-1),
148 mSliceRefCnt(-1),
149 mResult(false),
150 mWaiting(true)
153 nsresult
154 DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
155 int32_t* aDBRefCnt,
156 int32_t* aSliceRefCnt,
157 bool* aResult);
159 private:
160 ~GetFileReferencesHelper() {}
162 PersistenceType mPersistenceType;
163 nsCString mOrigin;
164 nsString mDatabaseName;
165 int64_t mFileId;
167 mozilla::Mutex& mMutex;
168 mozilla::CondVar mCondVar;
169 int32_t mMemRefCnt;
170 int32_t mDBRefCnt;
171 int32_t mSliceRefCnt;
172 bool mResult;
173 bool mWaiting;
176 struct MOZ_STACK_CLASS InvalidateInfo
178 InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
179 : persistenceType(aPersistenceType), pattern(aPattern)
182 PersistenceType persistenceType;
183 const nsACString& pattern;
186 } // anonymous namespace
188 IndexedDatabaseManager::IndexedDatabaseManager()
189 : mFileMutex("IndexedDatabaseManager.mFileMutex")
191 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
194 IndexedDatabaseManager::~IndexedDatabaseManager()
196 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
199 bool IndexedDatabaseManager::sIsMainProcess = false;
200 mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
202 // static
203 IndexedDatabaseManager*
204 IndexedDatabaseManager::GetOrCreate()
206 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
208 if (IsClosed()) {
209 NS_ERROR("Calling GetOrCreate() after shutdown!");
210 return nullptr;
213 if (!gDBManager) {
214 sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default;
216 if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
217 // See if we're starting up in low disk space conditions.
218 nsCOMPtr<nsIDiskSpaceWatcher> watcher =
219 do_GetService(DISKSPACEWATCHER_CONTRACTID);
220 if (watcher) {
221 bool isDiskFull;
222 if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) {
223 sLowDiskSpaceMode = isDiskFull;
225 else {
226 NS_WARNING("GetIsDiskFull failed!");
229 else {
230 NS_WARNING("No disk space watcher component available!");
234 nsRefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
236 nsresult rv = instance->Init();
237 NS_ENSURE_SUCCESS(rv, nullptr);
239 if (gInitialized.exchange(true)) {
240 NS_ERROR("Initialized more than once?!");
243 gDBManager = instance;
245 ClearOnShutdown(&gDBManager);
248 return gDBManager;
251 // static
252 IndexedDatabaseManager*
253 IndexedDatabaseManager::Get()
255 // Does not return an owning reference.
256 return gDBManager;
259 nsresult
260 IndexedDatabaseManager::Init()
262 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
264 // Make sure that the quota manager is up.
265 QuotaManager* qm = QuotaManager::GetOrCreate();
266 NS_ENSURE_STATE(qm);
268 // During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
269 // directly.
270 if (sIsMainProcess) {
271 // Must initialize the storage service on the main thread.
272 nsCOMPtr<mozIStorageService> ss =
273 do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
274 NS_ENSURE_STATE(ss);
276 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
277 NS_ENSURE_STATE(obs);
279 nsresult rv =
280 obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
281 NS_ENSURE_SUCCESS(rv, rv);
284 return NS_OK;
287 void
288 IndexedDatabaseManager::Destroy()
290 // Setting the closed flag prevents the service from being recreated.
291 // Don't set it though if there's no real instance created.
292 if (gInitialized && gClosed.exchange(true)) {
293 NS_ERROR("Shutdown more than once?!");
296 delete this;
299 // static
300 nsresult
301 IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
302 EventChainPostVisitor& aVisitor)
304 NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
305 if (!aOwner) {
306 return NS_OK;
309 if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
310 return NS_OK;
313 nsString type;
314 nsresult rv = aVisitor.mDOMEvent->GetType(type);
315 NS_ENSURE_SUCCESS(rv, rv);
317 if (!type.EqualsLiteral(ERROR_EVT_STR)) {
318 return NS_OK;
321 nsCOMPtr<EventTarget> eventTarget =
322 aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
324 IDBRequest* request = static_cast<IDBRequest*>(eventTarget.get());
325 NS_ENSURE_TRUE(request, NS_ERROR_UNEXPECTED);
327 ErrorResult ret;
328 nsRefPtr<DOMError> error = request->GetError(ret);
329 if (ret.Failed()) {
330 return ret.ErrorCode();
333 nsString errorName;
334 if (error) {
335 error->GetName(errorName);
338 ThreadsafeAutoJSContext cx;
339 RootedDictionary<ErrorEventInit> init(cx);
340 request->FillScriptErrorEvent(init);
342 init.mMessage = errorName;
343 init.mCancelable = true;
344 init.mBubbles = true;
346 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aOwner));
347 NS_ASSERTION(sgo, "How can this happen?!");
349 nsEventStatus status = nsEventStatus_eIgnore;
350 if (NS_FAILED(sgo->HandleScriptError(init, &status))) {
351 NS_WARNING("Failed to dispatch script error event");
352 status = nsEventStatus_eIgnore;
355 bool preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
356 if (preventDefaultCalled) {
357 return NS_OK;
360 // Log an error to the error console.
361 nsCOMPtr<nsIScriptError> scriptError =
362 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
363 NS_ENSURE_SUCCESS(rv, rv);
365 if (NS_FAILED(scriptError->InitWithWindowID(errorName,
366 init.mFilename,
367 EmptyString(), init.mLineno,
368 0, 0,
369 "IndexedDB",
370 aOwner->WindowID()))) {
371 NS_WARNING("Failed to init script error!");
372 return NS_ERROR_FAILURE;
375 nsCOMPtr<nsIConsoleService> consoleService =
376 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
377 NS_ENSURE_SUCCESS(rv, rv);
379 return consoleService->LogMessage(scriptError);
382 // static
383 bool
384 IndexedDatabaseManager::TabContextMayAccessOrigin(const TabContext& aContext,
385 const nsACString& aOrigin)
387 NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
389 // If aContext is for a browser element, it's allowed only to access other
390 // browser elements. But if aContext is not for a browser element, it may
391 // access both browser and non-browser elements.
392 nsAutoCString pattern;
393 QuotaManager::GetOriginPatternStringMaybeIgnoreBrowser(
394 aContext.OwnOrContainingAppId(),
395 aContext.IsBrowserElement(),
396 pattern);
398 return PatternMatchesOrigin(pattern, aOrigin);
401 // static
402 bool
403 IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
404 JS::Handle<JSObject*> aGlobal)
406 MOZ_ASSERT(NS_IsMainThread());
407 MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
408 MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
409 "Passed object is not a global object!");
411 if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) ||
412 !IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) ||
413 !IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) ||
414 !IDBFactoryBinding::GetConstructorObject(aCx, aGlobal) ||
415 !IDBIndexBinding::GetConstructorObject(aCx, aGlobal) ||
416 !IDBKeyRangeBinding::GetConstructorObject(aCx, aGlobal) ||
417 !IDBMutableFileBinding::GetConstructorObject(aCx, aGlobal) ||
418 !IDBObjectStoreBinding::GetConstructorObject(aCx, aGlobal) ||
419 !IDBOpenDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
420 !IDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
421 !IDBTransactionBinding::GetConstructorObject(aCx, aGlobal) ||
422 !IDBVersionChangeEventBinding::GetConstructorObject(aCx, aGlobal))
424 return false;
427 nsRefPtr<IDBFactory> factory;
428 if (NS_FAILED(IDBFactory::Create(aCx, aGlobal, nullptr,
429 getter_AddRefs(factory)))) {
430 return false;
433 MOZ_ASSERT(factory, "This should never fail for chrome!");
435 JS::Rooted<JS::Value> indexedDB(aCx);
436 js::AssertSameCompartment(aCx, aGlobal);
437 if (!WrapNewBindingObject(aCx, factory, &indexedDB)) {
438 return false;
441 return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE);
444 // static
445 bool
446 IndexedDatabaseManager::IsClosed()
448 return gClosed;
451 #ifdef DEBUG
452 // static
453 bool
454 IndexedDatabaseManager::IsMainProcess()
456 NS_ASSERTION(gDBManager,
457 "IsMainProcess() called before indexedDB has been initialized!");
458 NS_ASSERTION((XRE_GetProcessType() == GeckoProcessType_Default) ==
459 sIsMainProcess, "XRE_GetProcessType changed its tune!");
460 return sIsMainProcess;
463 //static
464 bool
465 IndexedDatabaseManager::InLowDiskSpaceMode()
467 NS_ASSERTION(gDBManager,
468 "InLowDiskSpaceMode() called before indexedDB has been "
469 "initialized!");
470 return sLowDiskSpaceMode;
472 #endif
474 already_AddRefed<FileManager>
475 IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
476 const nsACString& aOrigin,
477 const nsAString& aDatabaseName)
479 AssertIsOnIOThread();
481 FileManagerInfo* info;
482 if (!mFileManagerInfos.Get(aOrigin, &info)) {
483 return nullptr;
486 nsRefPtr<FileManager> fileManager =
487 info->GetFileManager(aPersistenceType, aDatabaseName);
489 return fileManager.forget();
492 void
493 IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
495 AssertIsOnIOThread();
496 NS_ASSERTION(aFileManager, "Null file manager!");
498 FileManagerInfo* info;
499 if (!mFileManagerInfos.Get(aFileManager->Origin(), &info)) {
500 info = new FileManagerInfo();
501 mFileManagerInfos.Put(aFileManager->Origin(), info);
504 info->AddFileManager(aFileManager);
507 // static
508 PLDHashOperator
509 IndexedDatabaseManager::InvalidateAndRemoveFileManagers(
510 const nsACString& aKey,
511 nsAutoPtr<FileManagerInfo>& aValue,
512 void* aUserArg)
514 AssertIsOnIOThread();
515 NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
516 NS_ASSERTION(aValue, "Null pointer!");
518 if (!aUserArg) {
519 aValue->InvalidateAllFileManagers();
520 return PL_DHASH_REMOVE;
523 InvalidateInfo* info = static_cast<InvalidateInfo*>(aUserArg);
525 if (PatternMatchesOrigin(info->pattern, aKey)) {
526 aValue->InvalidateAndRemoveFileManagers(info->persistenceType);
528 if (!aValue->HasFileManagers()) {
529 return PL_DHASH_REMOVE;
533 return PL_DHASH_NEXT;
536 void
537 IndexedDatabaseManager::InvalidateAllFileManagers()
539 AssertIsOnIOThread();
541 mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
544 void
545 IndexedDatabaseManager::InvalidateFileManagers(
546 PersistenceType aPersistenceType,
547 const OriginOrPatternString& aOriginOrPattern)
549 AssertIsOnIOThread();
550 NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
552 if (aOriginOrPattern.IsOrigin()) {
553 FileManagerInfo* info;
554 if (!mFileManagerInfos.Get(aOriginOrPattern, &info)) {
555 return;
558 info->InvalidateAndRemoveFileManagers(aPersistenceType);
560 if (!info->HasFileManagers()) {
561 mFileManagerInfos.Remove(aOriginOrPattern);
564 else {
565 InvalidateInfo info(aPersistenceType, aOriginOrPattern);
566 mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, &info);
570 void
571 IndexedDatabaseManager::InvalidateFileManager(PersistenceType aPersistenceType,
572 const nsACString& aOrigin,
573 const nsAString& aDatabaseName)
575 AssertIsOnIOThread();
577 FileManagerInfo* info;
578 if (!mFileManagerInfos.Get(aOrigin, &info)) {
579 return;
582 info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
584 if (!info->HasFileManagers()) {
585 mFileManagerInfos.Remove(aOrigin);
589 nsresult
590 IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
591 int64_t aFileId)
593 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
595 NS_ENSURE_ARG_POINTER(aFileManager);
597 QuotaManager* quotaManager = QuotaManager::Get();
598 NS_ASSERTION(quotaManager, "Shouldn't be null!");
600 // See if we're currently clearing the storages for this origin. If so then
601 // we pretend that we've already deleted everything.
602 if (quotaManager->IsClearOriginPending(
603 aFileManager->Origin(),
604 Nullable<PersistenceType>(aFileManager->Type()))) {
605 return NS_OK;
608 nsRefPtr<AsyncDeleteFileRunnable> runnable =
609 new AsyncDeleteFileRunnable(aFileManager, aFileId);
611 nsresult rv =
612 quotaManager->IOThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
613 NS_ENSURE_SUCCESS(rv, rv);
615 return NS_OK;
618 nsresult
619 IndexedDatabaseManager::BlockAndGetFileReferences(
620 PersistenceType aPersistenceType,
621 const nsACString& aOrigin,
622 const nsAString& aDatabaseName,
623 int64_t aFileId,
624 int32_t* aRefCnt,
625 int32_t* aDBRefCnt,
626 int32_t* aSliceRefCnt,
627 bool* aResult)
629 nsRefPtr<GetFileReferencesHelper> helper =
630 new GetFileReferencesHelper(aPersistenceType, aOrigin, aDatabaseName,
631 aFileId);
633 nsresult rv = helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt,
634 aSliceRefCnt, aResult);
635 NS_ENSURE_SUCCESS(rv, rv);
637 return NS_OK;
640 NS_IMPL_ADDREF(IndexedDatabaseManager)
641 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
642 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver)
644 NS_IMETHODIMP
645 IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
646 const char16_t* aData)
648 NS_ASSERTION(IsMainProcess(), "Wrong process!");
649 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
651 if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) {
652 NS_ASSERTION(aData, "No data?!");
654 const nsDependentString data(aData);
656 if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) {
657 sLowDiskSpaceMode = true;
659 else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) {
660 sLowDiskSpaceMode = false;
662 else {
663 NS_NOTREACHED("Unknown data value!");
666 return NS_OK;
669 NS_NOTREACHED("Unknown topic!");
670 return NS_ERROR_UNEXPECTED;
673 already_AddRefed<FileManager>
674 FileManagerInfo::GetFileManager(PersistenceType aPersistenceType,
675 const nsAString& aName) const
677 AssertIsOnIOThread();
679 const nsTArray<nsRefPtr<FileManager> >& managers =
680 GetImmutableArray(aPersistenceType);
682 for (uint32_t i = 0; i < managers.Length(); i++) {
683 const nsRefPtr<FileManager>& fileManager = managers[i];
685 if (fileManager->DatabaseName() == aName) {
686 nsRefPtr<FileManager> result = fileManager;
687 return result.forget();
691 return nullptr;
694 void
695 FileManagerInfo::AddFileManager(FileManager* aFileManager)
697 AssertIsOnIOThread();
699 nsTArray<nsRefPtr<FileManager> >& managers = GetArray(aFileManager->Type());
701 NS_ASSERTION(!managers.Contains(aFileManager), "Adding more than once?!");
703 managers.AppendElement(aFileManager);
706 void
707 FileManagerInfo::InvalidateAllFileManagers() const
709 AssertIsOnIOThread();
711 uint32_t i;
713 for (i = 0; i < mPersistentStorageFileManagers.Length(); i++) {
714 mPersistentStorageFileManagers[i]->Invalidate();
717 for (i = 0; i < mTemporaryStorageFileManagers.Length(); i++) {
718 mTemporaryStorageFileManagers[i]->Invalidate();
722 void
723 FileManagerInfo::InvalidateAndRemoveFileManagers(
724 PersistenceType aPersistenceType)
726 AssertIsOnIOThread();
728 nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
730 for (uint32_t i = 0; i < managers.Length(); i++) {
731 managers[i]->Invalidate();
734 managers.Clear();
737 void
738 FileManagerInfo::InvalidateAndRemoveFileManager(
739 PersistenceType aPersistenceType,
740 const nsAString& aName)
742 AssertIsOnIOThread();
744 nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
746 for (uint32_t i = 0; i < managers.Length(); i++) {
747 nsRefPtr<FileManager>& fileManager = managers[i];
748 if (fileManager->DatabaseName() == aName) {
749 fileManager->Invalidate();
750 managers.RemoveElementAt(i);
751 return;
756 nsTArray<nsRefPtr<FileManager> >&
757 FileManagerInfo::GetArray(PersistenceType aPersistenceType)
759 switch (aPersistenceType) {
760 case PERSISTENCE_TYPE_PERSISTENT:
761 return mPersistentStorageFileManagers;
762 case PERSISTENCE_TYPE_TEMPORARY:
763 return mTemporaryStorageFileManagers;
765 case PERSISTENCE_TYPE_INVALID:
766 default:
767 MOZ_CRASH("Bad storage type value!");
768 return mPersistentStorageFileManagers;
772 AsyncDeleteFileRunnable::AsyncDeleteFileRunnable(FileManager* aFileManager,
773 int64_t aFileId)
774 : mFileManager(aFileManager), mFileId(aFileId)
778 NS_IMPL_ISUPPORTS(AsyncDeleteFileRunnable,
779 nsIRunnable)
781 NS_IMETHODIMP
782 AsyncDeleteFileRunnable::Run()
784 AssertIsOnIOThread();
786 nsCOMPtr<nsIFile> directory = mFileManager->GetDirectory();
787 NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
789 nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId);
790 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
792 nsresult rv;
793 int64_t fileSize;
795 if (mFileManager->Privilege() != Chrome) {
796 rv = file->GetFileSize(&fileSize);
797 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
800 rv = file->Remove(false);
801 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
803 if (mFileManager->Privilege() != Chrome) {
804 QuotaManager* quotaManager = QuotaManager::Get();
805 NS_ASSERTION(quotaManager, "Shouldn't be null!");
807 quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
808 mFileManager->Group(),
809 mFileManager->Origin(), fileSize);
812 directory = mFileManager->GetJournalDirectory();
813 NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
815 file = mFileManager->GetFileForId(directory, mFileId);
816 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
818 rv = file->Remove(false);
819 NS_ENSURE_SUCCESS(rv, rv);
821 return NS_OK;
824 nsresult
825 GetFileReferencesHelper::DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
826 int32_t* aDBRefCnt,
827 int32_t* aSliceRefCnt,
828 bool* aResult)
830 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
832 QuotaManager* quotaManager = QuotaManager::Get();
833 NS_ASSERTION(quotaManager, "Shouldn't be null!");
835 nsresult rv =
836 quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
837 NS_ENSURE_SUCCESS(rv, rv);
839 mozilla::MutexAutoLock autolock(mMutex);
840 while (mWaiting) {
841 mCondVar.Wait();
844 *aMemRefCnt = mMemRefCnt;
845 *aDBRefCnt = mDBRefCnt;
846 *aSliceRefCnt = mSliceRefCnt;
847 *aResult = mResult;
849 return NS_OK;
852 NS_IMPL_ISUPPORTS(GetFileReferencesHelper,
853 nsIRunnable)
855 NS_IMETHODIMP
856 GetFileReferencesHelper::Run()
858 AssertIsOnIOThread();
860 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
861 NS_ASSERTION(mgr, "This should never fail!");
863 nsRefPtr<FileManager> fileManager =
864 mgr->GetFileManager(mPersistenceType, mOrigin, mDatabaseName);
866 if (fileManager) {
867 nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId);
869 if (fileInfo) {
870 fileInfo->GetReferences(&mMemRefCnt, &mDBRefCnt, &mSliceRefCnt);
872 if (mMemRefCnt != -1) {
873 // We added an extra temp ref, so account for that accordingly.
874 mMemRefCnt--;
877 mResult = true;
881 mozilla::MutexAutoLock lock(mMutex);
882 NS_ASSERTION(mWaiting, "Huh?!");
884 mWaiting = false;
885 mCondVar.Notify();
887 return NS_OK;