summaryrefslogtreecommitdiffstats
path: root/dom/indexedDB
diff options
context:
space:
mode:
Diffstat (limited to 'dom/indexedDB')
-rw-r--r--dom/indexedDB/ActorsParent.cpp441
-rw-r--r--dom/indexedDB/ActorsParent.h5
-rw-r--r--dom/indexedDB/ActorsParentCommon.cpp2
-rw-r--r--dom/indexedDB/IDBFactory.cpp35
-rw-r--r--dom/indexedDB/IndexedDatabaseManager.cpp45
-rw-r--r--dom/indexedDB/IndexedDatabaseManager.h3
-rw-r--r--dom/indexedDB/SchemaUpgrades.cpp6
-rw-r--r--dom/indexedDB/SerializationHelpers.h7
-rw-r--r--dom/indexedDB/test/abort_on_reload.html6
-rw-r--r--dom/indexedDB/test/bfcache_page1.html2
-rw-r--r--dom/indexedDB/test/blob_worker_crash_iframe.html2
-rw-r--r--dom/indexedDB/test/browser_private_idb.js4
-rw-r--r--dom/indexedDB/test/bug839193.js2
-rw-r--r--dom/indexedDB/test/error_events_abort_transactions_iframe.html6
-rw-r--r--dom/indexedDB/test/event_propagation_iframe.html4
-rw-r--r--dom/indexedDB/test/exceptions_in_events_iframe.html4
-rw-r--r--dom/indexedDB/test/head.js2
-rw-r--r--dom/indexedDB/test/helpers.js4
-rw-r--r--dom/indexedDB/test/leaving_page_iframe.html2
-rw-r--r--dom/indexedDB/test/mochitest-common.toml6
-rw-r--r--dom/indexedDB/test/test_abort_on_reload.html2
-rw-r--r--dom/indexedDB/test/test_event_listener_leaks.html2
-rw-r--r--dom/indexedDB/test/test_open_for_principal.html1
-rw-r--r--dom/indexedDB/test/third_party_window.html2
-rw-r--r--dom/indexedDB/test/unit/test_blocked_order.js8
-rw-r--r--dom/indexedDB/test/unit/test_cleanup_transaction.js4
-rw-r--r--dom/indexedDB/test/unit/test_clear.js2
-rw-r--r--dom/indexedDB/test/unit/test_connection_idle_maintenance.js97
-rw-r--r--dom/indexedDB/test/unit/test_connection_idle_maintenance_stop.js204
-rw-r--r--dom/indexedDB/test/unit/test_cursor_cycle.js2
-rw-r--r--dom/indexedDB/test/unit/test_cursor_mutation.js4
-rw-r--r--dom/indexedDB/test/unit/test_cursors.js4
-rw-r--r--dom/indexedDB/test/unit/test_database_onclose.js4
-rw-r--r--dom/indexedDB/test/unit/test_getAll.js2
-rw-r--r--dom/indexedDB/test/unit/test_index_object_cursors.js4
-rw-r--r--dom/indexedDB/test/unit/test_index_update_delete.js4
-rw-r--r--dom/indexedDB/test/unit/test_indexes_bad_values.js2
-rw-r--r--dom/indexedDB/test/unit/test_invalid_version.js1
-rw-r--r--dom/indexedDB/test/unit/test_quotaExceeded_recovery.js4
-rw-r--r--dom/indexedDB/test/unit/test_remove_objectStore.js2
-rw-r--r--dom/indexedDB/test/unit/test_setVersion_throw.js4
-rw-r--r--dom/indexedDB/test/unit/test_table_locks.js4
-rw-r--r--dom/indexedDB/test/unit/test_transaction_abort.js17
-rw-r--r--dom/indexedDB/test/unit/test_transaction_abort_hang.js4
-rw-r--r--dom/indexedDB/test/unit/xpcshell-head-parent-process.js14
-rw-r--r--dom/indexedDB/test/unit/xpcshell-parent-process.toml4
46 files changed, 657 insertions, 333 deletions
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index bc0baf1157..47360094ca 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -291,7 +291,8 @@ static_assert(kSQLiteGrowthIncrement >= 0 &&
"Must be 0 (disabled) or a positive multiple of the page size!");
// The maximum number of threads that can be used for database activity at a
-// single time.
+// single time. Please keep in sync with the constants in
+// test_connection_idle_maintenance*.js tests
const uint32_t kMaxConnectionThreadCount = 20;
static_assert(kMaxConnectionThreadCount, "Must have at least one thread!");
@@ -304,7 +305,8 @@ static_assert(kMaxConnectionThreadCount >= kMaxIdleConnectionThreadCount,
"Idle thread limit must be less than total thread limit!");
// The length of time that database connections will be held open after all
-// transactions have completed before doing idle maintenance.
+// transactions have completed before doing idle maintenance. Please keep in
+// sync with the timeouts in test_connection_idle_maintenance*.js tests
const uint32_t kConnectionIdleMaintenanceMS = 2 * 1000; // 2 seconds
// The length of time that database connections will be held open after all
@@ -1162,7 +1164,8 @@ class DatabaseConnection final : public CachingDatabaseConnection {
return CheckpointInternal(CheckpointMode::Full);
}
- void DoIdleProcessing(bool aNeedsCheckpoint);
+ void DoIdleProcessing(bool aNeedsCheckpoint,
+ const Atomic<bool>& aInterrupted);
void Close();
@@ -1189,7 +1192,8 @@ class DatabaseConnection final : public CachingDatabaseConnection {
*/
Result<bool, nsresult> ReclaimFreePagesWhileIdle(
CachedStatement& aFreelistStatement, CachedStatement& aRollbackStatement,
- uint32_t aFreelistCount, bool aNeedsCheckpoint);
+ uint32_t aFreelistCount, bool aNeedsCheckpoint,
+ const Atomic<bool>& aInterrupted);
Result<int64_t, nsresult> GetFileSize(const nsAString& aPath);
};
@@ -1362,6 +1366,34 @@ class ConnectionPool final {
}
};
+ struct PerformingIdleMaintenanceDatabaseInfo {
+ const NotNull<DatabaseInfo*> mDatabaseInfo;
+ RefPtr<IdleConnectionRunnable> mIdleConnectionRunnable;
+
+ PerformingIdleMaintenanceDatabaseInfo(
+ DatabaseInfo& aDatabaseInfo,
+ RefPtr<IdleConnectionRunnable> aIdleConnectionRunnable);
+
+ PerformingIdleMaintenanceDatabaseInfo(
+ const PerformingIdleMaintenanceDatabaseInfo& aOther) = delete;
+ PerformingIdleMaintenanceDatabaseInfo(
+ PerformingIdleMaintenanceDatabaseInfo&& aOther) noexcept
+ : mDatabaseInfo{aOther.mDatabaseInfo},
+ mIdleConnectionRunnable{std::move(aOther.mIdleConnectionRunnable)} {
+ MOZ_COUNT_CTOR(ConnectionPool::PerformingIdleMaintenanceDatabaseInfo);
+ }
+ PerformingIdleMaintenanceDatabaseInfo& operator=(
+ const PerformingIdleMaintenanceDatabaseInfo& aOther) = delete;
+ PerformingIdleMaintenanceDatabaseInfo& operator=(
+ PerformingIdleMaintenanceDatabaseInfo&& aOther) = delete;
+
+ ~PerformingIdleMaintenanceDatabaseInfo();
+
+ bool operator==(const DatabaseInfo* aDatabaseInfo) const {
+ return mDatabaseInfo == aDatabaseInfo;
+ }
+ };
+
class ThreadInfo {
public:
ThreadInfo();
@@ -1456,7 +1488,8 @@ class ConnectionPool final {
nsCOMPtr<nsIThreadPool> mIOTarget;
nsTArray<IdleThreadInfo> mIdleThreads;
nsTArray<IdleDatabaseInfo> mIdleDatabases;
- nsTArray<NotNull<DatabaseInfo*>> mDatabasesPerformingIdleMaintenance;
+ nsTArray<PerformingIdleMaintenanceDatabaseInfo>
+ mDatabasesPerformingIdleMaintenance;
nsCOMPtr<nsITimer> mIdleTimer;
TimeStamp mTargetIdleTime;
@@ -1559,6 +1592,7 @@ class ConnectionPool::ConnectionRunnable : public Runnable {
class ConnectionPool::IdleConnectionRunnable final : public ConnectionRunnable {
const bool mNeedsCheckpoint;
+ Atomic<bool> mInterrupted;
public:
IdleConnectionRunnable(DatabaseInfo& aDatabaseInfo, bool aNeedsCheckpoint)
@@ -1567,6 +1601,8 @@ class ConnectionPool::IdleConnectionRunnable final : public ConnectionRunnable {
NS_INLINE_DECL_REFCOUNTING_INHERITED(IdleConnectionRunnable,
ConnectionRunnable)
+ void Interrupt() { mInterrupted = true; }
+
private:
~IdleConnectionRunnable() override = default;
@@ -2061,6 +2097,7 @@ class TransactionDatabaseOperationBase : public DatabaseOperationBase {
class Factory final : public PBackgroundIDBFactoryParent,
public AtomicSafeRefCounted<Factory> {
+ nsCString mSystemLocale;
RefPtr<DatabaseLoggingInfo> mLoggingInfo;
#ifdef DEBUG
@@ -2072,7 +2109,7 @@ class Factory final : public PBackgroundIDBFactoryParent,
public:
[[nodiscard]] static SafeRefPtr<Factory> Create(
- const LoggingInfo& aLoggingInfo);
+ const LoggingInfo& aLoggingInfo, const nsACString& aSystemLocale);
DatabaseLoggingInfo* GetLoggingInfo() const {
AssertIsOnBackgroundThread();
@@ -2081,11 +2118,14 @@ class Factory final : public PBackgroundIDBFactoryParent,
return mLoggingInfo;
}
+ const nsCString& GetSystemLocale() const { return mSystemLocale; }
+
MOZ_DECLARE_REFCOUNTED_TYPENAME(mozilla::dom::indexedDB::Factory)
MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(Factory, AtomicSafeRefCounted)
// Only constructed in Create().
- explicit Factory(RefPtr<DatabaseLoggingInfo> aLoggingInfo);
+ Factory(RefPtr<DatabaseLoggingInfo> aLoggingInfo,
+ const nsACString& aSystemLocale);
// IPDL methods are only called by IPDL.
void ActorDestroy(ActorDestroyReason aWhy) override;
@@ -2961,17 +3001,11 @@ class FactoryOp
protected:
enum class State {
- // Just created on the PBackground thread, dispatched to the main thread.
- // Next step is either SendingResults if permission is denied,
- // PermissionChallenge if the permission is unknown, or FinishOpen
- // if permission is granted.
+ // Just created on the PBackground thread, dispatched to the current thread.
+ // Next step is either SendingResults if opening initialization failed, or
+ // DirectoryOpenPending if the opening initialization succeeded.
Initial,
- // Ensuring quota manager is created and opening directory on the
- // PBackground thread. Next step is either SendingResults if quota manager
- // is not available or DirectoryOpenPending if quota manager is available.
- FinishOpen,
-
// Waiting for directory open allowed on the PBackground thread. The next
// step is either SendingResults if directory lock failed to acquire, or
// DatabaseOpenPending if directory lock is acquired.
@@ -3129,10 +3163,6 @@ class FactoryOp
virtual void SendBlockedNotification() = 0;
private:
- mozilla::Result<PermissionValue, nsresult> CheckPermission();
-
- nsresult FinishOpen();
-
// Test whether this FactoryOp needs to wait for the given op.
bool MustWaitFor(const FactoryOp& aExistingOp);
};
@@ -6517,7 +6547,7 @@ already_AddRefed<nsIThreadPool> MakeConnectionIOTarget() {
******************************************************************************/
already_AddRefed<PBackgroundIDBFactoryParent> AllocPBackgroundIDBFactoryParent(
- const LoggingInfo& aLoggingInfo) {
+ const LoggingInfo& aLoggingInfo, const nsACString& aSystemLocale) {
AssertIsOnBackgroundThread();
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
@@ -6531,15 +6561,15 @@ already_AddRefed<PBackgroundIDBFactoryParent> AllocPBackgroundIDBFactoryParent(
return nullptr;
}
- SafeRefPtr<Factory> actor = Factory::Create(aLoggingInfo);
+ SafeRefPtr<Factory> actor = Factory::Create(aLoggingInfo, aSystemLocale);
MOZ_ASSERT(actor);
return actor.forget();
}
bool RecvPBackgroundIDBFactoryConstructor(
- PBackgroundIDBFactoryParent* aActor,
- const LoggingInfo& /* aLoggingInfo */) {
+ PBackgroundIDBFactoryParent* aActor, const LoggingInfo& /* aLoggingInfo */,
+ const nsACString& /* aSystemLocale */) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
@@ -6862,7 +6892,8 @@ nsresult DatabaseConnection::CheckpointInternal(CheckpointMode aMode) {
return NS_OK;
}
-void DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint) {
+void DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint,
+ const Atomic<bool>& aInterrupted) {
AssertIsOnConnectionThread();
MOZ_ASSERT(mInReadTransaction);
MOZ_ASSERT(!mInWriteTransaction);
@@ -6887,22 +6918,23 @@ void DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint) {
mInReadTransaction = false;
}
- const bool freedSomePages = freelistCount && [this, &freelistStmt,
- &rollbackStmt, freelistCount,
- aNeedsCheckpoint] {
- // Warn in case of an error, but do not propagate it. Just indicate we
- // didn't free any pages.
- QM_TRY_INSPECT(const bool& res,
- ReclaimFreePagesWhileIdle(freelistStmt, rollbackStmt,
- freelistCount, aNeedsCheckpoint),
- false);
+ const bool freedSomePages =
+ freelistCount && [this, &freelistStmt, &rollbackStmt, freelistCount,
+ aNeedsCheckpoint, &aInterrupted] {
+ // Warn in case of an error, but do not propagate it. Just indicate we
+ // didn't free any pages.
+ QM_TRY_INSPECT(
+ const bool& res,
+ ReclaimFreePagesWhileIdle(freelistStmt, rollbackStmt, freelistCount,
+ aNeedsCheckpoint, aInterrupted),
+ false);
- // Make sure we didn't leave a transaction running.
- MOZ_ASSERT(!mInReadTransaction);
- MOZ_ASSERT(!mInWriteTransaction);
+ // Make sure we didn't leave a transaction running.
+ MOZ_ASSERT(!mInReadTransaction);
+ MOZ_ASSERT(!mInWriteTransaction);
- return res;
- }();
+ return res;
+ }();
// Truncate the WAL if we were asked to or if we managed to free some space.
if (aNeedsCheckpoint || freedSomePages) {
@@ -6922,7 +6954,8 @@ void DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint) {
Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
CachedStatement& aFreelistStatement, CachedStatement& aRollbackStatement,
- uint32_t aFreelistCount, bool aNeedsCheckpoint) {
+ uint32_t aFreelistCount, bool aNeedsCheckpoint,
+ const Atomic<bool>& aInterrupted) {
AssertIsOnConnectionThread();
MOZ_ASSERT(aFreelistStatement);
MOZ_ASSERT(aRollbackStatement);
@@ -6932,11 +6965,14 @@ Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
AUTO_PROFILER_LABEL("DatabaseConnection::ReclaimFreePagesWhileIdle", DOM);
- // Make sure we don't keep working if anything else needs this thread.
- nsIThread* currentThread = NS_GetCurrentThread();
- MOZ_ASSERT(currentThread);
+ uint32_t pauseOnConnectionThreadMs = StaticPrefs::
+ dom_indexedDB_connectionIdleMaintenance_pauseOnConnectionThreadMs();
+ if (pauseOnConnectionThreadMs > 0) {
+ PR_Sleep(PR_MillisecondsToInterval(pauseOnConnectionThreadMs));
+ }
- if (NS_HasPendingEvents(currentThread)) {
+ // Make sure we don't keep working if anything else needs this thread.
+ if (aInterrupted) {
return false;
}
@@ -6968,7 +7004,7 @@ Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
mInWriteTransaction = true;
- bool freedSomePages = false, interrupted = false;
+ bool freedSomePages = false;
const auto rollback = [&aRollbackStatement, this](const auto&) {
MOZ_ASSERT(mInWriteTransaction);
@@ -6984,14 +7020,12 @@ Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
uint64_t previousFreelistCount = (uint64_t)aFreelistCount + 1;
QM_TRY(CollectWhile(
- [&aFreelistCount, &previousFreelistCount, &interrupted,
- currentThread]() -> Result<bool, nsresult> {
- if (NS_HasPendingEvents(currentThread)) {
- // Abort if something else wants to use the thread, and
- // roll back this transaction. It's ok if we never make
- // progress here because the idle service should
- // eventually reclaim this space.
- interrupted = true;
+ [&aFreelistCount, &previousFreelistCount,
+ &aInterrupted]() -> Result<bool, nsresult> {
+ if (aInterrupted) {
+ // On interrupt, abort and roll back this transaction. It's ok
+ // if we never make progress here because the idle service
+ // should eventually reclaim this space.
return false;
}
// If we were not able to free anything, we might either see
@@ -7001,7 +7035,7 @@ Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
bool madeProgress = previousFreelistCount != aFreelistCount;
previousFreelistCount = aFreelistCount;
MOZ_ASSERT(madeProgress);
- QM_WARNONLY_TRY(MOZ_TO_RESULT(!madeProgress));
+ QM_WARNONLY_TRY(MOZ_TO_RESULT(madeProgress));
return madeProgress && (aFreelistCount != 0);
},
[&aFreelistStatement, &aFreelistCount, &incrementalVacuumStmt,
@@ -7015,9 +7049,9 @@ Result<bool, nsresult> DatabaseConnection::ReclaimFreePagesWhileIdle(
return Ok{};
})
- .andThen([&commitStmt, &freedSomePages, &interrupted, &rollback,
+ .andThen([&commitStmt, &freedSomePages, &aInterrupted, &rollback,
this](Ok) -> Result<Ok, nsresult> {
- if (interrupted) {
+ if (aInterrupted) {
rollback(Ok{});
freedSomePages = false;
}
@@ -7982,8 +8016,9 @@ void ConnectionPool::CloseIdleDatabases() {
}
if (!mDatabasesPerformingIdleMaintenance.IsEmpty()) {
- for (const auto dbInfo : mDatabasesPerformingIdleMaintenance) {
- CloseDatabase(*dbInfo);
+ for (PerformingIdleMaintenanceDatabaseInfo& performingIdleMaintenanceInfo :
+ mDatabasesPerformingIdleMaintenance) {
+ CloseDatabase(*performingIdleMaintenanceInfo.mDatabaseInfo);
}
mDatabasesPerformingIdleMaintenance.Clear();
}
@@ -8059,16 +8094,13 @@ bool ConnectionPool::ScheduleTransaction(TransactionInfo& aTransactionInfo,
// deliberately const to prevent the attempt to wrongly optimize the
// refcounting by passing runnable.forget() to the Dispatch method, see
// bug 1598559.
- const nsCOMPtr<nsIRunnable> runnable =
- new Runnable("IndexedDBDummyRunnable");
for (uint32_t index = mDatabasesPerformingIdleMaintenance.Length();
index > 0; index--) {
- const auto dbInfo = mDatabasesPerformingIdleMaintenance[index - 1];
- dbInfo->mThreadInfo.AssertValid();
+ const auto& performingIdleMaintenanceInfo =
+ mDatabasesPerformingIdleMaintenance[index - 1];
- MOZ_ALWAYS_SUCCEEDS(dbInfo->mThreadInfo.ThreadRef().Dispatch(
- runnable, NS_DISPATCH_NORMAL));
+ performingIdleMaintenanceInfo.mIdleConnectionRunnable->Interrupt();
}
}
@@ -8369,12 +8401,15 @@ void ConnectionPool::PerformIdleDatabaseMaintenance(
aDatabaseInfo.mNeedsCheckpoint = false;
aDatabaseInfo.mIdle = false;
+ auto idleConnectionRunnable =
+ MakeRefPtr<IdleConnectionRunnable>(aDatabaseInfo, neededCheckpoint);
+
mDatabasesPerformingIdleMaintenance.AppendElement(
- WrapNotNullUnchecked(&aDatabaseInfo));
+ PerformingIdleMaintenanceDatabaseInfo{aDatabaseInfo,
+ idleConnectionRunnable});
MOZ_ALWAYS_SUCCEEDS(aDatabaseInfo.mThreadInfo.ThreadRef().Dispatch(
- MakeAndAddRef<IdleConnectionRunnable>(aDatabaseInfo, neededCheckpoint),
- NS_DISPATCH_NORMAL));
+ idleConnectionRunnable.forget(), NS_DISPATCH_NORMAL));
}
void ConnectionPool::CloseDatabase(DatabaseInfo& aDatabaseInfo) const {
@@ -8437,7 +8472,8 @@ ConnectionPool::IdleConnectionRunnable::Run() {
// The connection could be null if EnsureConnection() didn't run or was not
// successful in TransactionDatabaseOperationBase::RunOnConnectionThread().
if (mDatabaseInfo.mConnection) {
- mDatabaseInfo.mConnection->DoIdleProcessing(mNeedsCheckpoint);
+ mDatabaseInfo.mConnection->DoIdleProcessing(mNeedsCheckpoint,
+ mInterrupted);
}
MOZ_ALWAYS_SUCCEEDS(owningThread->Dispatch(this, NS_DISPATCH_NORMAL));
@@ -8733,6 +8769,25 @@ ConnectionPool::IdleDatabaseInfo::~IdleDatabaseInfo() {
MOZ_COUNT_DTOR(ConnectionPool::IdleDatabaseInfo);
}
+ConnectionPool::PerformingIdleMaintenanceDatabaseInfo::
+ PerformingIdleMaintenanceDatabaseInfo(
+ DatabaseInfo& aDatabaseInfo,
+ RefPtr<IdleConnectionRunnable> aIdleConnectionRunnable)
+ : mDatabaseInfo(WrapNotNullUnchecked(&aDatabaseInfo)),
+ mIdleConnectionRunnable(std::move(aIdleConnectionRunnable)) {
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(mIdleConnectionRunnable);
+
+ MOZ_COUNT_CTOR(ConnectionPool::PerformingIdleMaintenanceDatabaseInfo);
+}
+
+ConnectionPool::PerformingIdleMaintenanceDatabaseInfo::
+ ~PerformingIdleMaintenanceDatabaseInfo() {
+ AssertIsOnBackgroundThread();
+
+ MOZ_COUNT_DTOR(ConnectionPool::PerformingIdleMaintenanceDatabaseInfo);
+}
+
ConnectionPool::IdleThreadInfo::IdleThreadInfo(ThreadInfo aThreadInfo)
: IdleResource(TimeStamp::NowLoRes() +
TimeDuration::FromMilliseconds(kConnectionThreadIdleMS)),
@@ -8915,8 +8970,10 @@ DatabaseLoggingInfo::~DatabaseLoggingInfo() {
* Factory
******************************************************************************/
-Factory::Factory(RefPtr<DatabaseLoggingInfo> aLoggingInfo)
- : mLoggingInfo(std::move(aLoggingInfo))
+Factory::Factory(RefPtr<DatabaseLoggingInfo> aLoggingInfo,
+ const nsACString& aSystemLocale)
+ : mSystemLocale(aSystemLocale),
+ mLoggingInfo(std::move(aLoggingInfo))
#ifdef DEBUG
,
mActorDestroyed(false)
@@ -8929,7 +8986,8 @@ Factory::Factory(RefPtr<DatabaseLoggingInfo> aLoggingInfo)
Factory::~Factory() { MOZ_ASSERT(mActorDestroyed); }
// static
-SafeRefPtr<Factory> Factory::Create(const LoggingInfo& aLoggingInfo) {
+SafeRefPtr<Factory> Factory::Create(const LoggingInfo& aLoggingInfo,
+ const nsACString& aSystemLocale) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
@@ -8966,7 +9024,7 @@ SafeRefPtr<Factory> Factory::Create(const LoggingInfo& aLoggingInfo) {
return do_AddRef(entry.Data());
});
- return MakeSafeRefPtr<Factory>(std::move(loggingInfo));
+ return MakeSafeRefPtr<Factory>(std::move(loggingInfo), aSystemLocale);
}
void Factory::ActorDestroy(ActorDestroyReason aWhy) {
@@ -9045,6 +9103,14 @@ Factory::AllocPBackgroundIDBFactoryRequestParent(
return nullptr;
}
+ if (NS_AUUF_OR_WARN_IF(
+ principalInfo.type() == PrincipalInfo::TContentPrincipalInfo &&
+ QuotaManager::IsOriginInternal(
+ principalInfo.get_ContentPrincipalInfo().originNoSuffix()) &&
+ metadata.persistenceType() != PERSISTENCE_TYPE_PERSISTENT)) {
+ return nullptr;
+ }
+
Maybe<ContentParentId> contentParentId;
uint64_t childID = BackgroundParent::GetChildID(Manager());
@@ -9087,7 +9153,7 @@ mozilla::ipc::IPCResult Factory::RecvPBackgroundIDBFactoryRequestConstructor(
auto* op = static_cast<FactoryOp*>(aActor);
- MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(op));
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(op));
return IPC_OK();
}
@@ -12247,8 +12313,9 @@ nsresult QuotaClient::GetUsageForOriginInternal(
// If this fails, it probably means we are in a serious situation.
// e.g. Filesystem corruption. Will handle this in bug 1521541.
QM_TRY(MOZ_TO_RESULT(RemoveDatabaseFilesAndDirectory(
- *directory, subdirNameBase, nullptr, aPersistenceType,
- aOriginMetadata, u""_ns)),
+ *directory, subdirNameBase, /* aQuotaManager */ nullptr,
+ aPersistenceType, aOriginMetadata,
+ /* aDatabaseName */ u""_ns)),
Err(NS_ERROR_UNEXPECTED));
databaseFilenames.Remove(subdirNameBase);
@@ -14476,10 +14543,6 @@ void FactoryOp::StringifyState(nsACString& aResult) const {
aResult.AppendLiteral("Initial");
return;
- case State::FinishOpen:
- aResult.AppendLiteral("FinishOpen");
- return;
-
case State::DirectoryOpenPending:
aResult.AppendLiteral("DirectoryOpenPending");
return;
@@ -14538,23 +14601,50 @@ void FactoryOp::Stringify(nsACString& aResult) const {
}
nsresult FactoryOp::Open() {
- AssertIsOnMainThread();
+ AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::Initial);
+ MOZ_ASSERT(mOriginMetadata.mOrigin.IsEmpty());
+ MOZ_ASSERT(!mDirectoryLock);
- if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
- !OperationMayProceed()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+ IsActorDestroyed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
+ QM_TRY(QuotaManager::EnsureCreated());
+
+ QuotaManager* const quotaManager = QuotaManager::Get();
+ MOZ_ASSERT(quotaManager);
+
+ const DatabaseMetadata& metadata = mCommonParams.metadata();
+
+ const PersistenceType persistenceType = metadata.persistenceType();
+
const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
+
+ QM_TRY_UNWRAP(auto principalMetadata,
+ quotaManager->GetInfoFromValidatedPrincipalInfo(principalInfo));
+
+ mOriginMetadata = {std::move(principalMetadata), persistenceType};
+
if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
MOZ_ASSERT(mCommonParams.metadata().persistenceType() ==
PERSISTENCE_TYPE_PERSISTENT);
+
+ mEnforcingQuota = false;
} else if (principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
const ContentPrincipalInfo& contentPrincipalInfo =
principalInfo.get_ContentPrincipalInfo();
- if (contentPrincipalInfo.attrs().mPrivateBrowsingId != 0) {
+
+ MOZ_ASSERT_IF(
+ QuotaManager::IsOriginInternal(contentPrincipalInfo.originNoSuffix()),
+ mCommonParams.metadata().persistenceType() ==
+ PERSISTENCE_TYPE_PERSISTENT);
+
+ mEnforcingQuota = persistenceType != PERSISTENCE_TYPE_PERSISTENT;
+
+ if (mOriginMetadata.mIsPrivate) {
if (StaticPrefs::dom_indexedDB_privateBrowsing_enabled()) {
// Explicitly disallow moz-extension urls from using the encrypted
// indexedDB storage mode when the caller is an extension (see Bug
@@ -14573,35 +14663,46 @@ nsresult FactoryOp::Open() {
MOZ_ASSERT(false);
}
- QM_TRY_INSPECT(const auto& permission, CheckPermission());
+ QuotaManager::GetStorageId(persistenceType, mOriginMetadata.mOrigin,
+ Client::IDB, mDatabaseId);
- MOZ_ASSERT(permission == PermissionValue::kPermissionAllowed ||
- permission == PermissionValue::kPermissionDenied);
+ mDatabaseId.Append('*');
+ mDatabaseId.Append(NS_ConvertUTF16toUTF8(metadata.name()));
- if (permission == PermissionValue::kPermissionDenied) {
- return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
- }
+ // Need to get database file path before opening the directory.
+ // XXX: For what reason?
+ QM_TRY_UNWRAP(
+ mDatabaseFilePath,
+ ([this, metadata, quotaManager]() -> mozilla::Result<nsString, nsresult> {
+ QM_TRY_INSPECT(const auto& dbFile,
+ quotaManager->GetOriginDirectory(mOriginMetadata));
- {
- // These services have to be started on the main thread currently.
+ QM_TRY(MOZ_TO_RESULT(dbFile->Append(
+ NS_LITERAL_STRING_FROM_CSTRING(IDB_DIRECTORY_NAME))));
- IndexedDatabaseManager* mgr;
- if (NS_WARN_IF(!(mgr = IndexedDatabaseManager::GetOrCreate()))) {
- IDB_REPORT_INTERNAL_ERR();
- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
- }
+ QM_TRY(MOZ_TO_RESULT(
+ dbFile->Append(GetDatabaseFilenameBase(metadata.name(),
+ mOriginMetadata.mIsPrivate) +
+ kSQLiteSuffix)));
- nsCOMPtr<mozIStorageService> ss;
- if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) {
- IDB_REPORT_INTERNAL_ERR();
- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
- }
- }
+ QM_TRY_RETURN(
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
+ }()));
- MOZ_ASSERT(permission == PermissionValue::kPermissionAllowed);
+ // Open directory
+ mState = State::DirectoryOpenPending;
- mState = State::FinishOpen;
- MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
+ quotaManager->OpenClientDirectory({mOriginMetadata, Client::IDB})
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr(this)](
+ const ClientDirectoryLockPromise::ResolveOrRejectValue& aValue) {
+ if (aValue.IsResolve()) {
+ self->DirectoryLockAcquired(aValue.ResolveValue());
+ } else {
+ self->DirectoryLockFailed();
+ }
+ });
return NS_OK;
}
@@ -14724,37 +14825,6 @@ void FactoryOp::FinishSendResults() {
mFactory = nullptr;
}
-Result<PermissionValue, nsresult> FactoryOp::CheckPermission() {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mState == State::Initial);
-
- const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
- MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo ||
- principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
-
- if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
- MOZ_ASSERT(mState == State::Initial);
-
- return PermissionValue::kPermissionAllowed;
- }
-
- QM_TRY_INSPECT(
- const auto& permission,
- ([persistenceType = mCommonParams.metadata().persistenceType(),
- origin = QuotaManager::GetOriginFromValidatedPrincipalInfo(
- principalInfo)]() -> mozilla::Result<PermissionValue, nsresult> {
- if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
- if (QuotaManager::IsOriginInternal(origin)) {
- return PermissionValue::kPermissionAllowed;
- }
- return Err(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
- }
- return PermissionValue::kPermissionAllowed;
- })());
-
- return permission;
-}
-
nsresult FactoryOp::SendVersionChangeMessages(
DatabaseActorInfo* aDatabaseActorInfo, Maybe<Database&> aOpeningDatabase,
uint64_t aOldVersion, const Maybe<uint64_t>& aNewVersion) {
@@ -14795,91 +14865,6 @@ nsresult FactoryOp::SendVersionChangeMessages(
return NS_OK;
} // namespace indexedDB
-nsresult FactoryOp::FinishOpen() {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mState == State::FinishOpen);
- MOZ_ASSERT(mOriginMetadata.mOrigin.IsEmpty());
- MOZ_ASSERT(!mDirectoryLock);
-
- if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
- IsActorDestroyed()) {
- IDB_REPORT_INTERNAL_ERR();
- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
- }
-
- QM_TRY(QuotaManager::EnsureCreated());
-
- QuotaManager* const quotaManager = QuotaManager::Get();
- MOZ_ASSERT(quotaManager);
-
- const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
-
- const DatabaseMetadata& metadata = mCommonParams.metadata();
-
- const PersistenceType persistenceType = metadata.persistenceType();
-
- if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
- mOriginMetadata = {QuotaManager::GetInfoForChrome(), persistenceType};
-
- MOZ_ASSERT(QuotaManager::IsOriginInternal(mOriginMetadata.mOrigin));
-
- mEnforcingQuota = false;
- } else {
- MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
-
- QM_TRY_UNWRAP(
- auto principalMetadata,
- quotaManager->GetInfoFromValidatedPrincipalInfo(principalInfo));
-
- mOriginMetadata = {std::move(principalMetadata), persistenceType};
-
- mEnforcingQuota = persistenceType != PERSISTENCE_TYPE_PERSISTENT;
- }
-
- QuotaManager::GetStorageId(persistenceType, mOriginMetadata.mOrigin,
- Client::IDB, mDatabaseId);
-
- mDatabaseId.Append('*');
- mDatabaseId.Append(NS_ConvertUTF16toUTF8(metadata.name()));
-
- // Need to get database file path before opening the directory.
- // XXX: For what reason?
- QM_TRY_UNWRAP(
- mDatabaseFilePath,
- ([this, metadata, quotaManager]() -> mozilla::Result<nsString, nsresult> {
- QM_TRY_INSPECT(const auto& dbFile,
- quotaManager->GetOriginDirectory(mOriginMetadata));
-
- QM_TRY(MOZ_TO_RESULT(dbFile->Append(
- NS_LITERAL_STRING_FROM_CSTRING(IDB_DIRECTORY_NAME))));
-
- QM_TRY(MOZ_TO_RESULT(
- dbFile->Append(GetDatabaseFilenameBase(metadata.name(),
- mOriginMetadata.mIsPrivate) +
- kSQLiteSuffix)));
-
- QM_TRY_RETURN(
- MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
- }()));
-
- // Open directory
- mState = State::DirectoryOpenPending;
-
- quotaManager->OpenClientDirectory({mOriginMetadata, Client::IDB})
- ->Then(
- GetCurrentSerialEventTarget(), __func__,
- [self = RefPtr(this)](
- const ClientDirectoryLockPromise::ResolveOrRejectValue& aValue) {
- if (aValue.IsResolve()) {
- self->DirectoryLockAcquired(aValue.ResolveValue());
- } else {
- self->DirectoryLockFailed();
- }
- });
-
- return NS_OK;
-}
-
bool FactoryOp::MustWaitFor(const FactoryOp& aExistingOp) {
AssertIsOnOwningThread();
@@ -14920,10 +14905,6 @@ FactoryOp::Run() {
QM_WARNONLY_TRY(MOZ_TO_RESULT(Open()), handleError);
break;
- case State::FinishOpen:
- QM_WARNONLY_TRY(MOZ_TO_RESULT(FinishOpen()), handleError);
- break;
-
case State::DatabaseOpenPending:
QM_WARNONLY_TRY(MOZ_TO_RESULT(DatabaseOpen()), handleError);
break;
@@ -15328,7 +15309,7 @@ nsresult OpenDatabaseOp::LoadDatabaseInformation(
QM_TRY_INSPECT(
const auto& lastIndexId,
- ([&aConnection,
+ ([this, &aConnection,
&objectStores]() -> mozilla::Result<IndexOrObjectStoreId, nsresult> {
// Load index information
QM_TRY_INSPECT(
@@ -15345,7 +15326,7 @@ nsresult OpenDatabaseOp::LoadDatabaseInformation(
QM_TRY(CollectWhileHasResult(
*stmt,
- [&lastIndexId, &objectStores, &aConnection,
+ [this, &lastIndexId, &objectStores, &aConnection,
usedIds = Maybe<nsTHashSet<uint64_t>>{},
usedNames = Maybe<nsTHashSet<nsString>>{}](
auto& stmt) mutable -> mozilla::Result<Ok, nsresult> {
@@ -15436,8 +15417,7 @@ nsresult OpenDatabaseOp::LoadDatabaseInformation(
indexMetadata->mCommonMetadata.locale();
const bool& isAutoLocale =
indexMetadata->mCommonMetadata.autoLocale();
- const nsCString& systemLocale =
- IndexedDatabaseManager::GetLocale();
+ const nsCString& systemLocale = mFactory->GetSystemLocale();
if (!systemLocale.IsEmpty() && isAutoLocale &&
!indexedLocale.Equals(systemLocale)) {
QM_TRY(MOZ_TO_RESULT(UpdateLocaleAwareIndex(
@@ -16985,7 +16965,8 @@ TransactionBase::CommitOp::Run() {
connection->FinishWriteTransaction();
if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup) {
- connection->DoIdleProcessing(/* aNeedsCheckpoint */ true);
+ connection->DoIdleProcessing(/* aNeedsCheckpoint */ true,
+ /* aInterrupted */ Atomic<bool>(false));
connection->EnableQuotaChecks();
}
diff --git a/dom/indexedDB/ActorsParent.h b/dom/indexedDB/ActorsParent.h
index ab6c6c142f..45c0bf8688 100644
--- a/dom/indexedDB/ActorsParent.h
+++ b/dom/indexedDB/ActorsParent.h
@@ -38,10 +38,11 @@ class PBackgroundIDBFactoryParent;
class PBackgroundIndexedDBUtilsParent;
already_AddRefed<PBackgroundIDBFactoryParent> AllocPBackgroundIDBFactoryParent(
- const LoggingInfo& aLoggingInfo);
+ const LoggingInfo& aLoggingInfo, const nsACString& aSystemLocale);
bool RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
- const LoggingInfo& aLoggingInfo);
+ const LoggingInfo& aLoggingInfo,
+ const nsACString& aSystemLocale);
bool DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor);
diff --git a/dom/indexedDB/ActorsParentCommon.cpp b/dom/indexedDB/ActorsParentCommon.cpp
index 637906b6d3..1b92e15dad 100644
--- a/dom/indexedDB/ActorsParentCommon.cpp
+++ b/dom/indexedDB/ActorsParentCommon.cpp
@@ -728,7 +728,7 @@ nsresult ExecuteSimpleSQLSequence(mozIStorageConnection& aConnection,
Span<const nsLiteralCString> aSQLCommands) {
for (const auto& aSQLCommand : aSQLCommands) {
const auto extraInfo = quota::ScopedLogExtraInfo{
- quota::ScopedLogExtraInfo::kTagQuery, aSQLCommand};
+ quota::ScopedLogExtraInfo::kTagQueryTainted, aSQLCommand};
QM_TRY(MOZ_TO_RESULT(aConnection.ExecuteSimpleSQL(aSQLCommand)));
}
diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp
index be34e1914d..81dce07d7e 100644
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -242,6 +242,12 @@ Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForMainThreadJSInternal(
return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
+ nsresult rv = mgr->EnsureLocale();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+ };
+
return CreateInternal(aGlobal, std::move(aPrincipalInfo),
/* aInnerWindowID */ 0);
}
@@ -283,10 +289,17 @@ nsresult IDBFactory::AllowedForWindowInternal(
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
- if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
+ IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
+ if (NS_WARN_IF(!mgr)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
+ nsresult rv = mgr->EnsureLocale();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ };
+
StorageAccess access = StorageAllowedForWindow(aWindow);
// the factory callsite records whether the browser is in private browsing.
@@ -341,10 +354,16 @@ bool IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
- if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
+ IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
+ if (NS_WARN_IF(!mgr)) {
return false;
}
+ nsresult rv = mgr->EnsureLocale();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return false;
+ };
+
if (aPrincipal->IsSystemPrincipal()) {
if (aIsSystemPrincipal) {
*aIsSystemPrincipal = true;
@@ -573,19 +592,20 @@ RefPtr<IDBOpenDBRequest> IDBFactory::OpenInternal(
PersistenceType persistenceType;
- bool isInternal = principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo;
- if (!isInternal &&
+ bool isPersistent =
+ principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo;
+ if (!isPersistent &&
principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
nsCString origin =
principalInfo.get_ContentPrincipalInfo().originNoSuffix();
- isInternal = QuotaManager::IsOriginInternal(origin);
+ isPersistent = QuotaManager::IsOriginInternal(origin);
}
const bool isPrivate =
principalInfo.type() == PrincipalInfo::TContentPrincipalInfo &&
principalInfo.get_ContentPrincipalInfo().attrs().mPrivateBrowsingId > 0;
- if (isInternal) {
+ if (isPersistent) {
// Chrome privilege and internal origins always get persistent storage.
persistenceType = PERSISTENCE_TYPE_PERSISTENT;
} else if (isPrivate) {
@@ -641,7 +661,8 @@ RefPtr<IDBOpenDBRequest> IDBFactory::OpenInternal(
mBackgroundActor = static_cast<BackgroundFactoryChild*>(
backgroundActor->SendPBackgroundIDBFactoryConstructor(
- actor, idbThreadLocal->GetLoggingInfo()));
+ actor, idbThreadLocal->GetLoggingInfo(),
+ IndexedDatabaseManager::GetLocale()));
if (NS_WARN_IF(!mBackgroundActor)) {
mBackgroundActorFailed = true;
diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp
index 5ee16ec5e9..0558c38826 100644
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -296,25 +296,6 @@ nsresult IndexedDatabaseManager::Init() {
Preferences::RegisterCallbackAndCall(MaxPreloadExtraRecordsPrefChangeCallback,
kPrefMaxPreloadExtraRecords);
- nsAutoCString acceptLang;
- Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
-
- // Split values on commas.
- for (const auto& lang :
- nsCCharSeparatedTokenizer(acceptLang, ',').ToRange()) {
- mozilla::intl::LocaleCanonicalizer::Vector asciiString{};
- auto result = mozilla::intl::LocaleCanonicalizer::CanonicalizeICULevel1(
- PromiseFlatCString(lang).get(), asciiString);
- if (result.isOk()) {
- mLocale.AssignASCII(asciiString);
- break;
- }
- }
-
- if (mLocale.IsEmpty()) {
- mLocale.AssignLiteral("en_US");
- }
-
return NS_OK;
}
@@ -652,11 +633,37 @@ void IndexedDatabaseManager::LoggingModePrefChangedCallback(
}
}
+nsresult IndexedDatabaseManager::EnsureLocale() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoCString acceptLang;
+ Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
+
+ // Split values on commas.
+ for (const auto& lang :
+ nsCCharSeparatedTokenizer(acceptLang, ',').ToRange()) {
+ mozilla::intl::LocaleCanonicalizer::Vector asciiString{};
+ auto result = mozilla::intl::LocaleCanonicalizer::CanonicalizeICULevel1(
+ PromiseFlatCString(lang).get(), asciiString);
+ if (result.isOk()) {
+ mLocale.AssignASCII(asciiString);
+ break;
+ }
+ }
+
+ if (mLocale.IsEmpty()) {
+ mLocale.AssignLiteral("en_US");
+ }
+
+ return NS_OK;
+}
+
// static
const nsCString& IndexedDatabaseManager::GetLocale() {
IndexedDatabaseManager* idbManager = Get();
MOZ_ASSERT(idbManager, "IDBManager is not ready!");
+ MOZ_ASSERT(!idbManager->mLocale.IsEmpty());
return idbManager->mLocale;
}
diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h
index 5bf6485aff..0766143dd6 100644
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -123,6 +123,9 @@ class IndexedDatabaseManager final {
nsresult FlushPendingFileDeletions();
+ // XXX This extra explicit initialization should go away with bug 1730706.
+ nsresult EnsureLocale();
+
static const nsCString& GetLocale();
static bool ResolveSandboxBinding(JSContext* aCx);
diff --git a/dom/indexedDB/SchemaUpgrades.cpp b/dom/indexedDB/SchemaUpgrades.cpp
index 6066390740..234c4c9f04 100644
--- a/dom/indexedDB/SchemaUpgrades.cpp
+++ b/dom/indexedDB/SchemaUpgrades.cpp
@@ -2861,8 +2861,10 @@ nsresult UpgradeFileIdsFunction::Init(nsIFile* aFMDirectory,
// purpose is to store file ids without adding more complexity or code
// duplication.
auto fileManager = MakeSafeRefPtr<DatabaseFileManager>(
- PERSISTENCE_TYPE_INVALID, quota::OriginMetadata{}, u""_ns, ""_ns, false,
- false);
+ PERSISTENCE_TYPE_INVALID, quota::OriginMetadata{},
+ /* aDatabaseName */ u""_ns, /* aDatabaseID */ ""_ns,
+ /* aEnforcingQuota */ false,
+ /* aIsInPrivateBrowsingMode */ false);
nsresult rv = fileManager->Init(aFMDirectory, aConnection);
if (NS_WARN_IF(NS_FAILED(rv))) {
diff --git a/dom/indexedDB/SerializationHelpers.h b/dom/indexedDB/SerializationHelpers.h
index 7bc05720d4..488c1eb044 100644
--- a/dom/indexedDB/SerializationHelpers.h
+++ b/dom/indexedDB/SerializationHelpers.h
@@ -10,6 +10,7 @@
#include "ipc/EnumSerializer.h"
#include "ipc/IPCMessageUtilsSpecializations.h"
+#include "mozilla/dom/BindingIPCUtils.h"
#include "mozilla/dom/indexedDB/Key.h"
#include "mozilla/dom/indexedDB/KeyPath.h"
#include "mozilla/dom/IDBCursor.h"
@@ -61,10 +62,8 @@ struct ParamTraits<mozilla::dom::indexedDB::KeyPath> {
template <>
struct ParamTraits<mozilla::dom::IDBCursor::Direction>
- : public ContiguousEnumSerializer<
- mozilla::dom::IDBCursor::Direction,
- mozilla::dom::IDBCursor::Direction::Next,
- mozilla::dom::IDBCursor::Direction::EndGuard_> {};
+ : public mozilla::dom::WebIDLEnumSerializer<
+ mozilla::dom::IDBCursor::Direction> {};
template <>
struct ParamTraits<mozilla::dom::IDBTransaction::Mode>
diff --git a/dom/indexedDB/test/abort_on_reload.html b/dom/indexedDB/test/abort_on_reload.html
index 4e4fe3a339..7b3cba6d95 100644
--- a/dom/indexedDB/test/abort_on_reload.html
+++ b/dom/indexedDB/test/abort_on_reload.html
@@ -3,7 +3,7 @@
<body>
<script>
function createDb() {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
const openRequest = indexedDB.open("test-abort-on-reload", 1);
openRequest.onsuccess = () => {
const db = openRequest.result;
@@ -14,7 +14,7 @@
};
resolve();
};
- openRequest.onupgradeneeded = (evt) => {
+ openRequest.onupgradeneeded = () => {
// Interrupt upgrade
window.location.reload();
opener.info('reload requested\n');
@@ -24,7 +24,7 @@
}
function reset() {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
const request = indexedDB.deleteDatabase("test-abort-on-reload");
request.onsuccess = resolve;
});
diff --git a/dom/indexedDB/test/bfcache_page1.html b/dom/indexedDB/test/bfcache_page1.html
index e537d42008..a78d4c0d94 100644
--- a/dom/indexedDB/test/bfcache_page1.html
+++ b/dom/indexedDB/test/bfcache_page1.html
@@ -6,7 +6,7 @@
request.onupgradeneeded = function(e) {
var db = e.target.result;
// This should never be called
- db.onversionchange = function(e) {
+ db.onversionchange = function() {
db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
};
var trans = e.target.transaction;
diff --git a/dom/indexedDB/test/blob_worker_crash_iframe.html b/dom/indexedDB/test/blob_worker_crash_iframe.html
index 15d8277515..8f98ba206a 100644
--- a/dom/indexedDB/test/blob_worker_crash_iframe.html
+++ b/dom/indexedDB/test/blob_worker_crash_iframe.html
@@ -80,7 +80,7 @@ dump("EXCEPTION IN CREATION: " + e + "\n " + e.stack + "\n");
objectStore.delete(42).onsuccess = closeDBTellOwningThread;
}
- function closeDBTellOwningThread(event) {
+ function closeDBTellOwningThread() {
// Now that worker has latched the blob, clean up the database.
db.close();
db = null;
diff --git a/dom/indexedDB/test/browser_private_idb.js b/dom/indexedDB/test/browser_private_idb.js
index 5627361fc6..fb8108ef35 100644
--- a/dom/indexedDB/test/browser_private_idb.js
+++ b/dom/indexedDB/test/browser_private_idb.js
@@ -12,7 +12,7 @@ async function idbCheckFunc() {
try {
console.log("opening db");
const req = factory.open("db", 1);
- const result = await new Promise((resolve, reject) => {
+ const result = await new Promise(resolve => {
req.onerror = () => {
resolve("error");
};
@@ -21,7 +21,7 @@ async function idbCheckFunc() {
resolve("created");
};
// ...so this will lose the race
- req.onsuccess = event => {
+ req.onsuccess = () => {
resolve("already-exists");
};
});
diff --git a/dom/indexedDB/test/bug839193.js b/dom/indexedDB/test/bug839193.js
index b5b951e32e..d267c00348 100644
--- a/dom/indexedDB/test/bug839193.js
+++ b/dom/indexedDB/test/bug839193.js
@@ -6,7 +6,7 @@ const nsIQuotaManagerService = Ci.nsIQuotaManagerService;
var gURI = Services.io.newURI("http://localhost");
-function onUsageCallback(request) {}
+function onUsageCallback() {}
function onLoad() {
var quotaManagerService = Cc[
diff --git a/dom/indexedDB/test/error_events_abort_transactions_iframe.html b/dom/indexedDB/test/error_events_abort_transactions_iframe.html
index 672b7c3a5b..b6df9d8b0b 100644
--- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html
+++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html
@@ -29,7 +29,7 @@
finishTest();
}
- function unexpectedSuccessHandler(event) {
+ function unexpectedSuccessHandler() {
ok(false, "got success when it was not expected!");
finishTest();
}
@@ -43,7 +43,7 @@
}, 0);
}
- window.onerror = function(message, filename, lineno) {
+ window.onerror = function(message) {
is(message, "ConstraintError", "Expect a constraint error");
};
@@ -82,7 +82,7 @@
request = objectStore.add({}, 1);
request.onsuccess = unexpectedSuccessHandler;
- request.onerror = function(event) {
+ request.onerror = function() {
// Don't do anything! ConstraintError is expected in window.onerror.
};
event = yield undefined;
diff --git a/dom/indexedDB/test/event_propagation_iframe.html b/dom/indexedDB/test/event_propagation_iframe.html
index 3788958014..2d852b3b98 100644
--- a/dom/indexedDB/test/event_propagation_iframe.html
+++ b/dom/indexedDB/test/event_propagation_iframe.html
@@ -101,7 +101,7 @@
event = yield undefined;
request = objectStore.add({}, 1);
- request.onsuccess = function(event) {
+ request.onsuccess = function() {
ok(false, "Did not expect second add to succeed.");
};
request.onerror = errorEventCounter;
@@ -119,7 +119,7 @@
event = yield undefined;
request = objectStore.add({}, 1);
- request.onsuccess = function(event) {
+ request.onsuccess = function() {
ok(false, "Did not expect second add to succeed.");
};
request.onerror = errorEventCounter;
diff --git a/dom/indexedDB/test/exceptions_in_events_iframe.html b/dom/indexedDB/test/exceptions_in_events_iframe.html
index 25a4f01e77..b67d4c5b21 100644
--- a/dom/indexedDB/test/exceptions_in_events_iframe.html
+++ b/dom/indexedDB/test/exceptions_in_events_iframe.html
@@ -31,7 +31,7 @@
finishTest();
}
- function unexpectedSuccessHandler(event) {
+ function unexpectedSuccessHandler() {
ok(false, "got success when it was not expected!");
finishTest();
}
@@ -105,7 +105,7 @@
ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
request = objectStore.add({}, 1);
- request.onsuccess = function(event) {
+ request.onsuccess = function() {
throw new Error("foo");
};
diff --git a/dom/indexedDB/test/head.js b/dom/indexedDB/test/head.js
index 802f093c6b..b06658e466 100644
--- a/dom/indexedDB/test/head.js
+++ b/dom/indexedDB/test/head.js
@@ -74,7 +74,7 @@ function triggerSecondaryCommand(popup, win) {
EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {}, win);
}
-function dismissNotification(popup) {
+function dismissNotification() {
info("dismissing notification");
executeSoon(function () {
EventUtils.synthesizeKey("KEY_Escape");
diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js
index 3555abf722..2ba2a440df 100644
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
+/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
+
// testSteps is expected to be defined by the test using this file.
/* global testSteps:false */
@@ -482,7 +484,7 @@ function workerScript() {
self.executeSoon = function (_fun_) {
var channel = new MessageChannel();
channel.port1.postMessage("");
- channel.port2.onmessage = function (event) {
+ channel.port2.onmessage = function () {
_fun_();
};
};
diff --git a/dom/indexedDB/test/leaving_page_iframe.html b/dom/indexedDB/test/leaving_page_iframe.html
index 4ed299df33..712fb89991 100644
--- a/dom/indexedDB/test/leaving_page_iframe.html
+++ b/dom/indexedDB/test/leaving_page_iframe.html
@@ -23,7 +23,7 @@ function madeMod() {
parent.postMessage("didcommit", "*");
};
- store.put({ hello: "officer" }, 42).onsuccess = function(e) {
+ store.put({ hello: "officer" }, 42).onsuccess = function() {
// Make this transaction run until the end of time or until the page is
// navigated away, whichever comes first.
function doGet() {
diff --git a/dom/indexedDB/test/mochitest-common.toml b/dom/indexedDB/test/mochitest-common.toml
index 4ba2312bd5..d42228da45 100644
--- a/dom/indexedDB/test/mochitest-common.toml
+++ b/dom/indexedDB/test/mochitest-common.toml
@@ -282,7 +282,7 @@ skip-if = ["true"] # disabled for the moment
["test_names_sorted.html"]
skip-if = [
"xorigin && !debug", # Hangs
- "os == 'linux' && bits == 64 && !debug", # Bug 1602927
+ "os == 'linux' && os_version == '18.04' && bits == 64 && !debug", # Bug 1602927
]
["test_objectCursors.html"]
@@ -382,7 +382,9 @@ skip-if = [
["test_upgrade_add_index.html"]
skip-if = [
- "!debug && bits == 64 && (os == 'linux' || os == 'mac')",
+ "os == 'linux' && os_version == '18.04' && bits == 64 && !debug",
+ "apple_silicon && !debug",
+ "apple_catalina && !debug",
"os == 'win'", #Bug 1637715
]
scheme = "https"
diff --git a/dom/indexedDB/test/test_abort_on_reload.html b/dom/indexedDB/test/test_abort_on_reload.html
index fd31e709c6..43e3178977 100644
--- a/dom/indexedDB/test/test_abort_on_reload.html
+++ b/dom/indexedDB/test/test_abort_on_reload.html
@@ -17,7 +17,7 @@
openedWindow = window.open("abort_on_reload.html");
}
- function messageListener(event) {
+ function messageListener() {
ok(true, "reload recorded");
if (++reloads == 20) {
diff --git a/dom/indexedDB/test/test_event_listener_leaks.html b/dom/indexedDB/test/test_event_listener_leaks.html
index d1d9a69068..ebe5c202dd 100644
--- a/dom/indexedDB/test/test_event_listener_leaks.html
+++ b/dom/indexedDB/test/test_event_listener_leaks.html
@@ -37,7 +37,7 @@ async function useIDB(contentWindow) {
store.get(0).onsuccess = spin;
}
- store.put(0, "purgatory").onsuccess = e => {
+ store.put(0, "purgatory").onsuccess = () => {
contentWindow.putCount += 1;
spin();
};
diff --git a/dom/indexedDB/test/test_open_for_principal.html b/dom/indexedDB/test/test_open_for_principal.html
index bd9da12f74..04cd86126b 100644
--- a/dom/indexedDB/test/test_open_for_principal.html
+++ b/dom/indexedDB/test/test_open_for_principal.html
@@ -10,6 +10,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
+ // eslint-disable-next-line require-yield
function* testSteps()
{
is("open" in indexedDB, true, "open() defined");
diff --git a/dom/indexedDB/test/third_party_window.html b/dom/indexedDB/test/third_party_window.html
index 14b16bf5d4..20d453d7a3 100644
--- a/dom/indexedDB/test/third_party_window.html
+++ b/dom/indexedDB/test/third_party_window.html
@@ -14,7 +14,7 @@
let iframe = document.getElementById("iframe1");
iframe.src = evt.data.iframeUrl;
- iframe.addEventListener("load", e => {
+ iframe.addEventListener("load", () => {
iframe.contentWindow.postMessage(JSON.stringify(evt.data), "*");
});
diff --git a/dom/indexedDB/test/unit/test_blocked_order.js b/dom/indexedDB/test/unit/test_blocked_order.js
index 212b1b3254..0301c12df2 100644
--- a/dom/indexedDB/test/unit/test_blocked_order.js
+++ b/dom/indexedDB/test/unit/test_blocked_order.js
@@ -33,7 +33,7 @@ function* testSteps() {
let db = request.result;
is(db.version, 1, "Got version 1");
- db.onversionchange = function (event) {
+ db.onversionchange = function () {
info("Closing database " + thisIndex);
db.close();
@@ -51,7 +51,7 @@ function* testSteps() {
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
- request.onblocked = function (event) {
+ request.onblocked = function () {
ok(false, "Should not receive a blocked event");
};
@@ -95,7 +95,7 @@ function* testSteps() {
let db = request.result;
is(db.version, 1, "Got version 1");
- db.onversionchange = function (event) {
+ db.onversionchange = function () {
if (thisIndex == databaseCount - 1) {
info("Closing all databases with version 1");
@@ -121,7 +121,7 @@ function* testSteps() {
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
- request.onblocked = function (event) {
+ request.onblocked = function () {
ok(false, "Should not receive a blocked event");
};
diff --git a/dom/indexedDB/test/unit/test_cleanup_transaction.js b/dom/indexedDB/test/unit/test_cleanup_transaction.js
index cac3c9bf60..25af4c5729 100644
--- a/dom/indexedDB/test/unit/test_cleanup_transaction.js
+++ b/dom/indexedDB/test/unit/test_cleanup_transaction.js
@@ -74,12 +74,12 @@ function* testSteps() {
event.stopPropagation();
};
- trans.oncomplete = function (event) {
+ trans.oncomplete = function () {
i++;
j++;
testGenerator.next(true);
};
- trans.onabort = function (event) {
+ trans.onabort = function () {
is(trans.error.name, "QuotaExceededError", "Reached quota limit");
testGenerator.next(false);
};
diff --git a/dom/indexedDB/test/unit/test_clear.js b/dom/indexedDB/test/unit/test_clear.js
index d504ff8851..87eef2c0ab 100644
--- a/dom/indexedDB/test/unit/test_clear.js
+++ b/dom/indexedDB/test/unit/test_clear.js
@@ -70,7 +70,7 @@ function* testSteps() {
request = db.transaction("foo").objectStore("foo").openCursor();
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
let cursor = request.result;
if (cursor) {
ok(false, "Shouldn't have any entries");
diff --git a/dom/indexedDB/test/unit/test_connection_idle_maintenance.js b/dom/indexedDB/test/unit/test_connection_idle_maintenance.js
new file mode 100644
index 0000000000..288f656c65
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_connection_idle_maintenance.js
@@ -0,0 +1,97 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* exported testSteps */
+async function testSteps() {
+ // A constant used to deal with small decrease in usage when transactions are
+ // transferred from the WAL file back into the original database, also called
+ // as checkpointing.
+ const cosmologicalConstant = 31768;
+
+ // The length of time that database connections will be held open after all
+ // transactions have completed before doing idle maintenance.
+ const connectionIdleMaintenanceMS = 2 * 1000;
+
+ const name = "test_connection_idle_maintenance";
+ const abc = "abcdefghijklmnopqrstuvwxyz";
+
+ // IndexedDB on Android does `PRAGMA auto_vacuum = FULL`, so the freelist
+ // pages are moved to the end of the database file and the database file is
+ // truncated to remove the freelist pages at every transaction commit.
+ if (mozinfo.os == "android") {
+ info("Test disabled on Android for now");
+ return;
+ }
+
+ info("Creating database");
+
+ let request = indexedDB.open(name, 1);
+
+ let event = await expectingUpgrade(request);
+
+ let database = event.target.result;
+
+ let objectStore = database.createObjectStore(name);
+
+ // Add lots of data...
+ for (let i = 0; i < 10000; i++) {
+ objectStore.add(abc, i);
+ }
+
+ // And then clear it so that maintenance has some space to reclaim.
+ objectStore.clear();
+
+ await expectingSuccess(request);
+
+ info("Getting database usage before maintenance");
+
+ let databaseUsageBeforeMaintenance = await new Promise(function (resolve) {
+ getCurrentUsage(function (request) {
+ resolve(request.result.databaseUsage);
+ });
+ });
+
+ info("Waiting for maintenance to start");
+
+ // This time is a double of connectionIdleMaintenanceMS which should be
+ // pessimistic enough to work with randomly slowed down threads in the chaos
+ // mode.
+ await new Promise(function (resolve) {
+ do_timeout(2 * connectionIdleMaintenanceMS, resolve);
+ });
+
+ info("Waiting for maintenance to finish");
+
+ // This time is a double of connectionIdleMaintenanceMS which should be
+ // pessimistic enough to work with randomly slowed down threads in the chaos
+ // mode.
+ await new Promise(function (resolve) {
+ do_timeout(2 * connectionIdleMaintenanceMS, resolve);
+ });
+
+ info("Getting database usage after maintenance");
+
+ let databaseUsageAfterMaintenance = await new Promise(function (resolve) {
+ getCurrentUsage(function (request) {
+ resolve(request.result.databaseUsage);
+ });
+ });
+
+ info(
+ "Database usage before: " +
+ databaseUsageBeforeMaintenance +
+ ". " +
+ "Database usage after: " +
+ databaseUsageAfterMaintenance
+ );
+
+ // Checkpointing done immediately after the maintenance can slightly decrease
+ // the usage even when the maintenance was not run at all.
+ ok(
+ databaseUsageBeforeMaintenance - databaseUsageAfterMaintenance >=
+ cosmologicalConstant,
+ "Maintenance significantly decreased database usage"
+ );
+}
diff --git a/dom/indexedDB/test/unit/test_connection_idle_maintenance_stop.js b/dom/indexedDB/test/unit/test_connection_idle_maintenance_stop.js
new file mode 100644
index 0000000000..33dc69b210
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_connection_idle_maintenance_stop.js
@@ -0,0 +1,204 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* exported testSteps */
+async function testSteps() {
+ // A constant used to deal with small decrease in usage when transactions are
+ // transferred from the WAL file back into the original database, also called
+ // as checkpointing.
+ const cosmologicalConstant = 32768;
+
+ // The maximum number of threads that can be used for database activity at a
+ // single time.
+ const maxConnectionThreadCount = 20;
+
+ // The length of time that database connections will be held open after all
+ // transactions have completed before doing idle maintenance.
+ const connectionIdleMaintenanceMS = 2 * 1000;
+
+ const name = "test_connection_idle_maintenance_stop";
+ const abc = "abcdefghijklmnopqrstuvwxyz";
+
+ // IndexedDB on Android does `PRAGMA auto_vacuum = FULL`, so the freelist
+ // pages are moved to the end of the database file and the database file is
+ // truncated to remove the freelist pages at every transaction commit.
+ if (mozinfo.os == "android") {
+ info("Test disabled on Android for now");
+ return;
+ }
+
+ info("Setting pref");
+
+ Services.prefs.setIntPref(
+ "dom.indexedDB.connectionIdleMaintenance.pauseOnConnectionThreadMs",
+ 2 * connectionIdleMaintenanceMS
+ );
+
+ info("Forcing only one connection thread to be available");
+
+ let done = false;
+
+ // Create databases which will continuously keep their connection threads
+ // busy.
+ const completePromises = await (async function () {
+ let promises = [];
+
+ for (let index = 0; index < maxConnectionThreadCount - 1; index++) {
+ const request = indexedDB.open(name + "-" + index, 1);
+
+ {
+ const event = await expectingUpgrade(request);
+
+ const database = event.target.result;
+
+ const objectStore = database.createObjectStore(name);
+
+ objectStore.add("foo", 42);
+ }
+
+ const event = await expectingSuccess(request);
+
+ const database = event.target.result;
+
+ const transaction = database.transaction(name);
+
+ const objectStore = transaction.objectStore(name);
+
+ function doWork() {
+ const request = objectStore.get(42);
+ request.onsuccess = function () {
+ if (!done) {
+ doWork();
+ }
+ };
+ }
+
+ doWork();
+
+ const promise = new Promise(function (resolve) {
+ transaction.oncomplete = resolve;
+ });
+
+ promises.push(promise);
+ }
+
+ return promises;
+ })();
+
+ info("Creating database A");
+
+ // Create a database which will be used for stopping of the connection idle
+ // maintenance.
+ const databaseA = await (async function () {
+ const request = indexedDB.open(name + "-a", 1);
+
+ {
+ const event = await expectingUpgrade(request);
+
+ const database = event.target.result;
+
+ database.createObjectStore(name);
+ }
+
+ const event = await expectingSuccess(request);
+
+ const database = event.target.result;
+
+ return database;
+ })();
+
+ info("Creating database B");
+
+ // Create a database for checking of the connection idle maintenance.
+ {
+ const request = indexedDB.open(name + "-b", 1);
+
+ const event = await expectingUpgrade(request);
+
+ const database = event.target.result;
+
+ const objectStore = database.createObjectStore(name);
+
+ // Add lots of data...
+ for (let index = 0; index < 10000; index++) {
+ objectStore.add(abc, index);
+ }
+
+ // And then clear it so that maintenance has some space to reclaim.
+ objectStore.clear();
+
+ await expectingSuccess(request);
+ }
+
+ info("Getting database usage before maintenance");
+
+ const databaseUsageBeforeMaintenance = await new Promise(function (resolve) {
+ getCurrentUsage(function (request) {
+ resolve(request.result.databaseUsage);
+ });
+ });
+
+ info("Waiting for maintenance to start");
+
+ // This time is a double of connectionIdleMaintenanceMS which should be
+ // pessimistic enough to work with randomly slowed down threads in the
+ // chaos mode.
+ await new Promise(function (resolve) {
+ do_timeout(2 * connectionIdleMaintenanceMS, resolve);
+ });
+
+ info("Activating database A");
+
+ // Activate an open database which should trigger stopping of the connection
+ // idle maintenance of the database which had a lot of data.
+ {
+ const transaction = databaseA.transaction(name);
+
+ const objectStore = transaction.objectStore(name);
+
+ const request = objectStore.get(42);
+
+ await requestSucceeded(request);
+ }
+
+ info("Waiting for maintenance to finish");
+
+ // This time is a double of connectionIdleMaintenanceMS which should be
+ // pessimistic enough to work with randomly slowed down threads in the
+ // chaos mode.
+ await new Promise(function (resolve) {
+ do_timeout(2 * connectionIdleMaintenanceMS, resolve);
+ });
+
+ info("Getting database usage after maintenance");
+
+ const databaseUsageAfterMaintenance = await new Promise(function (resolve) {
+ getCurrentUsage(function (request) {
+ resolve(request.result.databaseUsage);
+ });
+ });
+
+ info(
+ "Database usage before: " +
+ databaseUsageBeforeMaintenance +
+ ". " +
+ "Database usage after: " +
+ databaseUsageAfterMaintenance
+ );
+
+ // Checkpointing done immediately after the maintenance can slightly decrease
+ // the usage even when the maintenance was stopped very early.
+ ok(
+ databaseUsageBeforeMaintenance - databaseUsageAfterMaintenance <
+ cosmologicalConstant,
+ "Maintenance did not significantly decrease database usage"
+ );
+
+ done = true;
+
+ info("Waiting for transactions to complete");
+
+ await Promise.all(completePromises);
+}
diff --git a/dom/indexedDB/test/unit/test_cursor_cycle.js b/dom/indexedDB/test/unit/test_cursor_cycle.js
index 09099387f3..3c60c24238 100644
--- a/dom/indexedDB/test/unit/test_cursor_cycle.js
+++ b/dom/indexedDB/test/unit/test_cursor_cycle.js
@@ -34,7 +34,7 @@ function* testSteps() {
let cursor = event.target.result;
if (cursor) {
let objectStore = event.target.transaction.objectStore("foo");
- objectStore.delete(Bob.ss).onsuccess = function (event) {
+ objectStore.delete(Bob.ss).onsuccess = function () {
cursor.continue();
};
}
diff --git a/dom/indexedDB/test/unit/test_cursor_mutation.js b/dom/indexedDB/test/unit/test_cursor_mutation.js
index 6af7df5c9b..c948b8d6c9 100644
--- a/dom/indexedDB/test/unit/test_cursor_mutation.js
+++ b/dom/indexedDB/test/unit/test_cursor_mutation.js
@@ -101,10 +101,10 @@ function* testSteps() {
if (count == 1) {
let objectStore = event.target.transaction.objectStore("foo");
- objectStore.delete(objectStoreData[0].ss).onsuccess = function (event) {
+ objectStore.delete(objectStoreData[0].ss).onsuccess = function () {
objectStore.add(
objectStoreData[objectStoreData.length - 1]
- ).onsuccess = function (event) {
+ ).onsuccess = function () {
cursor.continue();
};
};
diff --git a/dom/indexedDB/test/unit/test_cursors.js b/dom/indexedDB/test/unit/test_cursors.js
index 15e3d94355..84d0f082a8 100644
--- a/dom/indexedDB/test/unit/test_cursors.js
+++ b/dom/indexedDB/test/unit/test_cursors.js
@@ -77,7 +77,7 @@ function* testSteps() {
for (let i in keys) {
request = objectStore.add("foo", keys[i]);
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
if (++keyIndex == keys.length) {
testGenerator.next();
}
@@ -233,7 +233,7 @@ function* testSteps() {
if (keyIndex == 4) {
request = cursor.update("bar");
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
keyIndex++;
cursor.continue();
};
diff --git a/dom/indexedDB/test/unit/test_database_onclose.js b/dom/indexedDB/test/unit/test_database_onclose.js
index 0162ffc3ab..8d24ad620b 100644
--- a/dom/indexedDB/test/unit/test_database_onclose.js
+++ b/dom/indexedDB/test/unit/test_database_onclose.js
@@ -104,7 +104,7 @@ function* testSteps() {
let objectId = 0;
while (true) {
let addRequest = objectStore.add({ foo: "foo" }, objectId);
- addRequest.onerror = function (event) {
+ addRequest.onerror = function () {
info("addRequest.onerror, objectId: " + objectId);
txn.onerror = grabEventAndContinueHandler;
testGenerator.next(true);
@@ -200,7 +200,7 @@ function* testSteps() {
let numberOfReadObjects = 0;
let readRequest = objectStore.openCursor();
- readRequest.onerror = function (event) {
+ readRequest.onerror = function () {
info("readRequest.onerror, numberOfReadObjects: " + numberOfReadObjects);
testGenerator.next(true);
};
diff --git a/dom/indexedDB/test/unit/test_getAll.js b/dom/indexedDB/test/unit/test_getAll.js
index 6ada30d845..b8c3e6854a 100644
--- a/dom/indexedDB/test/unit/test_getAll.js
+++ b/dom/indexedDB/test/unit/test_getAll.js
@@ -33,7 +33,7 @@ function* testSteps() {
for (let i in values) {
request = objectStore.add(values[i]);
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
if (++addedCount == values.length) {
executeSoon(function () {
testGenerator.next();
diff --git a/dom/indexedDB/test/unit/test_index_object_cursors.js b/dom/indexedDB/test/unit/test_index_object_cursors.js
index 850e1c6007..992fe9e0e3 100644
--- a/dom/indexedDB/test/unit/test_index_object_cursors.js
+++ b/dom/indexedDB/test/unit/test_index_object_cursors.js
@@ -102,7 +102,7 @@ function* testSteps() {
let obj = cursor.value;
obj.updated = true;
- cursor.update(obj).onsuccess = function (event) {
+ cursor.update(obj).onsuccess = function () {
ok(true, "Object updated");
cursor.continue();
keyIndex++;
@@ -110,7 +110,7 @@ function* testSteps() {
return;
}
- cursor.delete().onsuccess = function (event) {
+ cursor.delete().onsuccess = function () {
ok(true, "Object deleted");
cursor.continue();
keyIndex++;
diff --git a/dom/indexedDB/test/unit/test_index_update_delete.js b/dom/indexedDB/test/unit/test_index_update_delete.js
index da43feb3b9..df6d3d86f4 100644
--- a/dom/indexedDB/test/unit/test_index_update_delete.js
+++ b/dom/indexedDB/test/unit/test_index_update_delete.js
@@ -73,7 +73,7 @@ function* testSteps() {
is(cursor.key, modifiedEntry, "Correct key");
cursor.value.index = unique ? 30 : 35;
- cursor.update(cursor.value).onsuccess = function (event) {
+ cursor.update(cursor.value).onsuccess = function () {
cursor.continue();
};
} else {
@@ -106,7 +106,7 @@ function* testSteps() {
is(cursor.key, modifiedEntry, "Correct key");
delete cursor.value.index;
- cursor.update(cursor.value).onsuccess = function (event) {
+ cursor.update(cursor.value).onsuccess = function () {
indexCount--;
cursor.continue();
};
diff --git a/dom/indexedDB/test/unit/test_indexes_bad_values.js b/dom/indexedDB/test/unit/test_indexes_bad_values.js
index c695490f74..d8426d60cc 100644
--- a/dom/indexedDB/test/unit/test_indexes_bad_values.js
+++ b/dom/indexedDB/test/unit/test_indexes_bad_values.js
@@ -74,7 +74,7 @@ function* testSteps() {
badObjectStoreData[i].key
);
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
if (++addedData == badObjectStoreData.length) {
executeSoon(function () {
testGenerator.next();
diff --git a/dom/indexedDB/test/unit/test_invalid_version.js b/dom/indexedDB/test/unit/test_invalid_version.js
index 79d74ab2cc..ea5e2953d0 100644
--- a/dom/indexedDB/test/unit/test_invalid_version.js
+++ b/dom/indexedDB/test/unit/test_invalid_version.js
@@ -6,6 +6,7 @@
/* exported testGenerator */
var testGenerator = testSteps();
+// eslint-disable-next-line require-yield
function* testSteps() {
const name = this.window ? window.location.pathname : "Splendid Test";
diff --git a/dom/indexedDB/test/unit/test_quotaExceeded_recovery.js b/dom/indexedDB/test/unit/test_quotaExceeded_recovery.js
index 20366be417..3f5ef96ba4 100644
--- a/dom/indexedDB/test/unit/test_quotaExceeded_recovery.js
+++ b/dom/indexedDB/test/unit/test_quotaExceeded_recovery.js
@@ -82,14 +82,14 @@ function* testSteps() {
event.stopPropagation();
};
- trans.oncomplete = function (event) {
+ trans.oncomplete = function () {
if (iter == 1) {
i++;
}
j++;
testGenerator.next(true);
};
- trans.onabort = function (event) {
+ trans.onabort = function () {
is(trans.error.name, "QuotaExceededError", "Reached quota limit");
testGenerator.next(false);
};
diff --git a/dom/indexedDB/test/unit/test_remove_objectStore.js b/dom/indexedDB/test/unit/test_remove_objectStore.js
index bdc16d9a6a..8d4cd17246 100644
--- a/dom/indexedDB/test/unit/test_remove_objectStore.js
+++ b/dom/indexedDB/test/unit/test_remove_objectStore.js
@@ -28,7 +28,7 @@ function* testSteps() {
for (let i = 0; i < 100; i++) {
request = objectStore.add({ foo: i });
request.onerror = errorHandler;
- request.onsuccess = function (event) {
+ request.onsuccess = function () {
if (++addedCount == 100) {
executeSoon(function () {
testGenerator.next();
diff --git a/dom/indexedDB/test/unit/test_setVersion_throw.js b/dom/indexedDB/test/unit/test_setVersion_throw.js
index 2706c2c2a4..b0b5392ba2 100644
--- a/dom/indexedDB/test/unit/test_setVersion_throw.js
+++ b/dom/indexedDB/test/unit/test_setVersion_throw.js
@@ -17,7 +17,7 @@ function* testSteps() {
let request = indexedDB.open(name, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
- request.onupgradeneeded = function (event) {
+ request.onupgradeneeded = function () {
info("Got upgradeneeded event for db 1");
};
let event = yield undefined;
@@ -36,7 +36,7 @@ function* testSteps() {
request = indexedDB.open(name, 2);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
- request.onupgradeneeded = function (event) {
+ request.onupgradeneeded = function () {
info("Got upgradeneeded event for db 2");
expectUncaughtException(true);
// eslint-disable-next-line no-undef
diff --git a/dom/indexedDB/test/unit/test_table_locks.js b/dom/indexedDB/test/unit/test_table_locks.js
index e1f3b5e7d6..3363520775 100644
--- a/dom/indexedDB/test/unit/test_table_locks.js
+++ b/dom/indexedDB/test/unit/test_table_locks.js
@@ -81,7 +81,7 @@ function doReadOnlyTransaction(db, key, remaining) {
let cursor = event.target.result;
ok(cursor, "Got readonly cursor");
- objectStore.get(cursor.primaryKey).onsuccess = function (event) {
+ objectStore.get(cursor.primaryKey).onsuccess = function () {
if (++key == objDataCount) {
key = 0;
}
@@ -113,7 +113,7 @@ function doReadWriteTransaction(db, key, remaining) {
let value = cursor.value;
value[idxKeyPathProp]++;
- cursor.update(value).onsuccess = function (event) {
+ cursor.update(value).onsuccess = function () {
if (++key == objDataCount) {
key = 0;
}
diff --git a/dom/indexedDB/test/unit/test_transaction_abort.js b/dom/indexedDB/test/unit/test_transaction_abort.js
index 6829392842..48f3677e0d 100644
--- a/dom/indexedDB/test/unit/test_transaction_abort.js
+++ b/dom/indexedDB/test/unit/test_transaction_abort.js
@@ -150,7 +150,7 @@ function* testSteps() {
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
- event.target.transaction.onabort = function (event) {
+ event.target.transaction.onabort = function () {
ok(false, "Shouldn't see an abort event!");
};
event.target.transaction.oncomplete = grabEventAndContinueHandler;
@@ -168,7 +168,7 @@ function* testSteps() {
key = event.target.result;
event.target.transaction.onabort = grabEventAndContinueHandler;
- event.target.transaction.oncomplete = function (event) {
+ event.target.transaction.oncomplete = function () {
ok(false, "Shouldn't see a complete event here!");
};
@@ -303,7 +303,7 @@ function* testSteps() {
r.onerror = abortErrorHandler;
}
makeNewRequest();
- transaction.objectStore("foo").get(1).onsuccess = function (event) {
+ transaction.objectStore("foo").get(1).onsuccess = function () {
executeSoon(function () {
transaction.abort();
expectedAbortEventCount++;
@@ -315,7 +315,7 @@ function* testSteps() {
// During COMMITTING
transaction = db.transaction("foo", "readwrite");
transaction.objectStore("foo").put({ hello: "world" }, 1).onsuccess =
- function (event) {
+ function () {
continueToNextStep();
};
yield undefined;
@@ -335,11 +335,10 @@ function* testSteps() {
// Abort both failing and succeeding requests
transaction = db.transaction("foo", "readwrite");
transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler;
- transaction.objectStore("foo").add({ indexKey: "key" }).onsuccess = function (
- event
- ) {
- transaction.abort();
- };
+ transaction.objectStore("foo").add({ indexKey: "key" }).onsuccess =
+ function () {
+ transaction.abort();
+ };
let request1 = transaction.objectStore("foo").add({ indexKey: "key" });
request1.onsuccess = grabEventAndContinueHandler;
request1.onerror = grabEventAndContinueHandler;
diff --git a/dom/indexedDB/test/unit/test_transaction_abort_hang.js b/dom/indexedDB/test/unit/test_transaction_abort_hang.js
index 6a2c61128b..cb7e4f7133 100644
--- a/dom/indexedDB/test/unit/test_transaction_abort_hang.js
+++ b/dom/indexedDB/test/unit/test_transaction_abort_hang.js
@@ -47,7 +47,7 @@ function* testSteps() {
// Last one, finish the test.
transaction.oncomplete = grabEventAndContinueHandler;
} else if (i == abortedTransactionIndex - 1) {
- transaction.oncomplete = function (event) {
+ transaction.oncomplete = function () {
ok(
true,
"Completed transaction " +
@@ -84,7 +84,7 @@ function* testSteps() {
transaction.abort();
});
} else {
- transaction.oncomplete = function (event) {
+ transaction.oncomplete = function () {
ok(true, "Completed transaction " + ++completedTransactionCount);
};
}
diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
index f297b72d25..f6bd2608ef 100644
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -28,7 +28,7 @@ function isnot(a, b, msg) {
Assert.notEqual(a, b, msg);
}
-function todo(condition, name, diag) {
+function todo(condition) {
todo_check_true(condition);
}
@@ -122,7 +122,7 @@ function expectedErrorHandler(name) {
};
}
-function expectUncaughtException(expecting) {
+function expectUncaughtException() {
// This is dummy for xpcshell test.
}
@@ -196,19 +196,19 @@ function compareKeys(k1, k2) {
return false;
}
-function addPermission(permission, url) {
+function addPermission() {
throw new Error("addPermission");
}
-function removePermission(permission, url) {
+function removePermission() {
throw new Error("removePermission");
}
-function allowIndexedDB(url) {
+function allowIndexedDB() {
throw new Error("allowIndexedDB");
}
-function disallowIndexedDB(url) {
+function disallowIndexedDB() {
throw new Error("disallowIndexedDB");
}
@@ -240,7 +240,7 @@ function scheduleGC() {
function setTimeout(fun, timeout) {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
var event = {
- notify(timer) {
+ notify() {
fun();
},
};
diff --git a/dom/indexedDB/test/unit/xpcshell-parent-process.toml b/dom/indexedDB/test/unit/xpcshell-parent-process.toml
index d63e3d6bf2..01740cdd82 100644
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.toml
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.toml
@@ -44,6 +44,10 @@ skip-if = ["true"] # Only used for recreating URLSearchParams_profile.zip
requesttimeoutfactor = 2
skip-if = ["tsan"]
+["test_connection_idle_maintenance.js"]
+
+["test_connection_idle_maintenance_stop.js"]
+
["test_database_close_without_onclose.js"]
["test_database_onclose.js"]