Bug 1904750 Prefer DefaultDuration over previous inter-timestamp interval r=media...
[gecko.git] / dom / indexedDB / IndexedDatabaseManager.cpp
blob8120b97381d8f19428a9bdc40084316d409cf91f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=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 "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
10 #include "nsIScriptError.h"
11 #include "nsIScriptGlobalObject.h"
13 #include "jsapi.h"
14 #include "js/Object.h" // JS::GetClass
15 #include "js/PropertyAndElement.h" // JS_DefineProperty
16 #include "mozilla/ClearOnShutdown.h"
17 #include "mozilla/ContentEvents.h"
18 #include "mozilla/EventDispatcher.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/ResultExtensions.h"
21 #include "mozilla/dom/DOMException.h"
22 #include "mozilla/dom/ErrorEvent.h"
23 #include "mozilla/dom/ErrorEventBinding.h"
24 #include "mozilla/dom/WorkerScope.h"
25 #include "mozilla/dom/Promise.h"
26 #include "mozilla/dom/RootedDictionary.h"
27 #include "mozilla/dom/quota/Assertions.h"
28 #include "mozilla/dom/quota/PromiseUtils.h"
29 #include "mozilla/dom/quota/ResultExtensions.h"
30 #include "mozilla/intl/LocaleCanonicalizer.h"
31 #include "mozilla/ipc/BackgroundChild.h"
32 #include "mozilla/ipc/PBackgroundChild.h"
33 #include "nsContentUtils.h"
34 #include "mozilla/Logging.h"
36 #include "ActorsChild.h"
37 #include "DatabaseFileManager.h"
38 #include "IDBEvents.h"
39 #include "IDBFactory.h"
40 #include "IDBKeyRange.h"
41 #include "IDBRequest.h"
42 #include "IndexedDBCommon.h"
43 #include "ProfilerHelpers.h"
44 #include "ScriptErrorHelper.h"
45 #include "nsCharSeparatedTokenizer.h"
47 // Bindings for ResolveConstructors
48 #include "mozilla/dom/IDBCursorBinding.h"
49 #include "mozilla/dom/IDBDatabaseBinding.h"
50 #include "mozilla/dom/IDBFactoryBinding.h"
51 #include "mozilla/dom/IDBIndexBinding.h"
52 #include "mozilla/dom/IDBKeyRangeBinding.h"
53 #include "mozilla/dom/IDBObjectStoreBinding.h"
54 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
55 #include "mozilla/dom/IDBRequestBinding.h"
56 #include "mozilla/dom/IDBTransactionBinding.h"
57 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
59 #define IDB_STR "indexedDB"
61 namespace mozilla::dom {
62 namespace indexedDB {
64 using namespace mozilla::dom::quota;
65 using namespace mozilla::ipc;
67 class FileManagerInfo {
68 public:
69 [[nodiscard]] SafeRefPtr<DatabaseFileManager> GetFileManager(
70 PersistenceType aPersistenceType, const nsAString& aName) const;
72 [[nodiscard]] SafeRefPtr<DatabaseFileManager>
73 GetFileManagerByDatabaseFilePath(PersistenceType aPersistenceType,
74 const nsAString& aDatabaseFilePath) const;
76 const nsTArray<SafeRefPtr<DatabaseFileManager>>& GetFileManagers(
77 PersistenceType aPersistenceType) const;
79 void AddFileManager(SafeRefPtr<DatabaseFileManager> aFileManager);
81 bool HasFileManagers() const {
82 AssertIsOnIOThread();
84 return !mPersistentStorageFileManagers.IsEmpty() ||
85 !mTemporaryStorageFileManagers.IsEmpty() ||
86 !mDefaultStorageFileManagers.IsEmpty() ||
87 !mPrivateStorageFileManagers.IsEmpty();
90 void InvalidateAllFileManagers() const;
92 void InvalidateAndRemoveFileManagers(PersistenceType aPersistenceType);
94 void InvalidateAndRemoveFileManager(PersistenceType aPersistenceType,
95 const nsAString& aName);
97 private:
98 nsTArray<SafeRefPtr<DatabaseFileManager>>& GetArray(
99 PersistenceType aPersistenceType);
101 const nsTArray<SafeRefPtr<DatabaseFileManager>>& GetImmutableArray(
102 PersistenceType aPersistenceType) const {
103 return const_cast<FileManagerInfo*>(this)->GetArray(aPersistenceType);
106 nsTArray<SafeRefPtr<DatabaseFileManager>> mPersistentStorageFileManagers;
107 nsTArray<SafeRefPtr<DatabaseFileManager>> mTemporaryStorageFileManagers;
108 nsTArray<SafeRefPtr<DatabaseFileManager>> mDefaultStorageFileManagers;
109 nsTArray<SafeRefPtr<DatabaseFileManager>> mPrivateStorageFileManagers;
112 } // namespace indexedDB
114 using namespace mozilla::dom::indexedDB;
116 namespace {
118 // The threshold we use for structured clone data storing.
119 // Anything smaller than the threshold is compressed and stored in the database.
120 // Anything larger is compressed and stored outside the database.
121 const int32_t kDefaultDataThresholdBytes = 1024 * 1024; // 1MB
123 // The maximal size of a serialized object to be transfered through IPC.
124 const int32_t kDefaultMaxSerializedMsgSize = IPC::Channel::kMaximumMessageSize;
126 // The maximum number of records to preload (in addition to the one requested by
127 // the child).
129 // TODO: The current number was chosen for no particular reason. Telemetry
130 // should be added to determine whether this is a reasonable number for an
131 // overwhelming majority of cases.
132 const int32_t kDefaultMaxPreloadExtraRecords = 64;
134 #define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
136 const char kDataThresholdPref[] = IDB_PREF_BRANCH_ROOT "dataThreshold";
137 const char kPrefMaxSerilizedMsgSize[] =
138 IDB_PREF_BRANCH_ROOT "maxSerializedMsgSize";
139 const char kPrefMaxPreloadExtraRecords[] =
140 IDB_PREF_BRANCH_ROOT "maxPreloadExtraRecords";
142 #define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
144 const char kPrefLoggingEnabled[] = IDB_PREF_LOGGING_BRANCH_ROOT "enabled";
145 const char kPrefLoggingDetails[] = IDB_PREF_LOGGING_BRANCH_ROOT "details";
147 const char kPrefLoggingProfiler[] =
148 IDB_PREF_LOGGING_BRANCH_ROOT "profiler-marks";
150 #undef IDB_PREF_LOGGING_BRANCH_ROOT
151 #undef IDB_PREF_BRANCH_ROOT
153 StaticMutex gDBManagerMutex;
154 StaticRefPtr<IndexedDatabaseManager> gDBManager MOZ_GUARDED_BY(gDBManagerMutex);
155 bool gInitialized MOZ_GUARDED_BY(gDBManagerMutex) = false;
156 bool gClosed MOZ_GUARDED_BY(gDBManagerMutex) = false;
158 Atomic<int32_t> gDataThresholdBytes(0);
159 Atomic<int32_t> gMaxSerializedMsgSize(0);
160 Atomic<int32_t> gMaxPreloadExtraRecords(0);
162 void DataThresholdPrefChangedCallback(const char* aPrefName, void* aClosure) {
163 MOZ_ASSERT(NS_IsMainThread());
164 MOZ_ASSERT(!strcmp(aPrefName, kDataThresholdPref));
165 MOZ_ASSERT(!aClosure);
167 int32_t dataThresholdBytes =
168 Preferences::GetInt(aPrefName, kDefaultDataThresholdBytes);
170 // The magic -1 is for use only by tests that depend on stable blob file id's.
171 if (dataThresholdBytes == -1) {
172 dataThresholdBytes = INT32_MAX;
175 gDataThresholdBytes = dataThresholdBytes;
178 void MaxSerializedMsgSizePrefChangeCallback(const char* aPrefName,
179 void* aClosure) {
180 MOZ_ASSERT(NS_IsMainThread());
181 MOZ_ASSERT(!strcmp(aPrefName, kPrefMaxSerilizedMsgSize));
182 MOZ_ASSERT(!aClosure);
184 gMaxSerializedMsgSize =
185 Preferences::GetInt(aPrefName, kDefaultMaxSerializedMsgSize);
186 MOZ_ASSERT(gMaxSerializedMsgSize > 0);
189 void MaxPreloadExtraRecordsPrefChangeCallback(const char* aPrefName,
190 void* aClosure) {
191 MOZ_ASSERT(NS_IsMainThread());
192 MOZ_ASSERT(!strcmp(aPrefName, kPrefMaxPreloadExtraRecords));
193 MOZ_ASSERT(!aClosure);
195 gMaxPreloadExtraRecords =
196 Preferences::GetInt(aPrefName, kDefaultMaxPreloadExtraRecords);
197 MOZ_ASSERT(gMaxPreloadExtraRecords >= 0);
199 // TODO: We could also allow setting a negative value to preload all available
200 // records, but this doesn't seem to be too useful in general, and it would
201 // require adaptations in ActorsParent.cpp
204 auto DatabaseNameMatchPredicate(const nsAString* const aName) {
205 MOZ_ASSERT(aName);
206 return [aName](const auto& fileManager) {
207 return fileManager->DatabaseName() == *aName;
211 auto DatabaseFilePathMatchPredicate(const nsAString* const aDatabaseFilePath) {
212 MOZ_ASSERT(aDatabaseFilePath);
213 return [aDatabaseFilePath](const auto& fileManager) {
214 return fileManager->DatabaseFilePath() == *aDatabaseFilePath;
218 } // namespace
220 IndexedDatabaseManager::IndexedDatabaseManager() : mBackgroundActor(nullptr) {
221 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
224 IndexedDatabaseManager::~IndexedDatabaseManager() {
225 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
227 if (mBackgroundActor) {
228 mBackgroundActor->SendDeleteMeInternal();
229 MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
233 bool IndexedDatabaseManager::sIsMainProcess = false;
234 bool IndexedDatabaseManager::sFullSynchronousMode = false;
236 mozilla::LazyLogModule IndexedDatabaseManager::sLoggingModule("IndexedDB");
238 Atomic<IndexedDatabaseManager::LoggingMode>
239 IndexedDatabaseManager::sLoggingMode(
240 IndexedDatabaseManager::Logging_Disabled);
242 // static
243 IndexedDatabaseManager* IndexedDatabaseManager::GetOrCreate() {
244 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
246 StaticMutexAutoLock lock(gDBManagerMutex);
248 if (gClosed) {
249 NS_ERROR("Calling GetOrCreate() after shutdown!");
250 return nullptr;
253 if (!gDBManager) {
254 sIsMainProcess = XRE_IsParentProcess();
256 if (gInitialized) {
257 NS_ERROR("Initialized more than once?!");
260 RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
263 StaticMutexAutoUnlock unlock(gDBManagerMutex);
265 QM_TRY(MOZ_TO_RESULT(instance->Init()), nullptr);
268 gDBManager = instance;
270 ClearOnShutdown(&gDBManager);
272 gInitialized = true;
275 return gDBManager;
278 // static
279 IndexedDatabaseManager* IndexedDatabaseManager::Get() {
280 StaticMutexAutoLock lock(gDBManagerMutex);
282 // Does not return an owning reference.
283 return gDBManager;
286 // static
287 already_AddRefed<IndexedDatabaseManager>
288 IndexedDatabaseManager::FactoryCreate() {
289 RefPtr<IndexedDatabaseManager> indexedDatabaseManager = GetOrCreate();
290 return indexedDatabaseManager.forget();
293 nsresult IndexedDatabaseManager::Init() {
294 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
296 // By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
297 // guarantees (unlike synchronous = OFF) atomicity and consistency, but not
298 // necessarily durability in situations such as power loss. This preference
299 // allows enabling PRAGMA synchronous = FULL on SQLite, which does guarantee
300 // durability, but with an extra fsync() and the corresponding performance
301 // hit.
302 sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous");
304 Preferences::RegisterCallback(LoggingModePrefChangedCallback,
305 kPrefLoggingDetails);
307 Preferences::RegisterCallback(LoggingModePrefChangedCallback,
308 kPrefLoggingProfiler);
310 Preferences::RegisterCallbackAndCall(LoggingModePrefChangedCallback,
311 kPrefLoggingEnabled);
313 Preferences::RegisterCallbackAndCall(DataThresholdPrefChangedCallback,
314 kDataThresholdPref);
316 Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback,
317 kPrefMaxSerilizedMsgSize);
319 Preferences::RegisterCallbackAndCall(MaxPreloadExtraRecordsPrefChangeCallback,
320 kPrefMaxPreloadExtraRecords);
322 return NS_OK;
325 void IndexedDatabaseManager::Destroy() {
327 StaticMutexAutoLock lock(gDBManagerMutex);
329 // Setting the closed flag prevents the service from being recreated.
330 // Don't set it though if there's no real instance created.
331 if (gInitialized && gClosed) {
332 NS_ERROR("Shutdown more than once?!");
335 gClosed = true;
338 Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
339 kPrefLoggingDetails);
341 Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
342 kPrefLoggingProfiler);
344 Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
345 kPrefLoggingEnabled);
347 Preferences::UnregisterCallback(DataThresholdPrefChangedCallback,
348 kDataThresholdPref);
350 Preferences::UnregisterCallback(MaxSerializedMsgSizePrefChangeCallback,
351 kPrefMaxSerilizedMsgSize);
353 delete this;
356 nsresult IndexedDatabaseManager::EnsureBackgroundActor() {
357 if (mBackgroundActor) {
358 return NS_OK;
361 PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
362 if (NS_WARN_IF(!bgActor)) {
363 return NS_ERROR_FAILURE;
367 BackgroundUtilsChild* actor = new BackgroundUtilsChild(this);
369 mBackgroundActor = static_cast<BackgroundUtilsChild*>(
370 bgActor->SendPBackgroundIndexedDBUtilsConstructor(actor));
372 if (NS_WARN_IF(!mBackgroundActor)) {
373 return NS_ERROR_FAILURE;
377 return NS_OK;
380 // static
381 bool IndexedDatabaseManager::ResolveSandboxBinding(JSContext* aCx) {
382 MOZ_ASSERT(NS_IsMainThread());
383 MOZ_ASSERT(
384 JS::GetClass(JS::CurrentGlobalOrNull(aCx))->flags & JSCLASS_DOM_GLOBAL,
385 "Passed object is not a global object!");
387 // We need to ensure that the manager has been created already here so that we
388 // load preferences that may control which properties are exposed.
389 if (NS_WARN_IF(!GetOrCreate())) {
390 return false;
393 if (!IDBCursor_Binding::GetConstructorObject(aCx) ||
394 !IDBCursorWithValue_Binding::GetConstructorObject(aCx) ||
395 !IDBDatabase_Binding::GetConstructorObject(aCx) ||
396 !IDBFactory_Binding::GetConstructorObject(aCx) ||
397 !IDBIndex_Binding::GetConstructorObject(aCx) ||
398 !IDBKeyRange_Binding::GetConstructorObject(aCx) ||
399 !IDBObjectStore_Binding::GetConstructorObject(aCx) ||
400 !IDBOpenDBRequest_Binding::GetConstructorObject(aCx) ||
401 !IDBRequest_Binding::GetConstructorObject(aCx) ||
402 !IDBTransaction_Binding::GetConstructorObject(aCx) ||
403 !IDBVersionChangeEvent_Binding::GetConstructorObject(aCx)) {
404 return false;
407 return true;
410 // static
411 bool IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
412 JS::Handle<JSObject*> aGlobal) {
413 MOZ_ASSERT(NS_IsMainThread());
414 MOZ_ASSERT(JS::GetClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
415 "Passed object is not a global object!");
417 nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
418 if (NS_WARN_IF(!global)) {
419 return false;
422 QM_TRY_UNWRAP(auto factory, IDBFactory::CreateForMainThreadJS(global), false);
424 MOZ_ASSERT(factory, "This should never fail for chrome!");
426 JS::Rooted<JS::Value> indexedDB(aCx);
427 js::AssertSameCompartment(aCx, aGlobal);
428 if (!GetOrCreateDOMReflector(aCx, factory, &indexedDB)) {
429 return false;
432 return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE);
435 // static
436 bool IndexedDatabaseManager::IsClosed() {
437 StaticMutexAutoLock lock(gDBManagerMutex);
439 return gClosed;
442 #ifdef DEBUG
443 // static
444 bool IndexedDatabaseManager::IsMainProcess() {
445 NS_ASSERTION(Get(),
446 "IsMainProcess() called before indexedDB has been initialized!");
447 NS_ASSERTION((XRE_IsParentProcess()) == sIsMainProcess,
448 "XRE_GetProcessType changed its tune!");
449 return sIsMainProcess;
452 // static
453 IndexedDatabaseManager::LoggingMode IndexedDatabaseManager::GetLoggingMode() {
454 MOZ_ASSERT(Get(),
455 "GetLoggingMode called before IndexedDatabaseManager has been "
456 "initialized!");
458 return sLoggingMode;
461 // static
462 mozilla::LogModule* IndexedDatabaseManager::GetLoggingModule() {
463 MOZ_ASSERT(Get(),
464 "GetLoggingModule called before IndexedDatabaseManager has been "
465 "initialized!");
467 return sLoggingModule;
470 #endif // DEBUG
472 // static
473 bool IndexedDatabaseManager::FullSynchronous() {
474 MOZ_ASSERT(Get(),
475 "FullSynchronous() called before indexedDB has been initialized!");
477 return sFullSynchronousMode;
480 // static
481 uint32_t IndexedDatabaseManager::DataThreshold() {
482 MOZ_ASSERT(Get(),
483 "DataThreshold() called before indexedDB has been initialized!");
485 return gDataThresholdBytes;
488 // static
489 uint32_t IndexedDatabaseManager::MaxSerializedMsgSize() {
490 MOZ_ASSERT(
491 Get(),
492 "MaxSerializedMsgSize() called before indexedDB has been initialized!");
493 MOZ_ASSERT(gMaxSerializedMsgSize > 0);
495 return gMaxSerializedMsgSize;
498 // static
499 int32_t IndexedDatabaseManager::MaxPreloadExtraRecords() {
500 MOZ_ASSERT(Get(),
501 "MaxPreloadExtraRecords() called before indexedDB has been "
502 "initialized!");
504 return gMaxPreloadExtraRecords;
507 void IndexedDatabaseManager::ClearBackgroundActor() {
508 MOZ_ASSERT(NS_IsMainThread());
510 mBackgroundActor = nullptr;
513 SafeRefPtr<DatabaseFileManager> IndexedDatabaseManager::GetFileManager(
514 PersistenceType aPersistenceType, const nsACString& aOrigin,
515 const nsAString& aDatabaseName) {
516 AssertIsOnIOThread();
518 FileManagerInfo* info;
519 if (!mFileManagerInfos.Get(aOrigin, &info)) {
520 return nullptr;
523 return info->GetFileManager(aPersistenceType, aDatabaseName);
526 SafeRefPtr<DatabaseFileManager>
527 IndexedDatabaseManager::GetFileManagerByDatabaseFilePath(
528 PersistenceType aPersistenceType, const nsACString& aOrigin,
529 const nsAString& aDatabaseFilePath) {
530 AssertIsOnIOThread();
532 FileManagerInfo* info;
533 if (!mFileManagerInfos.Get(aOrigin, &info)) {
534 return nullptr;
537 return info->GetFileManagerByDatabaseFilePath(aPersistenceType,
538 aDatabaseFilePath);
541 const nsTArray<SafeRefPtr<DatabaseFileManager>>&
542 IndexedDatabaseManager::GetFileManagers(PersistenceType aPersistenceType,
543 const nsACString& aOrigin) {
544 AssertIsOnIOThread();
546 FileManagerInfo* info;
547 if (!mFileManagerInfos.Get(aOrigin, &info)) {
548 static nsTArray<SafeRefPtr<DatabaseFileManager>> emptyArray;
549 return emptyArray;
552 return info->GetFileManagers(aPersistenceType);
555 void IndexedDatabaseManager::AddFileManager(
556 SafeRefPtr<DatabaseFileManager> aFileManager) {
557 AssertIsOnIOThread();
558 MOZ_ASSERT(aFileManager);
560 const auto& origin = aFileManager->Origin();
561 mFileManagerInfos.GetOrInsertNew(origin)->AddFileManager(
562 std::move(aFileManager));
565 void IndexedDatabaseManager::InvalidateAllFileManagers() {
566 AssertIsOnIOThread();
568 for (const auto& fileManagerInfo : mFileManagerInfos.Values()) {
569 fileManagerInfo->InvalidateAllFileManagers();
572 mFileManagerInfos.Clear();
575 void IndexedDatabaseManager::InvalidateFileManagers(
576 PersistenceType aPersistenceType) {
577 AssertIsOnIOThread();
579 for (auto iter = mFileManagerInfos.Iter(); !iter.Done(); iter.Next()) {
580 iter.Data()->InvalidateAndRemoveFileManagers(aPersistenceType);
582 if (!iter.Data()->HasFileManagers()) {
583 iter.Remove();
588 void IndexedDatabaseManager::InvalidateFileManagers(
589 PersistenceType aPersistenceType, const nsACString& aOrigin) {
590 AssertIsOnIOThread();
591 MOZ_ASSERT(!aOrigin.IsEmpty());
593 FileManagerInfo* info;
594 if (!mFileManagerInfos.Get(aOrigin, &info)) {
595 return;
598 info->InvalidateAndRemoveFileManagers(aPersistenceType);
600 if (!info->HasFileManagers()) {
601 mFileManagerInfos.Remove(aOrigin);
605 void IndexedDatabaseManager::InvalidateFileManager(
606 PersistenceType aPersistenceType, const nsACString& aOrigin,
607 const nsAString& aDatabaseName) {
608 AssertIsOnIOThread();
610 FileManagerInfo* info;
611 if (!mFileManagerInfos.Get(aOrigin, &info)) {
612 return;
615 info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
617 if (!info->HasFileManagers()) {
618 mFileManagerInfos.Remove(aOrigin);
622 nsresult IndexedDatabaseManager::BlockAndGetFileReferences(
623 PersistenceType aPersistenceType, const nsACString& aOrigin,
624 const nsAString& aDatabaseName, int64_t aFileId, int32_t* aRefCnt,
625 int32_t* aDBRefCnt, bool* aResult) {
626 MOZ_ASSERT(NS_IsMainThread());
628 if (NS_WARN_IF(!StaticPrefs::dom_indexedDB_testing())) {
629 return NS_ERROR_UNEXPECTED;
632 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
634 if (!mBackgroundActor->SendGetFileReferences(
635 aPersistenceType, nsCString(aOrigin), nsString(aDatabaseName),
636 aFileId, aRefCnt, aDBRefCnt, aResult)) {
637 return NS_ERROR_FAILURE;
640 return NS_OK;
643 nsresult IndexedDatabaseManager::FlushPendingFileDeletions() {
644 MOZ_ASSERT(NS_IsMainThread());
646 if (NS_WARN_IF(!StaticPrefs::dom_indexedDB_testing())) {
647 return NS_ERROR_UNEXPECTED;
650 PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
651 if (NS_WARN_IF(!bgActor)) {
652 return NS_ERROR_FAILURE;
655 if (!bgActor->SendFlushPendingFileDeletions()) {
656 return NS_ERROR_FAILURE;
659 return NS_OK;
662 NS_IMPL_ADDREF(IndexedDatabaseManager)
663 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
664 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIIndexedDatabaseManager)
666 NS_IMETHODIMP
667 IndexedDatabaseManager::DoMaintenance(JSContext* aContext, Promise** _retval) {
668 MOZ_ASSERT(NS_IsMainThread());
669 MOZ_ASSERT(_retval);
671 if (NS_WARN_IF(!StaticPrefs::dom_indexedDB_testing())) {
672 return NS_ERROR_UNEXPECTED;
675 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
677 RefPtr<Promise> promise;
678 nsresult rv = CreatePromise(aContext, getter_AddRefs(promise));
679 if (NS_WARN_IF(NS_FAILED(rv))) {
680 return rv;
683 mBackgroundActor->SendDoMaintenance()->Then(
684 GetCurrentSerialEventTarget(), __func__,
685 [promise](const PBackgroundIndexedDBUtilsChild::DoMaintenancePromise::
686 ResolveOrRejectValue& aValue) {
687 if (aValue.IsReject()) {
688 promise->MaybeReject(NS_ERROR_FAILURE);
689 return;
692 if (NS_FAILED(aValue.ResolveValue())) {
693 promise->MaybeReject(aValue.ResolveValue());
694 return;
697 promise->MaybeResolveWithUndefined();
700 promise.forget(_retval);
701 return NS_OK;
704 // static
705 void IndexedDatabaseManager::LoggingModePrefChangedCallback(
706 const char* /* aPrefName */, void* /* aClosure */) {
707 MOZ_ASSERT(NS_IsMainThread());
709 if (!Preferences::GetBool(kPrefLoggingEnabled)) {
710 sLoggingMode = Logging_Disabled;
711 return;
714 bool useProfiler = Preferences::GetBool(kPrefLoggingProfiler);
715 #if !defined(MOZ_GECKO_PROFILER)
716 if (useProfiler) {
717 NS_WARNING(
718 "IndexedDB cannot create profiler marks because this build does "
719 "not have profiler extensions enabled!");
720 useProfiler = false;
722 #endif
724 const bool logDetails = Preferences::GetBool(kPrefLoggingDetails);
726 if (useProfiler) {
727 sLoggingMode = logDetails ? Logging_DetailedProfilerMarks
728 : Logging_ConciseProfilerMarks;
729 } else {
730 sLoggingMode = logDetails ? Logging_Detailed : Logging_Concise;
734 nsresult IndexedDatabaseManager::EnsureLocale() {
735 MOZ_ASSERT(NS_IsMainThread());
737 nsAutoCString acceptLang;
738 Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
740 // Split values on commas.
741 for (const auto& lang :
742 nsCCharSeparatedTokenizer(acceptLang, ',').ToRange()) {
743 mozilla::intl::LocaleCanonicalizer::Vector asciiString{};
744 auto result = mozilla::intl::LocaleCanonicalizer::CanonicalizeICULevel1(
745 PromiseFlatCString(lang).get(), asciiString);
746 if (result.isOk()) {
747 mLocale.AssignASCII(asciiString);
748 break;
752 if (mLocale.IsEmpty()) {
753 mLocale.AssignLiteral("en_US");
756 return NS_OK;
759 // static
760 const nsCString& IndexedDatabaseManager::GetLocale() {
761 IndexedDatabaseManager* idbManager = Get();
762 MOZ_ASSERT(idbManager, "IDBManager is not ready!");
764 MOZ_ASSERT(!idbManager->mLocale.IsEmpty());
765 return idbManager->mLocale;
768 SafeRefPtr<DatabaseFileManager> FileManagerInfo::GetFileManager(
769 PersistenceType aPersistenceType, const nsAString& aName) const {
770 AssertIsOnIOThread();
772 const auto& managers = GetImmutableArray(aPersistenceType);
774 const auto end = managers.cend();
775 const auto foundIt =
776 std::find_if(managers.cbegin(), end, DatabaseNameMatchPredicate(&aName));
778 return foundIt != end ? foundIt->clonePtr() : nullptr;
781 SafeRefPtr<DatabaseFileManager>
782 FileManagerInfo::GetFileManagerByDatabaseFilePath(
783 PersistenceType aPersistenceType,
784 const nsAString& aDatabaseFilePath) const {
785 AssertIsOnIOThread();
787 const auto& managers = GetImmutableArray(aPersistenceType);
789 const auto end = managers.cend();
790 const auto foundIt =
791 std::find_if(managers.cbegin(), end,
792 DatabaseFilePathMatchPredicate(&aDatabaseFilePath));
794 return foundIt != end ? foundIt->clonePtr() : nullptr;
797 const nsTArray<SafeRefPtr<DatabaseFileManager>>&
798 FileManagerInfo::GetFileManagers(PersistenceType aPersistenceType) const {
799 AssertIsOnIOThread();
801 return GetImmutableArray(aPersistenceType);
804 void FileManagerInfo::AddFileManager(
805 SafeRefPtr<DatabaseFileManager> aFileManager) {
806 AssertIsOnIOThread();
808 nsTArray<SafeRefPtr<DatabaseFileManager>>& managers =
809 GetArray(aFileManager->Type());
811 NS_ASSERTION(!managers.Contains(aFileManager), "Adding more than once?!");
813 managers.AppendElement(std::move(aFileManager));
816 void FileManagerInfo::InvalidateAllFileManagers() const {
817 AssertIsOnIOThread();
819 uint32_t i;
821 for (i = 0; i < mPersistentStorageFileManagers.Length(); i++) {
822 mPersistentStorageFileManagers[i]->Invalidate();
825 for (i = 0; i < mTemporaryStorageFileManagers.Length(); i++) {
826 mTemporaryStorageFileManagers[i]->Invalidate();
829 for (i = 0; i < mDefaultStorageFileManagers.Length(); i++) {
830 mDefaultStorageFileManagers[i]->Invalidate();
833 for (i = 0; i < mPrivateStorageFileManagers.Length(); i++) {
834 mPrivateStorageFileManagers[i]->Invalidate();
838 void FileManagerInfo::InvalidateAndRemoveFileManagers(
839 PersistenceType aPersistenceType) {
840 AssertIsOnIOThread();
842 nsTArray<SafeRefPtr<DatabaseFileManager>>& managers =
843 GetArray(aPersistenceType);
845 for (uint32_t i = 0; i < managers.Length(); i++) {
846 managers[i]->Invalidate();
849 managers.Clear();
852 void FileManagerInfo::InvalidateAndRemoveFileManager(
853 PersistenceType aPersistenceType, const nsAString& aName) {
854 AssertIsOnIOThread();
856 auto& managers = GetArray(aPersistenceType);
857 const auto end = managers.cend();
858 const auto foundIt =
859 std::find_if(managers.cbegin(), end, DatabaseNameMatchPredicate(&aName));
861 if (foundIt != end) {
862 (*foundIt)->Invalidate();
863 managers.RemoveElementAt(foundIt.GetIndex());
867 nsTArray<SafeRefPtr<DatabaseFileManager>>& FileManagerInfo::GetArray(
868 PersistenceType aPersistenceType) {
869 switch (aPersistenceType) {
870 case PERSISTENCE_TYPE_PERSISTENT:
871 return mPersistentStorageFileManagers;
872 case PERSISTENCE_TYPE_TEMPORARY:
873 return mTemporaryStorageFileManagers;
874 case PERSISTENCE_TYPE_DEFAULT:
875 return mDefaultStorageFileManagers;
876 case PERSISTENCE_TYPE_PRIVATE:
877 return mPrivateStorageFileManagers;
879 case PERSISTENCE_TYPE_INVALID:
880 default:
881 MOZ_CRASH("Bad storage type value!");
885 } // namespace mozilla::dom