Operational Defect Database

BugZero found this defect 59 days ago.

MongoDB | 2616496

Initial sync / secondary oplog application don't update _nextId for recordId

Last update date:

3/21/2024

Affected products:

MongoDB Server

Affected releases:

No affected releases provided.

Fixed releases:

No fixed releases provided.

Description:

Info

When the recordId is provided (as in colls with recordIdsReplicated:true), on secondaries / during initial sync we don't take any additional steps to update _nextId so that it points to the highest of the recordIds provided (i.e. something like _nextId = max(_nextId, providedRecordId)), and therefore, _nextId can fall behind the highest recordId on the node. As a result, if the former secondary / initial syncing node becomes the primary, it will start allocating recordIds from the value of _nextId it has, which can mean it may use recordIds that are already in use, as _nextId might be smaller than the highest recordId on the node. This will result in the bug SERVER-88309. It's a surprise we haven't hit this dassert yet either.

Top User Comments


Steps to Reproduce

On the primary, perform the following: assert.commandWorked(primDB[collName].insertMany([ {_id: 1, a: 1}, // recordId: 1 {$recordId: 12, _id: 2, a: 2}, // recordId: 2 {_id: 3, $recordId: 13, a: 3}, // recordId: 3 {_id: 4, a: 4} // recordId: 4 ])); // Remove recordId: 1 and then insert the doc again, which now gets recordId: 5. assert.commandWorked(primDB[collName].remove({_id: 1})); assert.commandWorked(primDB[collName].insert({_id: 1, a: 1})); // There are now a total of 4 documents on the primary, but the recordIds are // [2, 3, 4, 5]. Add a new node and let it initial sync. Make the new node primary. As there are only 4 documents, on the new node, _ndextId is currently 5 (4 + 1). Therefore the next document inserted on it will get recordId(5) which collides with the doc with {_id: 1, a: 1}. Insert doc on new primary. assert.commandWorked(primDB[collName].insert({_id: 6, a: 6})); We see that the old doc was overwritten: > db.rrid.find().showRecordId() { "_id" : 2, "$recordId" : NumberLong(2), "a" : 2 } { "_id" : 3, "$recordId" : NumberLong(3), "a" : 3 } { "_id" : 4, "a" : 4, "$recordId" : NumberLong(4) } { "_id" : 6, "$recordId" : NumberLong(5) } // Overwrote the old doc!

Additional Resources / Links

Share:

BugZero® Risk Score

What's this?

Coming soon

Status

In Progress

Learn More

Search:

...