summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/rename_collection_across_dbs.js
blob: 5c2c3b8810ac671fa778c331bf272f16e595bb0b (plain)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
 * Tests batching of insert oplog entries when a collection is renamed across databases.
 *
 * @tags: [
 *   requires_replication,
 * ]
 */

(function() {
'use strict';

const testName = jsTestName();
let dbName1 = testName + '1-1';
let dbName2 = testName + '1-2';
const collName = "test";
const collCount = 10;
const maxInsertsCount = collCount;
const maxInsertsSize = /*single object size=*/ 14 * maxInsertsCount * 3;
let srcNs = dbName1 + '.' + collName;
let dstNs = dbName2 + '.' + collName;

//
// 1. Multiple oplog entries
//
jsTestLog("1. Multiple oplog entries");
const setParams = {
    "maxNumberOfInsertsBatchInsertsForRenameAcrossDatabases": maxInsertsCount,
    "maxSizeOfBatchedInsertsForRenameAcrossDatabasesBytes": maxInsertsSize
};
let rst = new ReplSetTest(
    {nodes: [{}, {rsConfig: {votes: 0, priority: 0}}], nodeOptions: {setParameter: setParams}});
rst.startSet();
rst.initiate();

let primary = rst.getPrimary();
let db = primary.getDB(dbName1);

let coll1 = db.getCollection(collName);
assert.commandWorked(coll1.insertMany([...Array(collCount).keys()].map(x => ({_id: x, a: x}))));
assert.commandWorked(db.adminCommand({renameCollection: srcNs, to: dstNs}));

let db2 = primary.getDB(dbName2);
let opEntries =
    db.getSiblingDB('local')
        .oplog.rs.find({op: 'i', ns: {$regex: '^' + dbName2 + '\.tmp.{5}\.renameCollection$'}})
        .sort({$natural: -1})
        .toArray();

assert.eq(0, opEntries.length, "Should be no insert oplog entries.");

opEntries = db.getSiblingDB('local')
                .oplog.rs
                .find({op: 'c', ns: 'admin.$cmd', "o.applyOps": {$exists: true}}, {"o.applyOps": 1})
                .sort({$natural: -1})
                .toArray();

let applyOpsOpEntries = opEntries[0].o.applyOps;
for (const op of applyOpsOpEntries) {
    assert.eq(op.op, "i", "Each applyOps operation should be an insert");
}
assert.eq(
    collCount, applyOpsOpEntries.length, "Should have " + collCount + " applyOps insert ops.");

// Check prior collection gone
assert(!db.getCollectionNames().includes(collName));

// Check new collection exists
let numNewDocs = db2.getCollection(collName).find().itcount();
assert.eq(collCount, numNewDocs);

//
// 2. Single oplog entry
//
jsTestLog("2. Single oplog entry");
dbName1 = testName + '2-1';
dbName2 = testName + '2-2';
srcNs = dbName1 + '.' + collName;
dstNs = dbName2 + '.' + collName;

primary = rst.getPrimary();
db = primary.getDB(dbName1);
db2 = primary.getDB(dbName1);

coll1 = db.getCollection(collName);
assert.commandWorked(coll1.insertOne(({_id: 1, a: 1})));
assert.commandWorked(db.adminCommand({renameCollection: srcNs, to: dstNs}));
opEntries =
    db.getSiblingDB('local')
        .oplog.rs.find({op: 'i', ns: {$regex: '^' + dbName2 + '\.tmp.{5}\.renameCollection$'}})
        .sort({$natural: -1})
        .toArray();
assert.eq(1, opEntries.length, "Should be 1 insert oplog entry, not in applyOps format.");
opEntries = db.getSiblingDB('local')
                .oplog.rs
                .find({
                    op: 'c',
                    ns: 'admin.$cmd',
                    "o.applyOps": {$exists: true},
                    "o.applyOps.ns": {$regex: '^' + dbName2 + '\.tmp.{5}\.renameCollection$'}
                })
                .sort({$natural: -1})
                .toArray();
assert.eq(
    0, opEntries.length, "Should be no applyOps oplog entries for an unbatched single insert.");

//
// 3. Too many documents
//
jsTestLog("3. Too many documents");
dbName1 = testName + '3-1-too-many-documents';
dbName2 = testName + '3-2-too-many-documents';
srcNs = dbName1 + '.' + collName;
dstNs = dbName2 + '.' + collName;

primary = rst.getPrimary();
db = primary.getDB(dbName1);
db2 = primary.getDB(dbName1);

coll1 = db.getCollection(collName);
let largeNumberOfDocsToExceedBatchCountLimit = (maxInsertsCount * 4);

// Add 1 extra document to spill over to a new batch with 1 element
for (let i = 0; i < largeNumberOfDocsToExceedBatchCountLimit + 1; i++) {
    assert.commandWorked(coll1.insertOne(({a: i})));
}

assert.commandWorked(db.adminCommand({renameCollection: srcNs, to: dstNs}));

// ns: rename_collection_across_dbs3-2-too-many-documents.tmp1h5Aj.renameCollection
opEntries =
    db.getSiblingDB('local')
        .oplog.rs.find({op: 'i', ns: {$regex: '^' + dbName2 + '\.tmp.{5}\.renameCollection$'}})
        .sort({$natural: -1})
        .toArray();

assert.eq(opEntries.length, 1, "Spillover insert should have its own insert entry.");

opEntries = db.getSiblingDB('local')
                .oplog.rs
                .find({
                    op: 'c',
                    ns: 'admin.$cmd',
                    "o.applyOps": {$exists: true},
                    "o.applyOps.ns": {$regex: '^' + dbName2 + '\.tmp.{5}\.renameCollection$'}
                })
                .sort({$natural: -1})
                .toArray();

for (let i = 0; i < opEntries.length; i++) {
    for (const op of opEntries[i]["o"]["applyOps"]) {
        assert.eq(op.op, "i", "Each applyOps operation should be an insert.");
    }
    // Keep in mind there is also a limit on the total size of the documents not just
    // the number of documents.
    assert.eq(opEntries[i]['o']["applyOps"].length,
              maxInsertsCount,
              "Each batch should contain the maximum size of " + maxInsertsCount + "entries.");
}
assert.eq(largeNumberOfDocsToExceedBatchCountLimit / maxInsertsCount,
          opEntries.length,
          "Should be " + largeNumberOfDocsToExceedBatchCountLimit + "/" + maxInsertsCount +
              " insert oplog entries, in applyOps format.");

rst.stopSet();
})();