Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

It's not possible to lock a mongodb document. What if I need to?

I know that I can't lock a single mongodb document, in fact there is no way to lock a collection either.

However, I've got this scenario, where I think I need some way to prevent more than one thread (or process, it's not important) from modifying a document. Here's my scenario.

I have a collection that contains object of type A. I have some code that retrieve a document of type A, add an element in an array that is a property of the document (a.arr.add(new Thing()) and then save back the document to mongodb. This code is parallel, multiple threads in my applications can do theses operations and for now there is no way to prevent to threads from doing theses operations in parallel on the same document. This is bad because one of the threads could overwrite the works of the other.

I do use the repository pattern to abstract the access to the mongodb collection, so I only have CRUDs operations at my disposition.

Now that I think about it, maybe it's a limitation of the repository pattern and not a limitation of mongodb that is causing me troubles. Anyway, how can I make this code "thread safe"? I guess there's a well known solution to this problem, but being new to mongodb and the repository pattern, I don't immediately sees it.

Thanks

like image 279
Mathieu Pagé Avatar asked Jun 18 '12 02:06

Mathieu Pagé


People also ask

Can you lock a document in MongoDB?

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).

Which of the following operations in MongoDB can lock?

The following MongoDB operations lock multiple databases: db. copyDatabase() must lock the entire mongod instance at once. Journaling, which is an internal operation, locks all databases for short intervals.

How can you achieve transaction and locking in MongoDB?

User 1 -> read request start User 2 -> read request start User 1 -> read request success (booking available) User 2 -> read request success (booking available) User 1 -> write a new record to the db (new booking) User 2 -> write a new record to the db (new booking) but this conflicts with User 1.

How many types of locking modes exist in MongoDB?

There are four different levels of locking in MongoDB.


2 Answers

Hey the only way of which I think now is to add an status parameter and use the operation findAndModify(), which enables you to atomically modify a document. It's a bit slower, but should do the trick.

So let's say you add an status attribut and when you retrieve the document change the status from "IDLE" to "PROCESSING". Then you update the document and save it back to the collection updating the status to "IDLE" again.

Code example:

var doc = db.runCommand({               "findAndModify" : "COLLECTION_NAME",               "query" : {"_id": "ID_DOCUMENT", "status" : "IDLE"},               "update" : {"$set" : {"status" : "RUNNING"} } }).value 

Change the COLLECTION_NAME and ID_DOCUMENT to a proper value. By default findAndModify() returns the old value, which means the status value will be still IDLE on the client side. So when you are done with updating just save/update everything again.

The only think you need be be aware is that you can only modify one document at a time.

Hope it helps.

like image 154
golja Avatar answered Sep 22 '22 17:09

golja


Stumbled into this question while working on mongodb upgrades. Unlike at the time this question was asked, now mongodb supports document level locking out of the box.

From: http://docs.mongodb.org/manual/faq/concurrency/

"How granular are locks in MongoDB?

Changed in version 3.0.

Beginning with version 3.0, MongoDB ships with the WiredTiger storage engine, which uses optimistic concurrency control for most read and write operations. WiredTiger uses only intent locks at the global, database and collection levels. When the storage engine detects conflicts between two operations, one will incur a write conflict causing MongoDB to transparently retry that operation."

like image 45
Mahesh Avatar answered Sep 20 '22 17:09

Mahesh