Linearizable Reads via findAndModify

Overview

When reading from a replica set, it is possible to read data that isstale (i.e. may not reflect all writes that have occurred prior to theread operation) or not durable (i.e. the state of the data may reflecta write that has not been acknowledged by a majority or the replica setmembers and thus could be rolled back), depending on the read concernused.

Starting in version 3.4, MongoDB introduces"linearizable" read concern that returns durable datathat is not stale. Linearizable readconcern guarantees only apply if read operations specify a query filterthat uniquely identifies a single document.

This tutorial outlines an alternative procedure, one usingdb.collection.findAndModify() to read data that is not staleand cannot be rolled back, for deployments using MongoDB 3.2. ForMongoDB 3.4, although the outlined procedure can be applied, see"linearizable" read concern instead.

Linearizable Reads via findAndModify

This procedure uses db.collection.findAndModify() to readdata that is not stale and cannot be rolled back. To do so, theprocedure uses the findAndModify() method witha write concern to modify a dummy field in adocument. Specifically, the procedure requires that:

Important

The “quorum read” procedure has a substantial cost over simply usinga read concern of "majority" because it incurs writelatency rather than read latency. This technique should only be usedif staleness is absolutely intolerable.

Prerequisites

This tutorial reads from a collection named products. Initializethe collection using the following operation.

  1. db.products.insert( [
  2. {
  3. _id: 1,
  4. sku: "xyz123",
  5. description: "hats",
  6. available: [ { quantity: 25, size: "S" }, { quantity: 50, size: "M" } ],
  7. _dummy_field: 0
  8. },
  9. {
  10. _id: 2,
  11. sku: "abc123",
  12. description: "socks",
  13. available: [ { quantity: 10, size: "L" } ],
  14. _dummy_field: 0
  15. },
  16. {
  17. _id: 3,
  18. sku: "ijk123",
  19. description: "t-shirts",
  20. available: [ { quantity: 30, size: "M" }, { quantity: 5, size: "L" } ],
  21. _dummy_field: 0
  22. }
  23. ] )

The documents in this collection contain a dummy field named_dummy_field that will be incremented by thedb.collection.findAndModify() in the tutorial. If the fielddoes not exist, the db.collection.findAndModify() operationwill add the field to the document. The purpose of the field is toensure that the db.collection.findAndModify() results in amodification to the document.

Procedure

Create a unique index.

Create a unique index on the fields that will be used to specify anexact match in the db.collection.findAndModify() operation.

This tutorial will use an exact match on the sku field. As such,create a unique index on the sku field.

  1. db.products.createIndex( { sku: 1 }, { unique: true } )

Use findAndModify to read committed data.

Use the db.collection.findAndModify() method to make atrivial update to the document you want to read and return themodified document. A write concern of { w: "majority" } is required. To specify the document to read, you mustuse an exact match query that is supported by a unique index.

The following findAndModify() operationspecifies an exact match on the uniquely indexed field sku andincrements the field named _dummy_field in the matching document.While not necessary, the write concern for this command also includesa wtimeout value of 5000 milliseconds to prevent theoperation from blocking forever if the write cannot propagate to amajority of voting members.

  1. var updatedDocument = db.products.findAndModify(
  2. {
  3. query: { sku: "abc123" },
  4. update: { $inc: { _dummy_field: 1 } },
  5. new: true,
  6. writeConcern: { w: "majority", wtimeout: 5000 }
  7. }
  8. );

Even in situations where two nodes in the replica set believe thatthey are the primary, only one will be able to complete the write withw: "majority". As such, thefindAndModify() method with"majority" write concern will be successful only whenthe client has connected to the true primary to perform the operation.

Since the quorum read procedure only increments a dummy field in thedocument, you can safely repeat invocations offindAndModify(), adjusting thewtimeout as necessary.