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"
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
{
64 using namespace mozilla::dom::quota
;
65 using namespace mozilla::ipc
;
67 class FileManagerInfo
{
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 {
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
);
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
;
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
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
,
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
,
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
) {
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
;
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
);
243 IndexedDatabaseManager
* IndexedDatabaseManager::GetOrCreate() {
244 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
246 StaticMutexAutoLock
lock(gDBManagerMutex
);
249 NS_ERROR("Calling GetOrCreate() after shutdown!");
254 sIsMainProcess
= XRE_IsParentProcess();
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
);
279 IndexedDatabaseManager
* IndexedDatabaseManager::Get() {
280 StaticMutexAutoLock
lock(gDBManagerMutex
);
282 // Does not return an owning reference.
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
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
,
316 Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback
,
317 kPrefMaxSerilizedMsgSize
);
319 Preferences::RegisterCallbackAndCall(MaxPreloadExtraRecordsPrefChangeCallback
,
320 kPrefMaxPreloadExtraRecords
);
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?!");
338 Preferences::UnregisterCallback(LoggingModePrefChangedCallback
,
339 kPrefLoggingDetails
);
341 Preferences::UnregisterCallback(LoggingModePrefChangedCallback
,
342 kPrefLoggingProfiler
);
344 Preferences::UnregisterCallback(LoggingModePrefChangedCallback
,
345 kPrefLoggingEnabled
);
347 Preferences::UnregisterCallback(DataThresholdPrefChangedCallback
,
350 Preferences::UnregisterCallback(MaxSerializedMsgSizePrefChangeCallback
,
351 kPrefMaxSerilizedMsgSize
);
356 nsresult
IndexedDatabaseManager::EnsureBackgroundActor() {
357 if (mBackgroundActor
) {
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
;
381 bool IndexedDatabaseManager::ResolveSandboxBinding(JSContext
* aCx
) {
382 MOZ_ASSERT(NS_IsMainThread());
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())) {
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
)) {
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
)) {
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
)) {
432 return JS_DefineProperty(aCx
, aGlobal
, IDB_STR
, indexedDB
, JSPROP_ENUMERATE
);
436 bool IndexedDatabaseManager::IsClosed() {
437 StaticMutexAutoLock
lock(gDBManagerMutex
);
444 bool IndexedDatabaseManager::IsMainProcess() {
446 "IsMainProcess() called before indexedDB has been initialized!");
447 NS_ASSERTION((XRE_IsParentProcess()) == sIsMainProcess
,
448 "XRE_GetProcessType changed its tune!");
449 return sIsMainProcess
;
453 IndexedDatabaseManager::LoggingMode
IndexedDatabaseManager::GetLoggingMode() {
455 "GetLoggingMode called before IndexedDatabaseManager has been "
462 mozilla::LogModule
* IndexedDatabaseManager::GetLoggingModule() {
464 "GetLoggingModule called before IndexedDatabaseManager has been "
467 return sLoggingModule
;
473 bool IndexedDatabaseManager::FullSynchronous() {
475 "FullSynchronous() called before indexedDB has been initialized!");
477 return sFullSynchronousMode
;
481 uint32_t IndexedDatabaseManager::DataThreshold() {
483 "DataThreshold() called before indexedDB has been initialized!");
485 return gDataThresholdBytes
;
489 uint32_t IndexedDatabaseManager::MaxSerializedMsgSize() {
492 "MaxSerializedMsgSize() called before indexedDB has been initialized!");
493 MOZ_ASSERT(gMaxSerializedMsgSize
> 0);
495 return gMaxSerializedMsgSize
;
499 int32_t IndexedDatabaseManager::MaxPreloadExtraRecords() {
501 "MaxPreloadExtraRecords() called before indexedDB has been "
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
)) {
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
)) {
537 return info
->GetFileManagerByDatabaseFilePath(aPersistenceType
,
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
;
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()) {
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
)) {
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
)) {
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
;
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
;
662 NS_IMPL_ADDREF(IndexedDatabaseManager
)
663 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager
, Destroy())
664 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager
, nsIIndexedDatabaseManager
)
667 IndexedDatabaseManager::DoMaintenance(JSContext
* aContext
, Promise
** _retval
) {
668 MOZ_ASSERT(NS_IsMainThread());
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
))) {
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
);
692 if (NS_FAILED(aValue
.ResolveValue())) {
693 promise
->MaybeReject(aValue
.ResolveValue());
697 promise
->MaybeResolveWithUndefined();
700 promise
.forget(_retval
);
705 void IndexedDatabaseManager::LoggingModePrefChangedCallback(
706 const char* /* aPrefName */, void* /* aClosure */) {
707 MOZ_ASSERT(NS_IsMainThread());
709 if (!Preferences::GetBool(kPrefLoggingEnabled
)) {
710 sLoggingMode
= Logging_Disabled
;
714 bool useProfiler
= Preferences::GetBool(kPrefLoggingProfiler
);
715 #if !defined(MOZ_GECKO_PROFILER)
718 "IndexedDB cannot create profiler marks because this build does "
719 "not have profiler extensions enabled!");
724 const bool logDetails
= Preferences::GetBool(kPrefLoggingDetails
);
727 sLoggingMode
= logDetails
? Logging_DetailedProfilerMarks
728 : Logging_ConciseProfilerMarks
;
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
);
747 mLocale
.AssignASCII(asciiString
);
752 if (mLocale
.IsEmpty()) {
753 mLocale
.AssignLiteral("en_US");
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();
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();
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();
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();
852 void FileManagerInfo::InvalidateAndRemoveFileManager(
853 PersistenceType aPersistenceType
, const nsAString
& aName
) {
854 AssertIsOnIOThread();
856 auto& managers
= GetArray(aPersistenceType
);
857 const auto end
= managers
.cend();
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
:
881 MOZ_CRASH("Bad storage type value!");
885 } // namespace mozilla::dom