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
|
/**
* Test to ensure that indexes with long names are handled gracefully during a two phase collection
* drop rename. If a rename would violate length constraints on MMAPv1, the offending indexes should
* be physically dropped immediately.
*/
(function() {
'use strict';
load("jstests/replsets/libs/two_phase_drops.js"); // For TwoPhaseDropCollectionTest.
// Return a list of all indexes for a given collection. Use 'args' as the
// 'listIndexes' command arguments.
function listIndexes(database, coll, args) {
args = args || {};
let failMsg = "'listIndexes' command failed";
let listIndexesCmd = {listIndexes: coll};
let res = assert.commandWorked(database.runCommand(listIndexesCmd, args), failMsg);
return res.cursor.firstBatch;
}
// Set up a two phase drop test.
let testName = "drop_collection_two_phase_long_index_names";
let dbName = testName;
let collName = "collToDrop";
let twoPhaseDropTest = new TwoPhaseDropCollectionTest(testName, dbName);
// Initialize replica set.
let replTest = twoPhaseDropTest.initReplSet();
// Create the collection that will be dropped.
twoPhaseDropTest.createCollection(collName);
// Two phase collection drops should handle long index names gracefully. MMAPv1 imposes a hard
// limit on index namespaces so we have to drop indexes that are too long to store on disk after
// renaming the collection (see SERVER-29747). Other storage engines should allow the implicit
// index renames to proceed because these renamed indexes are internal and will not be visible
// to users (no risk of being exported to another storage engine).
let coll = replTest.getPrimary().getDB(dbName).getCollection(collName);
let maxNsLength = 127;
let longIndexName = ''.pad(maxNsLength - (coll.getFullName() + '.$').length, true, 'a');
let shortIndexName = "short_name";
// Create one index with a "too long" name, and one with a name of acceptable size.
assert.commandWorked(coll.ensureIndex({a: 1}, {name: longIndexName}));
assert.commandWorked(coll.ensureIndex({b: 1}, {name: shortIndexName}));
let droppedCollName = twoPhaseDropTest.prepareDropCollection(collName);
// Check that indexes that would violate the namespace length constraints after rename were
// dropped.
const primary = replTest.getPrimary();
let primaryDB = primary.getDB(dbName);
let indexes = listIndexes(primaryDB, droppedCollName);
assert(indexes.find(idx => idx.name === shortIndexName));
assert.eq(undefined, indexes.find(idx => idx.name === longIndexName));
// Check that index drop appears before collection drop in the oplog.
const oplogColl = primary.getCollection('local.oplog.rs');
const cmdNs = primaryDB.getCollection('$cmd').getFullName();
const dropOplogEntry = oplogColl.findOne({ns: cmdNs, o: {drop: collName}});
const dropIndexOplogEntry =
oplogColl.findOne({ns: cmdNs, o: {dropIndexes: collName, index: longIndexName}});
const dropTimestamp = dropOplogEntry.ts;
const dropIndexTimestamp = dropIndexOplogEntry.ts;
assert.lt(dropIndexTimestamp,
dropTimestamp,
'index was not dropped before collection. index drop: ' +
tojson(dropIndexOplogEntry) + ' . collection drop: ' + tojson(dropOplogEntry));
twoPhaseDropTest.commitDropCollection(collName);
replTest.stopSet();
})();
|