Optimistic concurrency in MongoDB using .NET and C#

github_icon
[Available via NuGet – MongoDB.Kennedy.Concurrency]
[Available via GitHub – optimistic_concurrency_mongodb_dotnet]

This article demonstrates a technique and supporting library for adding optimistic concurrency control to NoSQL databases and MongoDB in particular.

Watch a video walk-through using this library:

Quickly, what is optimistic concurrency control?

Ideally, all databases that allow concurrent access or disconnected access need to implement some form of concurrency control. This usually comes in two flavors:

  1. Pessimistic concurrency control
  2. Optimistic concurrency control

Pessimistic concurrency control is usually used when working heavily within transactions. That may be fine for bank transfers, but it typically falls down in the face of disconnected models used by almost all ORMs such as Entity Framework. Moreover, it is entirely inappropriate for NoSQL databases.

Frameworks such as Entity Framework have optimistic concurrency control built in (although it may be turned off). It’s instructive to quickly see how it works. Basically there are three steps:

  1. Get an entity from the DB and disconnect.
  2. Edit in memory.
  3. Update the db with changes using a special update clause. Something like: “Update this row WHERE the current values are same as original values”.

If that update returns “0 rows modified” then we know it was changed since we loaded it and are about to overwrite someone’s changes. This results in a concurrency exception and not changes go through.

Optimistic concurrency control for MongoDB

By carefully constructing update commands in C# with the official 10gen C# driver, we can achieve almost exactly the same flow. At the end of this article is a simple C# class (data context) which has save and delete methods which internally are safe via optimistic concurrency control.

The only thing you need to do to use this library in your apps is to implement this interface on all top-level MongoDB entities and use a class derived from ConcurrentDataContext (in library below) for your data access.

IMongoEntity

Using this interface, the data context will manage a unique ID for you named _accessId per save. If someone else edits this object after you have gotten it but before saving it, you’ll get a concurrency exception, just like EF, and no changes will go through. All you do is call save and access entities via LINQ queries. Nice huh?

Here is an example of your entities with this interface in the db:

entity

Here is an example of an app running end to end with only one editor on the document. See, no errors:

no errors

And here is simulating a concurrent edit, which results in an error.

error

Conclusion

There you have it! For all of you who want to adopt MongoDB and .NET but are concerned about concurrency issues, you now have the same level of concurrency safety as Entity Framework. That should be quite reassuring.

Download for the source, library with the concurrent data context, the sample app, and unit tests from GitHub:

https://github.com/mikeckennedy/optimistic_concurrency_mongodb_dotnet

Cheers,
@mkennedy

13 comments

  • Really nice post! This library was mentioned in an excellent talk at DevWeek 2012 in London. If you are installing this library out of the box using NuGet, ensure that you add the latest versions of MongoDB.Bson and MongoDB.Driver.

  • Hi Great Work

    How do I pass the MongoDB Credentials to the DataContext

    When I attempt to pass it in the server name parameter it is telling me that is still trying to autenticate with the default admin user.

    Your help will be really appreciated

  • Hi! Great Work

    How do I authenticate or pass the MongoDb Credentails utilizing this library

    I will really appreciate it! and Thanks

  • Michael, can you explain a bit more about how this works behind the scenes? For example, I dont understand how your library can work given its modifying the client driver only and not the core mongodb libraries – In any solution to the problem being addressed (concurrent updates) I would expect the server to have to check the etag/accessId whilst holding a lock on the object and throw/return a ‘ConcurrencyException’ to the callee if they do not match

    • Hi Wallace,

      The key thing my library leverages is that the server guarantees that updates to a single document are always atomic. There are no transactions or any multi-document promises, but single docs are basically transactional.

      So it goes like this. Each doc has a changing accessId field. And so

      Client 1 reads doc, has _id = 7 and accessId = 78472847
      Client 2 reads doc, has _id = 7 and accessId = 78472847

      Client 2 updates the doc using the query where _id = 7 and accessId = 78472847
      One row modified, all good.
      my lib changes accessId = 8594274 (as part of that update)

      Client 1 updates the doc using the query where _id = 7 and accessId = 78472847
      Zero rows modified (there is no such doc), concurrency error detected!

      Make sense?

      Thanks,
      Michael

  • Micheal do you have any reference for how to handle optimistic concurrency with the new 2.0.1 C# driver?

  • I would also be interested to see how this is implemented in the new driver. Great post!

Submit a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s