Skip to content

Atomic 2 #429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 30, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/reference/method/db.collection.findAndModify.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ db.collection.findAndModify()
#. The ``query`` finds a document in the ``people`` collection where
the ``name`` field has the value ``Tom``, the ``state`` field has
the value ``active`` and the ``rating`` field has a value
: operator:`greater than <$gt>` 10.
:operator:`greater than <$gt>` 10.

#. The ``sort`` orders the results of the query in ascending order.

Expand Down
2 changes: 1 addition & 1 deletion source/reference/method/db.collection.remove.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ db.collection.remove()
write operations to that collection. For an unsharded collection,
you have the option to override this behavior with the
:operator:`$atomic` isolation operator, effectively isolating the
delete operation and blocking all other operations during the
delete operation and blocking other write operations during the
delete. To isolate the query, include ``$atomic: 1`` in the
``query`` parameter as in the following example:

Expand Down
9 changes: 9 additions & 0 deletions source/reference/method/db.collection.update.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ db.collection.update()
In version 2.2 of the :program:`mongo` shell, you may also
specify ``multi`` in the ``options`` parameter.

.. note::

The ``multi`` update operation may interleave with other
write operations to that collection. For an unsharded
collection, you have the option to override this behavior
with the :operator:`$atomic` isolation operator,
effectively isolating the update operation and blocking
other write operations during the update. See the
:doc:`isolation operator </reference/operator/atomic>`.

Although the update operation may apply mostly to updating the
values of the fields, the :method:`update()
Expand Down
15 changes: 10 additions & 5 deletions source/reference/operator/atomic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ $atomic

.. operator:: $atomic

In multi-update mode, it's possible to specify an
:operator:`$atomic` "operator" that allows you to **isolate** some
updates from each other within this operation. Consider the
following example:
:operator:`$atomic` isolation operator **isolates** a write
operation that affect multiple documents from other write operations.

.. note::

The :operator:`$atomic` isolation operator does **not** mean
"all-or-nothing" atomicity to the write operation.

Consider the following example:

.. code-block:: javascript

db.foo.update( { field1 : 1 , $atomic : 1 }, { $inc : { field2 : 1 } } , false , true )
db.foo.update( { field1 : 1 , $atomic : 1 }, { $inc : { field2 : 1 } } , { multi: true } )

Without the :operator:`$atomic` operator, multi-updates will allow
other operations to interleave with this updates. If these
Expand Down
1 change: 1 addition & 0 deletions source/tutorial.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Development Patterns
:maxdepth: 1

tutorial/perform-two-phase-commits
tutorial/isolate-sequence-of-operations
tutorial/enforce-unique-keys-for-sharded-collections
tutorial/aggregation-examples

Expand Down
108 changes: 108 additions & 0 deletions source/tutorial/isolate-sequence-of-operations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
==============================
Isolate Sequence of Operations
==============================

.. default-domain:: mongodb

Background
----------

Write operations are atomic on the level of a single document: no
single write operation can atomically affect more than one document or
more than one collection.

When a single write operation modifies multiple documents, the
operation as a whole is not atomic, and other operations may
interleave. The modification of a single document, or record, is always
atomic, even if the write operation modifies multiple sub-document
*within* the single record.

No other operations are atomic; however, you can *isolate* a
single write operation that affects multiple documents using the
:doc:`isolation operator </reference/operator/atomic>`.

Additionally, the following patterns can manage a sequence of
operations:

- :method:`findAndModify() <db.collection.findAndModify()>`

- :ref:`tutorial-atomic-update-if-current`

- :doc:`/tutorial/perform-two-phase-commits`

- :method:`ensureIndex() <db.collection.ensureIndex()>` to create a
``unique`` index on a field

.. _tutorial-atomic-update-if-current:

Update if Current
-----------------

The "Update if Current" pattern queries a document, locally modifies
various fields of the document, and tries to update the fields of a
document *if* the fields have not changed in the collection since the
query.

Consider the following example which attempts to update the ``qty``
field of a document in the ``products`` collection:

.. code-block:: javascript

var myCollection = db.products;
var myDocument = myCollection.findOne( { sku: 'abc123' } );

if (myDocument) {

var oldQty = myDocument.qty;

if (myDocument.qty < 10) {
myDocument.qty *= 4;
} else if ( myDocument.qty < 20 ) {
myDocument.qty *= 3;
} else {
myDocument.qty *= 2;
}

myCollection.update(
{
_id: myDocument._id,
qty: oldQty
},
{
$set: { qty: myDocument.qty }
}
)

var err = db.getLastErrorObj();

if ( err && err.code ) {
print("unexpected error updating document: " + tojson( err ));
} else if ( err.n == 0 ) {
print("No update: no matching document for { _id: " + myDocument._id + ", qty: " + oldQty + " }")
}

}

Consider the following modifications to the "Update if Current" strategy:

- To generalize the strategy to guarantee that the whole document has
not changed rather than just certain fields, use the entire document in
the query expression.

- Add a version variable that is incremented upon each update operation
to the documents. Use this version variable in the query expression.

- Use :operator:`$set` in the update expression to modify only your
fields and prevent overriding other fields.

.. Add link to :doc:`/tutorial/create-an-auto-increment-field` once that branch is merged since it's a special case

.. Maybe incorporate the blurb: "MongoDB does not
support traditional locking and complex transactions for a number of
reasons: First, in sharded environments, distributed locks could be
expensive and slow. Mongo DB's goal is to be lightweight and fast. We
dislike the concept of deadlocks. We want the system to be simple and
predictable without these sort of surprises. We want Mongo DB to work
well for realtime problems. If an operation may execute which locks
large amounts of data, it might stop some small light queries for an
extended period of time."