Since hybrid index build collection scan phase can yield, it can violate the locking contracts of prepared transactions. Consider a below sequence.
1) Hybrid index build gets started on secondary for a collection A. And, collection phase of hybrid index build on secondary gets yielded. (Makes all the mongoDB and document level locks to get released - abandons the snapshot).
2) Secondary node steps up and becomes the new primary.
3) Transaction gets stated and inserts some documents in collection A. (This step acquires the collection lock in mode IX)
4) Transaction gets prepared. (After which, it holds the mongoDB locks (database, collection, global) except RSTL lock).
5) Now, the node steps down. This will make any prepared transactions to yield mongoDB locks. (As on secondaries, prepared transactions does not hold locks.)
6) Index build started at step #1, gets resumed and able to continue with drain phase (acquires collection lock in S mode) and commit phase( acquires collection lock in X mode) when the documents in collection A is in the prepared state. As a result, while committing the index build, server crash occurs due to this sanity check made for the side write table. (Since the entries in the side write table is prepared but not yet committed, the entry isn't be visible outside the transaction. As a result, second drain phase couldn't apply entries from the side write table and _numApplied was set to 0).
Even, if we make the collection scan phase of index build to not yield, we would still can face the same problem mentioned above. Since, after SERVER-41462, hybrid index builder started on secondaries does not hold RSTL lock while performing index build (collection scan, drain and commit phase). SERVER-41462 was implemented mainly to avoid a 3 way deadlock between hybrid index builder, prepared transactions and step down. But, then, because of releasing RSTL lock, hybrid index builder started on secondaries won't be blocking the state transitions like step up and step down. This means even if the index build gets resumed after step 4, index build (second drain phase) gets blocked on the prepared transaction due to collection lock conflict. But, once step down occurs, second drain phase can now gets unblocked and able to acquire collection lock in S mode and proceed with the index building.
Basically we are trying to do a following sequence that is not valid
<Index Build START> <Prepare Txn> <Index Build Commit> <CommitTxn>
P.S: The above sequence is prevented during secondary oplog application by this.
Notes:
Valid Sequences
1) <Index Build START> <Index Build Commit> <Prepare Txn> <CommitTxn> [ Applies to PRIMARY, SECONDARY] 2) <Prepare Txn> <CommitTxn> <Index Build START> <Index Build Commit> [ Applies to PRIMARY, SECONDARY] 3) <Index Build START> <Prepare Txn> <CommitTxn> <Index Build Commit> [ Applies only to PRIMARY]
- is related to
-
SERVER-44577 Ensure WiredTiger cursors have started a transaction before reading data
- Closed
-
SERVER-44045 allow secondary index builds to start without unlocking the RSTL
- Closed
- related to
-
SERVER-41462 do not lock RSTL for uninterruptible index lock operations
- Closed