Bug 1878143 - Add durability hint to IDB transaction properties. r=dom-storage-reviewers,webidl,saschanaz,janv,smaug

Differential Revision: https://phabricator.services.mozilla.com/D202732
This commit is contained in:
Jari Jalkanen 2024-03-27 17:34:01 +00:00
Родитель e8d1bbf993
Коммит f45b83a18e
11 изменённых файлов: 132 добавлений и 69 удалений

Просмотреть файл

@ -2410,11 +2410,13 @@ class Database final
already_AddRefed<PBackgroundIDBTransactionParent>
AllocPBackgroundIDBTransactionParent(
const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode) override;
const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode,
const Durability& aDurability) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBTransactionConstructor(
PBackgroundIDBTransactionParent* aActor,
nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode) override;
nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode,
const Durability& aDurability) override;
mozilla::ipc::IPCResult RecvDeleteMe() override;
@ -2607,6 +2609,7 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
protected:
using Mode = IDBTransaction::Mode;
using Durability = IDBTransaction::Durability;
private:
const SafeRefPtr<Database> mDatabase;
@ -2618,6 +2621,7 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
uint64_t mActiveRequestCount;
Atomic<bool> mInvalidatedOnAnyThread;
const Mode mMode;
const Durability mDurability; // TODO: See bug 1883045
FlippedOnce<false> mInitialized;
FlippedOnce<false> mHasBeenActiveOnConnectionThread;
FlippedOnce<false> mActorDestroyed;
@ -2677,6 +2681,8 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
Mode GetMode() const { return mMode; }
Durability GetDurability() const { return mDurability; }
const Database& GetDatabase() const {
MOZ_ASSERT(mDatabase);
@ -2739,7 +2745,8 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
virtual ~TransactionBase();
protected:
TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode);
TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode,
Durability aDurability);
void NoteActorDestroyed() {
AssertIsOnBackgroundThread();
@ -2895,6 +2902,7 @@ class NormalTransaction final : public TransactionBase,
// This constructor is only called by Database.
NormalTransaction(
SafeRefPtr<Database> aDatabase, TransactionBase::Mode aMode,
TransactionBase::Durability aDurability,
nsTArray<SafeRefPtr<FullObjectStoreMetadata>>&& aObjectStores);
MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(NormalTransaction, TransactionBase)
@ -9783,7 +9791,8 @@ bool Database::DeallocPBackgroundIDBDatabaseFileParent(
already_AddRefed<PBackgroundIDBTransactionParent>
Database::AllocPBackgroundIDBTransactionParent(
const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode) {
const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode,
const Durability& aDurability) {
AssertIsOnBackgroundThread();
// Once a database is closed it must not try to open new transactions.
@ -9803,6 +9812,12 @@ Database::AllocPBackgroundIDBTransactionParent(
return nullptr;
}
if (NS_AUUF_OR_WARN_IF(aDurability != IDBTransaction::Durability::Default &&
aDurability != IDBTransaction::Durability::Strict &&
aDurability != IDBTransaction::Durability::Relaxed)) {
return nullptr;
}
const ObjectStoreTable& objectStores = mMetadata->mObjectStores;
const uint32_t nameCount = aObjectStoreNames.Length();
@ -9845,13 +9860,15 @@ Database::AllocPBackgroundIDBTransactionParent(
nullptr);
return MakeSafeRefPtr<NormalTransaction>(SafeRefPtrFromThis(), aMode,
aDurability,
std::move(objectStoreMetadatas))
.forget();
}
mozilla::ipc::IPCResult Database::RecvPBackgroundIDBTransactionConstructor(
PBackgroundIDBTransactionParent* aActor,
nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode) {
nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode,
const Durability& aDurability) { // TODO: See bug 1883045
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
@ -9859,6 +9876,9 @@ mozilla::ipc::IPCResult Database::RecvPBackgroundIDBTransactionConstructor(
aMode == IDBTransaction::Mode::ReadWrite ||
aMode == IDBTransaction::Mode::ReadWriteFlush ||
aMode == IDBTransaction::Mode::Cleanup);
MOZ_ASSERT(aDurability == IDBTransaction::Durability::Default ||
aDurability == IDBTransaction::Durability::Strict ||
aDurability == IDBTransaction::Durability::Relaxed);
MOZ_ASSERT(!mClosed);
if (IsInvalidated()) {
@ -9990,7 +10010,8 @@ void Database::StartTransactionOp::Cleanup() {
* TransactionBase
******************************************************************************/
TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode)
TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode,
Durability aDurability)
: mDatabase(std::move(aDatabase)),
mDatabaseId(mDatabase->Id()),
mLoggingSerialNumber(
@ -9998,6 +10019,7 @@ TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode)
mActiveRequestCount(0),
mInvalidatedOnAnyThread(false),
mMode(aMode),
mDurability(aDurability),
mResultCode(NS_OK) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatabase);
@ -10757,8 +10779,9 @@ bool TransactionBase::StartCursor(PBackgroundIDBCursorParent* const aActor,
NormalTransaction::NormalTransaction(
SafeRefPtr<Database> aDatabase, TransactionBase::Mode aMode,
TransactionBase::Durability aDurability,
nsTArray<SafeRefPtr<FullObjectStoreMetadata>>&& aObjectStores)
: TransactionBase(std::move(aDatabase), aMode),
: TransactionBase(std::move(aDatabase), aMode, aDurability),
mObjectStores{std::move(aObjectStores)} {
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mObjectStores.IsEmpty());
@ -10881,7 +10904,9 @@ mozilla::ipc::IPCResult NormalTransaction::RecvPBackgroundIDBCursorConstructor(
VersionChangeTransaction::VersionChangeTransaction(
OpenDatabaseOp* aOpenDatabaseOp)
: TransactionBase(aOpenDatabaseOp->mDatabase.clonePtr(),
IDBTransaction::Mode::VersionChange),
IDBTransaction::Mode::VersionChange,
// VersionChange must not change durability.
IDBTransaction::Durability::Default), // Not used.
mOpenDatabaseOp(aOpenDatabaseOp) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aOpenDatabaseOp);

Просмотреть файл

@ -20,6 +20,7 @@
#include "MainThreadUtils.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/Services.h"
#include "mozilla/dom/IDBTransactionBinding.h"
#include "mozilla/storage.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/BindingDeclarations.h"
@ -474,7 +475,8 @@ void IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv) {
RefPtr<IDBTransaction> IDBDatabase::Transaction(
JSContext* aCx, const StringOrStringSequence& aStoreNames,
IDBTransactionMode aMode, ErrorResult& aRv) {
IDBTransactionMode aMode, const IDBTransactionOptions& aOptions,
ErrorResult& aRv) {
AssertIsOnOwningThread();
if ((aMode == IDBTransactionMode::Readwriteflush ||
@ -598,8 +600,26 @@ RefPtr<IDBTransaction> IDBDatabase::Transaction(
MOZ_CRASH("Unknown mode!");
}
auto durability = IDBTransaction::Durability::Default;
if (aOptions.IsAnyMemberPresent()) {
switch (aOptions.mDurability) {
case mozilla::dom::IDBTransactionDurability::Default:
durability = IDBTransaction::Durability::Default;
break;
case mozilla::dom::IDBTransactionDurability::Strict:
durability = IDBTransaction::Durability::Strict;
break;
case mozilla::dom::IDBTransactionDurability::Relaxed:
durability = IDBTransaction::Durability::Relaxed;
break;
default:
MOZ_CRASH("Unknown durability hint!");
}
}
SafeRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(aCx, this, sortedStoreNames, mode);
IDBTransaction::Create(aCx, this, sortedStoreNames, mode, durability);
if (NS_WARN_IF(!transaction)) {
IDB_REPORT_INTERNAL_ERR();
MOZ_ASSERT(!NS_IsMainThread(),
@ -617,7 +637,7 @@ RefPtr<IDBTransaction> IDBDatabase::Transaction(
IDB_LOG_STRINGIFY(*transaction));
if (!mBackgroundActor->SendPBackgroundIDBTransactionConstructor(
actor, sortedStoreNames, mode)) {
actor, sortedStoreNames, mode, durability)) {
IDB_REPORT_INTERNAL_ERR();
aRv.ThrowUnknownError("Failed to create IndexedDB transaction");
return nullptr;

Просмотреть файл

@ -166,7 +166,8 @@ class IDBDatabase final : public DOMEventTargetHelper {
// This will be called from the DOM.
[[nodiscard]] RefPtr<IDBTransaction> Transaction(
JSContext* aCx, const StringOrStringSequence& aStoreNames,
IDBTransactionMode aMode, ErrorResult& aRv);
IDBTransactionMode aMode, const IDBTransactionOptions& aOptions,
ErrorResult& aRv);
IMPL_EVENT_HANDLER(abort)
IMPL_EVENT_HANDLER(close)

Просмотреть файл

@ -89,8 +89,9 @@ auto IDBTransaction::DoWithTransactionChild(const Func& aFunc) const {
IDBTransaction::IDBTransaction(IDBDatabase* const aDatabase,
const nsTArray<nsString>& aObjectStoreNames,
const Mode aMode, nsString aFilename,
const uint32_t aLineNo, const uint32_t aColumn,
const Mode aMode, const Durability aDurability,
nsString aFilename, const uint32_t aLineNo,
const uint32_t aColumn,
CreatedFromFactoryFunction /*aDummy*/)
: DOMEventTargetHelper(aDatabase),
mDatabase(aDatabase),
@ -105,6 +106,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* const aDatabase,
mLineNo(aLineNo),
mColumn(aColumn),
mMode(aMode),
mDurability(aDurability),
mRegistered(false),
mNotedActiveTransaction(false) {
MOZ_ASSERT(aDatabase);
@ -178,9 +180,11 @@ SafeRefPtr<IDBTransaction> IDBTransaction::CreateVersionChange(
nsString filename;
uint32_t lineNo, column;
aOpenRequest->GetCallerLocation(filename, &lineNo, &column);
// XXX: What should we have as durability hint here?
auto transaction = MakeSafeRefPtr<IDBTransaction>(
aDatabase, emptyObjectStoreNames, Mode::VersionChange,
std::move(filename), lineNo, column, CreatedFromFactoryFunction{});
Durability::Default, std::move(filename), lineNo, column,
CreatedFromFactoryFunction{});
transaction->NoteActiveTransaction();
@ -197,7 +201,8 @@ SafeRefPtr<IDBTransaction> IDBTransaction::CreateVersionChange(
// static
SafeRefPtr<IDBTransaction> IDBTransaction::Create(
JSContext* const aCx, IDBDatabase* const aDatabase,
const nsTArray<nsString>& aObjectStoreNames, const Mode aMode) {
const nsTArray<nsString>& aObjectStoreNames, const Mode aMode,
const Durability aDurability) {
MOZ_ASSERT(aDatabase);
aDatabase->AssertIsOnOwningThread();
MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
@ -208,8 +213,8 @@ SafeRefPtr<IDBTransaction> IDBTransaction::Create(
uint32_t lineNo, column;
IDBRequest::CaptureCaller(aCx, filename, &lineNo, &column);
auto transaction = MakeSafeRefPtr<IDBTransaction>(
aDatabase, aObjectStoreNames, aMode, std::move(filename), lineNo, column,
CreatedFromFactoryFunction{});
aDatabase, aObjectStoreNames, aMode, aDurability, std::move(filename),
lineNo, column, CreatedFromFactoryFunction{});
if (!NS_IsMainThread()) {
WorkerPrivate* const workerPrivate = GetCurrentThreadWorkerPrivate();
@ -877,6 +882,24 @@ IDBTransactionMode IDBTransaction::GetMode(ErrorResult& aRv) const {
}
}
IDBTransactionDurability IDBTransaction::GetDurability(ErrorResult& aRv) const {
AssertIsOnOwningThread();
switch (mDurability) {
case Durability::Default:
return IDBTransactionDurability::Default;
case Durability::Strict:
return IDBTransactionDurability::Strict;
case Durability::Relaxed:
return IDBTransactionDurability::Relaxed;
default:
MOZ_CRASH("Bad mode!");
}
}
DOMException* IDBTransaction::GetError() const {
AssertIsOnOwningThread();

Просмотреть файл

@ -63,6 +63,15 @@ class IDBTransaction final
Invalid
};
enum struct Durability {
Default = 0,
Strict,
Relaxed,
// Only needed for IPC serialization helper, should never be used in code.
Invalid
};
enum struct ReadyState { Active, Inactive, Committing, Finished };
private:
@ -113,6 +122,7 @@ class IDBTransaction final
ReadyState mReadyState = ReadyState::Active;
FlippedOnce<false> mStarted;
const Mode mMode;
const Durability mDurability;
bool mRegistered; ///< Whether mDatabase->RegisterTransaction() has been
///< called (which may not be the case if construction was
@ -135,7 +145,8 @@ class IDBTransaction final
[[nodiscard]] static SafeRefPtr<IDBTransaction> Create(
JSContext* aCx, IDBDatabase* aDatabase,
const nsTArray<nsString>& aObjectStoreNames, Mode aMode);
const nsTArray<nsString>& aObjectStoreNames, Mode aMode,
Durability aDurability);
static Maybe<IDBTransaction&> MaybeCurrent();
@ -237,6 +248,11 @@ class IDBTransaction final
return mMode;
}
Durability GetDurability() const {
AssertIsOnOwningThread();
return mDurability;
}
uint32_t GetPendingRequestCount() const { return mPendingRequestCount; }
IDBDatabase* Database() const {
@ -307,6 +323,8 @@ class IDBTransaction final
IDBTransactionMode GetMode(ErrorResult& aRv) const;
IDBTransactionDurability GetDurability(ErrorResult& aRv) const;
DOMException* GetError() const;
[[nodiscard]] RefPtr<IDBObjectStore> ObjectStore(const nsAString& aName,
@ -331,8 +349,8 @@ class IDBTransaction final
public:
IDBTransaction(IDBDatabase* aDatabase,
const nsTArray<nsString>& aObjectStoreNames, Mode aMode,
nsString aFilename, uint32_t aLineNo, uint32_t aColumn,
CreatedFromFactoryFunction aDummy);
Durability aDurability, nsString aFilename, uint32_t aLineNo,
uint32_t aColumn, CreatedFromFactoryFunction aDummy);
private:
~IDBTransaction();

Просмотреть файл

@ -19,6 +19,9 @@ using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
using mozilla::dom::IDBTransaction::Mode
from "mozilla/dom/IDBTransaction.h";
using mozilla::dom::IDBTransaction::Durability
from "mozilla/dom/IDBTransaction.h";
namespace mozilla {
namespace dom {
namespace indexedDB {
@ -41,7 +44,7 @@ parent:
async PBackgroundIDBDatabaseFile(IPCBlob blob);
async PBackgroundIDBTransaction(nsString[] objectStoreNames, Mode mode);
async PBackgroundIDBTransaction(nsString[] objectStoreNames, Mode mode, Durability durability);
child:
async __delete__();

Просмотреть файл

@ -72,6 +72,13 @@ struct ParamTraits<mozilla::dom::IDBTransaction::Mode>
mozilla::dom::IDBTransaction::Mode::ReadOnly,
mozilla::dom::IDBTransaction::Mode::Invalid> {};
template <>
struct ParamTraits<mozilla::dom::IDBTransaction::Durability>
: public ContiguousEnumSerializer<
mozilla::dom::IDBTransaction::Durability,
mozilla::dom::IDBTransaction::Durability::Default,
mozilla::dom::IDBTransaction::Durability::Invalid> {};
} // namespace IPC
#endif // mozilla_dom_indexeddb_serializationhelpers_h__

Просмотреть файл

@ -5,11 +5,18 @@
*
* The origin of this IDL file is
* https://w3c.github.io/IndexedDB/#database-interface
* https://w3c.github.io/IndexedDB/#enumdef-idbtransactiondurability
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
enum IDBTransactionDurability { "default", "strict", "relaxed" };
dictionary IDBTransactionOptions {
IDBTransactionDurability durability = "default";
};
[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
[Constant] readonly attribute DOMString name;
@ -19,7 +26,8 @@ interface IDBDatabase : EventTarget {
[NewObject, Throws]
IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
optional IDBTransactionMode mode = "readonly");
optional IDBTransactionMode mode = "readonly",
optional IDBTransactionOptions options = {});
[NewObject, Throws]
IDBObjectStore createObjectStore(
DOMString name,

Просмотреть файл

@ -23,6 +23,10 @@ enum IDBTransactionMode {
interface IDBTransaction : EventTarget {
[Throws]
readonly attribute IDBTransactionMode mode;
[Throws]
readonly attribute IDBTransactionDurability durability;
[SameObject] readonly attribute IDBDatabase db;
readonly attribute DOMException? error;

Просмотреть файл

@ -7,9 +7,6 @@
[IDBFactory interface: operation databases()]
expected: PASS
[IDBTransaction interface: attribute durability]
expected: FAIL
[idlharness.any.html]
expected:
@ -20,9 +17,6 @@
[IDBFactory interface: operation databases()]
expected: PASS
[IDBTransaction interface: attribute durability]
expected: FAIL
[idlharness.any.worker.html]
expected:
@ -33,9 +27,6 @@
[IDBFactory interface: operation databases()]
expected: PASS
[IDBTransaction interface: attribute durability]
expected: FAIL
[idlharness.https.any.serviceworker.html]
expected: TIMEOUT
@ -48,6 +39,3 @@
[IDBFactory interface: operation databases()]
expected: PASS
[IDBTransaction interface: attribute durability]
expected: FAIL

Просмотреть файл

@ -1,42 +1,8 @@
[transaction-relaxed-durability.tentative.any.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Committed data can be read back out: case 3]
expected: FAIL
[Committed data can be read back out: case 2]
expected: FAIL
[Committed data can be read back out: case 1]
expected: FAIL
[Committed data can be read back out: case 0]
expected: FAIL
[Invalid durability option throws a TypeError]
expected: FAIL
[Committed data can be read back out: case 4]
expected: FAIL
[transaction-relaxed-durability.tentative.any.worker.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Committed data can be read back out: case 3]
expected: FAIL
[Committed data can be read back out: case 2]
expected: FAIL
[Committed data can be read back out: case 1]
expected: FAIL
[Committed data can be read back out: case 0]
expected: FAIL
[Invalid durability option throws a TypeError]
expected: FAIL
[Committed data can be read back out: case 4]
expected: FAIL