By default, Matter.js state is transactional.

Transactions are either shared (for reads) or exclusive (for writes). Exclusive transactions do not block shared transactions but state updates will not be visible until the transaction completes.

Writes do block other writes. Transactions start automatically when a write occurs. Since this usually happens synchronously, the best Matter.js can do is throw an error if two write transactions would conflict. However, you can avoid this by using begin which will wait for other transactions to complete before acquiring resource locks.

Persistence is implemented by a list of participants. Commits are two phase. If an error is thrown in phase one all participants roll back. An error in phase 2 could result in data inconsistency as we don't have any form of retry as of yet.

TODO - does prevent deadlock but we should probably add a timeout for resource locking

interface Transaction {
    participants: Set<Participant>;
    resources: Set<Resource>;
    status: Status;
    via: string;
    waitingOn: undefined | Iterable<Transaction, any, any>;
    addParticipants(...participants: Participant[]): void;
    addResources(...resources: Resource[]): Promise<void>;
    addResourcesSync(...resources: Resource[]): void;
    begin(): Promise<void>;
    beginSync(): void;
    commit(): MaybePromise;
    getParticipant(role: {}): undefined | Participant;
    onClose(actor: (() => void)): void;
    onShared(actor: (() => void), once?: boolean): void;
    rollback(): MaybePromise;
    waitFor(others: Set<Transaction>): Promise<void>;
    Participant: ParticipantType;
    Resource: ResourceType;
    Status: StatusType;
}

Properties

participants: Set<Participant>

Transaction participants.

resources: Set<Resource>

Resources addressed by the participants.

status: Status

The status of the transaction.

via: string

Diagnostic description of the transaction's source.

waitingOn: undefined | Iterable<Transaction, any, any>

The transactions currently blocking this transaction, if any.

Methods

  • Add Resources to the transaction.

    If the transaction is exclusive (writing) the transaction will acquire the lock on each ResourceType, waiting for other writers to finish if necessary.

    Parameters

    Returns Promise<void>

  • Begin an exclusive transaction.

    Transactions begin automatically on write but there are a few reasons you may want to use this method to start an exclusive transaction explicitly:

    1. Automatic transactions are started in a synchronous context so conflicting transactions will throw an error. If you start a transaction, your code will await any transaction that would otherwise throw an error.

    2. Transaction isolation means your view of data may become stale if a write occurs in another transaction. Once you start a transaction you block other writers so can be assured you're dealing with newest state.

    3. Say transaction A has an exclusive lock on resource 1 and awaits resource 2. Transaction B has an exclusive lock on resource 2. Transaction B cannot then await resource 1 without causing a deadlock. Matter.js will detect the deadlock and throw an error. One way to prevent this is to begin a transaction and acquire locks in a specific order.

    None of the issues above are likely and are probably not a concern for your application. If you do encounter these issues the error message will suggest solutions.

    Returns Promise<void>