-
Type: Task
-
Resolution: Unresolved
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Execution
The findAndModify command takes a sort parameter which indicates how the server should choose which document to modify when multiple documents match the filter.
Once the operation "chooses" a document to modify, it may get a write conflict attempting to modify it. If that happens, the update portion of the plan will retry updating the same document (by RID). However, the concurrent operation which caused the WriteConflict to happen may have changed the document so that it's position in the sort order is different, and it's no longer first. For example:
The collection contains three documents:
RID 1: {a: 1, b: 1} RID 2: {a: 1, b: 2} RID 3: {a: 3, b: 3}
Then the following sequence happens (this example is from daniel.gomezferro@mongodb.com and ivan.fefer@mongodb.com):
- Thread 1: A findAndModify is sent to the server, selecting docs:
- filter: a==1
- sort: {b:1}
- update: set b to 4
- Thread 1 searches for the document with the lowest 'b' value and finds RID1: {a: 1, b: 1}
- Thread 2: updates RID1: {_id: 1, b: 1} to {_id: 1, b: 5}
- Thread 1: Gets a write conflict.
- Thread 1 Retries, still on the document with RID1. Thread 1 updates RID1 to {_id: 1, b: 4}
The fAM essentially does its "read" before the other transaction which changes the sort key, but then does its write afterwards. This is technically legal with read committed semantics, though very counter intuitive.
It's worth pointing out that similar anomalies will always be possible. For example, it's possible another thread could have inserted a document with b: 0 while the fAM was running. This could only be prevented with coarse grain locks (ie preventing writes to the entire collection).
Options
- Update documentation to make it clear that the document modified was at one point first in the sort order, but that may not necessarily be the case when the update occurs.
- Change the Update stage to re-check that the sort key is the same value after re-fetching a document post-write conflict. If the sort key value changed, we retry.
- If we considered this, we'd have to reason through the performance consequences. For example, if the fAM had to ixscan/fetch a bunch of documents before it settled on which one to update. However, it would give fAM stronger semantics when reasoning about individual documents.
- related to
-
SERVER-86249 Consider changing findAndModify behavior when concurrent transaction re-inserts matching document
- Open
-
SERVER-78140 allow update to supply sort option
- Closed