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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
/**
* Tests the TenantMigrationAccessBlocker and donor state document are updated correctly after
* the donorStartMigration command is run.
*
* @tags: [requires_fcv_46]
*/
(function() {
"use strict";
load("jstests/libs/fail_point_util.js");
load("jstests/libs/parallelTester.js");
// An object that mirrors the access states for the TenantMigrationAccessBlocker.
const accessState = {
kAllow: 0,
kBlockingWrites: 1,
kBlockingReadsAndWrites: 2,
kReject: 3
};
const donorRst =
new ReplSetTest({nodes: [{}, {rsConfig: {priority: 0}}, {rsConfig: {priority: 0}}]});
const recipientRst = new ReplSetTest({nodes: 1});
donorRst.startSet();
donorRst.initiate();
const donorPrimary = donorRst.getPrimary();
const kRecipientConnString = recipientRst.getURL();
const kDBPrefix = 'testDb';
const kConfigDonorsNS = "config.tenantMigrationDonors";
(() => {
// Test the case where the migration commits.
const dbName = kDBPrefix + "Commit";
function startMigration(host, recipientConnString, dbName) {
const primary = new Mongo(host);
assert.commandWorked(primary.adminCommand({
donorStartMigration: 1,
migrationId: UUID(),
recipientConnectionString: recipientConnString,
databasePrefix: dbName,
readPreference: {mode: "primary"}
}));
}
let migrationThread =
new Thread(startMigration, donorPrimary.host, kRecipientConnString, dbName);
let blockingFp = configureFailPoint(donorPrimary, "pauseTenantMigrationAfterBlockingStarts");
migrationThread.start();
// Wait for the migration to enter the blocking state.
blockingFp.wait();
let mtab = donorPrimary.adminCommand({serverStatus: 1}).tenantMigrationAccessBlocker;
assert.eq(mtab[dbName].access, accessState.kBlockingReadsAndWrites);
assert(mtab[dbName].blockTimestamp);
let donorDoc = donorPrimary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName});
let blockOplogEntry = donorPrimary.getDB("local").oplog.rs.findOne(
{ns: kConfigDonorsNS, op: "u", "o.databasePrefix": dbName});
assert.eq(donorDoc.state, "blocking");
assert.eq(donorDoc.blockTimestamp, blockOplogEntry.ts);
// Allow the migration to complete.
blockingFp.off();
migrationThread.join();
mtab = donorPrimary.adminCommand({serverStatus: 1}).tenantMigrationAccessBlocker;
assert.eq(mtab[dbName].access, accessState.kReject);
assert(mtab[dbName].commitOrAbortOpTime);
donorDoc = donorPrimary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName});
let commitOplogEntry =
donorPrimary.getDB("local").oplog.rs.findOne({ns: kConfigDonorsNS, op: "u", o: donorDoc});
assert.eq(donorDoc.state, "committed");
assert.eq(donorDoc.commitOrAbortOpTime.ts, commitOplogEntry.ts);
})();
(() => {
// Test the case where the migration aborts.
const dbName = kDBPrefix + "Abort";
let abortFp = configureFailPoint(donorPrimary, "abortTenantMigrationAfterBlockingStarts");
assert.commandFailedWithCode(donorPrimary.adminCommand({
donorStartMigration: 1,
migrationId: UUID(),
recipientConnectionString: kRecipientConnString,
databasePrefix: dbName,
readPreference: {mode: "primary"}
}),
ErrorCodes.TenantMigrationAborted);
abortFp.off();
const mtab = donorPrimary.adminCommand({serverStatus: 1}).tenantMigrationAccessBlocker;
assert.eq(mtab[dbName].access, accessState.kAllow);
assert(!mtab[dbName].commitOrAbortOpTime);
const donorDoc = donorPrimary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName});
const abortOplogEntry =
donorPrimary.getDB("local").oplog.rs.findOne({ns: kConfigDonorsNS, op: "u", o: donorDoc});
assert.eq(donorDoc.state, "aborted");
assert.eq(donorDoc.commitOrAbortOpTime.ts, abortOplogEntry.ts);
})();
donorRst.stopSet();
})();
|