Info
Suppose the document being inserted into a collection is of the form:
RecordId(1) -> X
and the logical key/value being inserted into the index is of the form:
KeyString(X) -> RecordId(1)
WT (non _id) unique indexes will make writes to two keys:
KeyString(X) + RecordId(1)
KeyString(X)
The first key is persisted (on a successful WT txn commit). The second key is deleted before committing. The purpose of the second key is to correctly maintain the unique index constraint in the face of concurrent transactions at snapshot isolation that can possibly observe write skew .
For primaries this works fine. For secondaries, we can process oplog entries out of order. This has a consequence for the common key two separate inserts can touch. Consider the following oplog entries being applied to collection with a unique index on x:
| Oplog
|
|-------------------------------|
| Insert {_id: 1, x: 1} @ TS(1) |
| Delete {_id: 1}
@ TS(2) |
| Insert {_id: 2, x: 1} @ TS(3) |
Those oplog entries can be applied with the following interleaving:
| Applier 1
| Applier 2
|
|-----------------------------------+-----------------------------------|
|
| BeginTxn
|
|
| SetTimestamp 3
|
|
| Insert KeyString(1)
|
|
| Delete KeyString(1)
|
|
| Insert KeyString(1) + RecordId(2) |
|
| Commit
|
|
|
|
| BeginTxn
|
|
| SetTimestamp 1
|
|
| Insert KeyString(1)
|
|
| Delete KeyString(1)
|
|
| Insert KeyString(1) + RecordId(1) |
|
| Commit
|
|
Top User Comments
daniel.gottlieb@10gen.com commented on Fri, 15 Oct 2021 01:33:42 +0000:
Without going into my proof of correctness case analysis, I'm thinking we can solve this problem by simply omitting this insert/delete pair of writes on secondaries.