1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
/**
* Tests that the _mdb_catalog does not reuse RecordIds after a catalog restart.
* @tags: [
* requires_persistence,
* requires_replication,
* ]
*/
(function() {
'use strict';
TestData.rollbackShutdowns = true;
TestData.logComponentVerbosity = {
storage: {recovery: 2}
};
load('jstests/replsets/libs/rollback_test.js');
const rollbackTest = new RollbackTest();
let primary = rollbackTest.getPrimary();
// Do a majority write to guarantee the stable timestamp contains this create. Otherwise startup
// replication recovery will recreate the collection, initializing the _mdb_catalog RecordId
// generator.
assert.commandWorked(
primary.getDB("foo").runCommand({create: "timestamped", writeConcern: {w: "majority"}}));
// This restart forces the _mdb_catalog to refresh, uninitializing the auto-incrementing RecordId
// generator.
jsTestLog({msg: "Restarting primary.", primary: primary, nodeId: primary.nodeId});
const SIGTERM = 15; // clean shutdown
rollbackTest.restartNode(primary.nodeId, SIGTERM);
let rollbackNode = rollbackTest.transitionToRollbackOperations();
jsTestLog({
msg: "The restarted primary must be the node that goes into rollback.",
primary: primary,
rollback: rollbackNode
});
assert.eq(primary, rollbackNode);
// The `timestamped` collection is positioned as the last record in the _mdb_catalog. An unpatched
// MongoDB dropping this collection will result in its RecordId being reused.
assert.commandWorked(rollbackNode.getDB("foo").runCommand({drop: "timestamped"}));
// Reusing the RecordId with an untimestamped write (due to being in the `local` database) results
// in an illegal update chain. A successful rollback should see the timestamped collection. But an
// unpatched MongoDB would have the untimestamped update on the same update chain, "locking in" the
// drop.
assert.commandWorked(rollbackNode.getDB("local").createCollection("untimestamped"));
rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
rollbackTest.transitionToSyncSourceOperationsDuringRollback();
rollbackTest.transitionToSteadyStateOperations();
assert.contains("timestamped", rollbackNode.getDB("foo").getCollectionNames());
assert.contains("untimestamped", rollbackNode.getDB("local").getCollectionNames());
rollbackTest.stop();
})();
|