Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MongoDB deal with transactional conflicts?

If both two threads do read and write a same document:

try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    result = collection.find(clientSession, keyOfDoc);
    if (result blah blah blah) {
        // Change the doc
        collection.insertOne(clientSession, doc);
    }
    clientSession.commitTransaction();
}

From the purpose of the transaction, one of the thread should get the edited version of another thread.

However, when both threads start transaction they both acquired a read lock, and then read the doc. Both the threads got the old version of the doc. and when they need to write the doc, they try to acquire write locks, which will make the transaction not atomic.

Another situation is the write-write conflict.

try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    collection.insertOne(clientSession, docDifferent);
    collection.insertOne(clientSession, docSame);
    clientSession.commitTransaction();
}

Both thread first acquires write locks of different documents, and then they acquire the write lock of the same document, as it is another transactional conflict.

What level of lock does MongoDB use? I know they use instance level before version 2.2 while transactions are supported since 4.0. If MongoDB doesn't use database level locks, How does MongoDB deal with transactional conflicts? Or if it uses database level locks, how does it deal with read-write conflicts?

like image 584
iry Avatar asked Nov 08 '18 06:11

iry


People also ask

Does MongoDB support transactional?

For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions. With distributed transactions, transactions can be used across multiple operations, collections, databases, documents, and shards.

Does MongoDB follow ACID transactions?

How do ACID transactions work in MongoDB? MongoDB added support for multi-document ACID transactions in version 4.0 in 2018 and extended that support for distributed multi-document ACID transactions in version 4.2 in 2019. MongoDB's document model allows related data to be stored together in a single document.

How many transactions per second can MongoDB handle?

MongoDB supports 250 million ticks per second, at 40x lower cost than the legacy technologies it replaced. Qihoo uses MongoDB to support over 100 applications deployed on over 1,500 nodes, serving 20 billion operations per day.


1 Answers

I found some references in the MongoDB Manual that solved my own question.

What type of locking does MongoDB use?

MongoDB uses multi-granularity locking 1 that allows operations to lock at the global, database or collection level, and allows for individual storage engines to implement their own concurrency control below the collection level (e.g., at the document-level in WiredTiger).

MongoDB uses multiple levels of locking from collection, database, then to global. However, though it supports multiple levels of locking, the only level you can access is the collection level, meaning you can't create or drop databases or collections in transactions. It also means that acquiring one document to be locked in a collection will cause the whole collection to get locked.

Restricted Operations

The following operations are not allowed in multi-document transactions:

  • Operations that affect the database catalog, such as creating or dropping a collection or an index. For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection.

    The listCollections and listIndexes commands and their helper methods are also excluded.

  • Non-CRUD and non-informational operations, such as createUser,getParameter, count, etc. and their helpers.

For solving conflicts, MongoDB sends error messages to the visitor that could not get the lock when conflict happens.

Retry Transaction

The individual write operations inside the transaction are not retryable, regardless of whether retryWrites is set to true.

If an operation encounters an error, the returned error may have an errorLabels array field. If the error is a transient error, the errorLabels array field contains "TransientTransactionError" as an element and the transaction as a whole can be retried.

Meaning when the visitor receive MongoException and the exception .hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL), the visitor should close the session, and REDO the transaction. The visitor should redo and recommit until the commit successes.

You can simply use this method(modified from the manual example):

public static <T> T transactWithRetry(Callable<T> transactional) throws Exception {
    while (true) {
        try {
            return transactional.call();
        } catch (MongoException ex) {
            if (!ex.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)) throw ex;
        }
    }
}

See editions for more languages in the manual ;)!


References

Transactions — MongoDB Manual

FAQ: Concurrency — MongoDB Manual

like image 149
iry Avatar answered Nov 15 '22 06:11

iry