There are likely more JavaScript tests which have been added since
r3.6.9 that still need to be tagged.
(cherry picked from commit 05ec08fa62)
337 lines
9.6 KiB
JavaScript
337 lines
9.6 KiB
JavaScript
// @tags: [
|
|
// assumes_superuser_permissions,
|
|
// # Cannot implicitly shard accessed collections because the "splitVector" command cannot be run
|
|
// # on a sharded collection
|
|
// assumes_unsharded_collection,
|
|
// # rollbacks make WT RecordStore dataSize go out of sync, which negatively impacts the
|
|
// # splitVector calculations.
|
|
// does_not_support_stepdowns,
|
|
// # splitVector command is not available on embedded
|
|
// incompatible_with_embedded,
|
|
// requires_collstats,
|
|
// requires_fastcount,
|
|
// ]
|
|
|
|
// -------------------------
|
|
// SPLITVECTOR TEST UTILS
|
|
// -------------------------
|
|
|
|
// -------------------------
|
|
// assertChunkSizes verifies that a given 'splitVec' divides the 'test.jstest_splitvector'
|
|
// collection in 'maxChunkSize' approximately-sized chunks. Its asserts fail otherwise.
|
|
// @param splitVec: an array with keys for field 'x'
|
|
// e.g. [ { x : 1927 }, { x : 3855 }, ...
|
|
// @param numDocs: domain of 'x' field
|
|
// e.g. 20000
|
|
// @param maxChunkSize is in MBs.
|
|
//
|
|
assertChunkSizes = function(splitVec, numDocs, maxChunkSize, msg) {
|
|
splitVec = [{x: -1}].concat(splitVec);
|
|
splitVec.push({x: numDocs + 1});
|
|
for (i = 0; i < splitVec.length - 1; i++) {
|
|
min = splitVec[i];
|
|
max = splitVec[i + 1];
|
|
var avgObjSize = db.jstests_splitvector.stats().avgObjSize;
|
|
size = db.runCommand({datasize: "test.jstests_splitvector", min: min, max: max}).size;
|
|
|
|
// It is okay for the last chunk to be smaller. A collection's size does not
|
|
// need to be exactly a multiple of maxChunkSize.
|
|
if (i < splitVec.length - 2) {
|
|
// We are within one object of the correct chunk size.
|
|
assert.lt(Math.abs(maxChunkSize - size), avgObjSize, "A" + i);
|
|
} else {
|
|
assert.gt(maxChunkSize, size, "A" + i, msg + "b");
|
|
}
|
|
}
|
|
};
|
|
|
|
// Takes two documents and asserts that both contain exactly the same set of field names.
|
|
// This is useful for checking that splitPoints have the same format as the original key pattern,
|
|
// even when sharding on a prefix key.
|
|
// Not very efficient, so only call when # of field names is small
|
|
var assertFieldNamesMatch = function(splitPoint, keyPattern) {
|
|
for (var p in splitPoint) {
|
|
if (splitPoint.hasOwnProperty(p)) {
|
|
assert(keyPattern.hasOwnProperty(p), "property " + p + " not in keyPattern");
|
|
}
|
|
}
|
|
for (var p in keyPattern) {
|
|
if (keyPattern.hasOwnProperty(p)) {
|
|
assert(splitPoint.hasOwnProperty(p), "property " + p + " not in splitPoint");
|
|
}
|
|
}
|
|
};
|
|
|
|
var resetCollection = function() {
|
|
f.drop();
|
|
};
|
|
|
|
// Inserts numDocs into the given collection using a bulk operation. Each document's x value is its
|
|
// index within the batch, starting from 1, and the y value is the given filler.
|
|
let bulkInsertDocs = function(coll, numDocs, filler) {
|
|
const bulk = coll.initializeUnorderedBulkOp();
|
|
for (let i = 1; i <= numDocs; i++) {
|
|
bulk.insert({x: i, y: filler});
|
|
}
|
|
assert.writeOK(bulk.execute());
|
|
};
|
|
|
|
// Inserts numDocs into the given collection using a bulk operation. Each document's x value is set
|
|
// to the given xVal and the y value is the given filler.
|
|
let bulkInsertDocsFixedX = function(coll, numDocs, filler, xVal) {
|
|
const bulk = coll.initializeUnorderedBulkOp();
|
|
for (let i = 1; i <= numDocs; i++) {
|
|
bulk.insert({x: xVal, y: filler});
|
|
}
|
|
assert.writeOK(bulk.execute());
|
|
};
|
|
|
|
// -------------------------
|
|
// TESTS START HERE
|
|
// -------------------------
|
|
f = db.jstests_splitvector;
|
|
resetCollection();
|
|
|
|
// -------------------------
|
|
// Case 1: missing parameters
|
|
|
|
assert.eq(false, db.runCommand({splitVector: "test.jstests_splitvector"}).ok, "1a");
|
|
assert.eq(
|
|
false, db.runCommand({splitVector: "test.jstests_splitvector", maxChunkSize: 1}).ok, "1b");
|
|
|
|
// -------------------------
|
|
// Case 2: missing index
|
|
|
|
assert.eq(
|
|
false,
|
|
db.runCommand({splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, maxChunkSize: 1})
|
|
.ok,
|
|
"2");
|
|
|
|
// -------------------------
|
|
// Case 3: empty collection
|
|
|
|
f.ensureIndex({x: 1});
|
|
assert.eq(
|
|
[],
|
|
db.runCommand({splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, maxChunkSize: 1})
|
|
.splitKeys,
|
|
"3");
|
|
|
|
// -------------------------
|
|
// Case 4: uniform collection
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case4 = function() {
|
|
// Get baseline document size
|
|
filler = "";
|
|
while (filler.length < 500)
|
|
filler += "a";
|
|
f.save({x: 0, y: filler});
|
|
docSize = db.runCommand({datasize: "test.jstests_splitvector"}).size;
|
|
assert.gt(docSize, 500, "4a");
|
|
|
|
// Fill collection and get split vector for 1MB maxChunkSize
|
|
let numDocs = 4500;
|
|
bulkInsertDocs(f, numDocs - 1, filler); // 1 document was already inserted.
|
|
res = db.runCommand(
|
|
{splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, maxChunkSize: 1});
|
|
|
|
// splitVector aims at getting half-full chunks after split
|
|
factor = 0.5;
|
|
|
|
assert.eq(true, res.ok, "4b");
|
|
assert.close(
|
|
numDocs * docSize / ((1 << 20) * factor), res.splitKeys.length, "num split keys", -1);
|
|
assertChunkSizes(res.splitKeys, numDocs, (1 << 20) * factor, "4d");
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
};
|
|
case4();
|
|
|
|
// -------------------------
|
|
// Case 5: limit number of split points
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case5 = function() {
|
|
// Fill collection and get split vector for 1MB maxChunkSize
|
|
bulkInsertDocs(f, 4499, filler);
|
|
res = db.runCommand({
|
|
splitVector: "test.jstests_splitvector",
|
|
keyPattern: {x: 1},
|
|
maxChunkSize: 1,
|
|
maxSplitPoints: 1
|
|
});
|
|
|
|
assert.eq(true, res.ok, "5a");
|
|
assert.eq(1, res.splitKeys.length, "5b");
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
};
|
|
case5();
|
|
|
|
// -------------------------
|
|
// Case 6: limit number of objects in a chunk
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case6 = function() {
|
|
// Fill collection and get split vector for 1MB maxChunkSize
|
|
bulkInsertDocs(f, 1999, filler);
|
|
res = db.runCommand({
|
|
splitVector: "test.jstests_splitvector",
|
|
keyPattern: {x: 1},
|
|
maxChunkSize: 1,
|
|
maxChunkObjects: 500
|
|
});
|
|
|
|
assert.eq(true, res.ok, "6a");
|
|
assert.eq(3, res.splitKeys.length, "6b");
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
};
|
|
case6();
|
|
|
|
// -------------------------
|
|
// Case 7: enough occurances of min key documents to pass the chunk limit
|
|
// [1111111111111111,2,3)
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case7 = function() {
|
|
// Fill collection and get split vector for 1MB maxChunkSize
|
|
bulkInsertDocsFixedX(f, 2099, filler, 1);
|
|
bulkInsertDocsFixedX(f, 9, filler, 2);
|
|
res = db.runCommand(
|
|
{splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, maxChunkSize: 1});
|
|
|
|
assert.eq(true, res.ok, "7a");
|
|
assert.eq(2, res.splitKeys[0].x, "7b");
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
};
|
|
case7();
|
|
|
|
// -------------------------
|
|
// Case 8: few occurrances of min key, and enough of some other that we cannot split it
|
|
// [1, 22222222222222, 3)
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case8 = function() {
|
|
bulkInsertDocsFixedX(f, 9, filler, 1);
|
|
bulkInsertDocsFixedX(f, 2099, filler, 2);
|
|
bulkInsertDocsFixedX(f, 9, filler, 3);
|
|
res = db.runCommand(
|
|
{splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, maxChunkSize: 1});
|
|
|
|
assert.eq(true, res.ok, "8a");
|
|
assert.eq(2, res.splitKeys.length, "8b");
|
|
assert.eq(2, res.splitKeys[0].x, "8c");
|
|
assert.eq(3, res.splitKeys[1].x, "8d");
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
};
|
|
case8();
|
|
|
|
// -------------------------
|
|
// Case 9: splitVector "force" mode, where we split (possible small) chunks in the middle
|
|
//
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1});
|
|
|
|
var case9 = function() {
|
|
f.save({x: 1});
|
|
f.save({x: 2});
|
|
f.save({x: 3});
|
|
|
|
assert.eq(3, f.count());
|
|
print(f.getFullName());
|
|
|
|
res = db.runCommand({splitVector: f.getFullName(), keyPattern: {x: 1}, force: true});
|
|
|
|
assert.eq(true, res.ok, "9a");
|
|
assert.eq(1, res.splitKeys.length, "9b");
|
|
assert.eq(2, res.splitKeys[0].x, "9c");
|
|
|
|
if (db.runCommand("isMaster").msg != "isdbgrid") {
|
|
res = db.adminCommand(
|
|
{splitVector: "test.jstests_splitvector", keyPattern: {x: 1}, force: true});
|
|
|
|
assert.eq(true, res.ok, "9a: " + tojson(res));
|
|
assert.eq(1, res.splitKeys.length, "9b: " + tojson(res));
|
|
assert.eq(2, res.splitKeys[0].x, "9c: " + tojson(res));
|
|
for (i = 0; i < res.splitKeys.length; i++) {
|
|
assertFieldNamesMatch(res.splitKeys[i], {x: 1});
|
|
}
|
|
}
|
|
};
|
|
case9();
|
|
|
|
// -------------------------
|
|
// Repeat all cases using prefix shard key.
|
|
//
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case4();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case4();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case5();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case5();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case6();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case6();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case7();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case7();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case8();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case8();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: 1});
|
|
case9();
|
|
|
|
resetCollection();
|
|
f.ensureIndex({x: 1, y: -1, z: 1});
|
|
case9();
|
|
|
|
print("PASSED");
|