208 lines
8.9 KiB
JavaScript
208 lines
8.9 KiB
JavaScript
/**
|
|
* Verifies that haystack indexes cannot be created on 4.9+ binaries, but are maintained
|
|
* correctly in mixed version clusters.
|
|
*
|
|
* TODO SERVER-51871: This test can be deleted once 5.0 becomes last-lts.
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
load("jstests/multiVersion/libs/multi_rs.js"); // For 'upgradeSecondaries()/upgradePrimary()'
|
|
load('jstests/noPassthrough/libs/index_build.js'); // For 'assertIndexes()'
|
|
load("jstests/libs/fixture_helpers.js"); // For 'isSharded()'
|
|
|
|
const dbName = "test";
|
|
const collName = jsTestName();
|
|
const geoIndexKey = {
|
|
loc: "geoHaystack",
|
|
x: 1
|
|
};
|
|
const geoIndexName = "geo";
|
|
const indexList = ["_id_", geoIndexName];
|
|
const nonGeoIndexList = ["_id_"];
|
|
|
|
function insertInitialDocuments(coll) {
|
|
const documentList =
|
|
[{_id: 0, loc: [1, 2], x: 'foo', y: 2}, {_id: 1, loc: [1.5, 1.5], x: 'bar', y: 1}];
|
|
assert.commandWorked(coll.insert(documentList));
|
|
}
|
|
|
|
/**
|
|
* Calls 'validate()' on 'coll' and verifies that the documents which are inserted into 'coll'
|
|
* produce the correct number of index keys for the geoHaystack index in this test.
|
|
*/
|
|
function validateAndAssertCorrectIndexKeys(coll) {
|
|
const validateResult = assert.commandWorked(coll.validate({full: true}));
|
|
let validateOutput;
|
|
if (FixtureHelpers.isSharded(coll)) {
|
|
assert(validateResult.hasOwnProperty("raw"));
|
|
validateOutput = validateResult["raw"];
|
|
} else {
|
|
validateOutput = validateResult;
|
|
}
|
|
|
|
// There should be as many index keys as there are documents.
|
|
const expectedNumKeys = coll.find().itcount();
|
|
let keys = 0;
|
|
if (FixtureHelpers.isSharded(coll)) {
|
|
for (const shard of Object.keys(validateOutput)) {
|
|
keys += validateOutput[shard]["keysPerIndex"][geoIndexName];
|
|
assert.eq(0, validateOutput[shard]["errors"].length);
|
|
assert.eq(true, validateOutput[shard]["valid"]);
|
|
}
|
|
} else {
|
|
keys = validateOutput["keysPerIndex"][geoIndexName];
|
|
assert.eq(0, validateOutput["errors"].length);
|
|
assert.eq(true, validateOutput["valid"]);
|
|
}
|
|
|
|
assert.eq(expectedNumKeys, keys);
|
|
}
|
|
|
|
// Verify that haystack indexes cannot be created on a standalone in the latest version regardless
|
|
// of the FCV.
|
|
function runStandaloneTest() {
|
|
const mongo = MongoRunner.runMongod({binVersion: "latest"});
|
|
const testDB = mongo.getDB(dbName);
|
|
const coll = testDB[collName];
|
|
for (const fcv of [lastLTSFCV, latestFCV]) {
|
|
assert.commandWorked(mongo.adminCommand({setFeatureCompatibilityVersion: fcv}));
|
|
assert.commandFailedWithCode(
|
|
coll.createIndex(geoIndexKey, {name: geoIndexName, bucketSize: 1}),
|
|
ErrorCodes.CannotCreateIndex);
|
|
}
|
|
MongoRunner.stopMongod(mongo);
|
|
}
|
|
|
|
// Verify that haystack indexes are maintained properly on a mixed version replica set.
|
|
function runReplicaSetTest() {
|
|
// Set up a mixed version replica-set: both nodes will be initialized to the last-lts
|
|
// binary version (4.4), but the secondary will be initialized to the latest binary version.
|
|
const rst = new ReplSetTest({nodes: [{binVersion: "last-lts"}, {binVersion: "latest"}]});
|
|
rst.startSet();
|
|
rst.initiate();
|
|
let primaryDB = rst.getPrimary().getDB(dbName);
|
|
let primaryColl = primaryDB[collName];
|
|
insertInitialDocuments(primaryColl);
|
|
rst.awaitReplication();
|
|
|
|
// Creating a haystack index should still work.
|
|
assert.commandWorked(primaryDB.runCommand({
|
|
"createIndexes": collName,
|
|
indexes: [{key: geoIndexKey, name: geoIndexName, bucketSize: 1}],
|
|
writeConcern: {w: 2}
|
|
}));
|
|
|
|
// The haystack index should replicate correctly to the secondary.
|
|
const secondaryDB = rst.getSecondary().getDB(dbName);
|
|
const secondaryColl = secondaryDB[collName];
|
|
IndexBuildTest.assertIndexes(secondaryColl, indexList.length, indexList);
|
|
|
|
// Verify that documents which are inserted after the index is built produce valid index keys.
|
|
assert.commandWorked(
|
|
primaryColl.insert([{_id: 4, loc: [4, 4], x: "baz"}, {_id: 5, loc: [5, 5], x: "baz"}],
|
|
{writeConcern: {w: 2}}));
|
|
validateAndAssertCorrectIndexKeys(primaryColl);
|
|
validateAndAssertCorrectIndexKeys(secondaryColl);
|
|
|
|
// Upgrade the primary and attempt to re-create the index after the upgrade.
|
|
assert.commandWorked(
|
|
primaryDB.runCommand({"dropIndexes": collName, index: geoIndexName, writeConcern: {w: 2}}));
|
|
rst.upgradePrimary(rst.getPrimary(), {binVersion: "latest"});
|
|
rst.awaitNodesAgreeOnPrimary();
|
|
|
|
// Even though we haven't bumped the FCV, index creation should still fail on a primary in
|
|
// the latest version.
|
|
primaryDB = rst.getPrimary().getDB(dbName);
|
|
primaryColl = primaryDB[collName];
|
|
assert.commandFailedWithCode(
|
|
primaryColl.createIndex(geoIndexKey, {name: geoIndexName, bucketSize: 1}),
|
|
ErrorCodes.CannotCreateIndex);
|
|
|
|
rst.stopSet();
|
|
}
|
|
|
|
// Verify that haystack indexes are maintained properly in a mixed version sharded cluster.
|
|
function runShardingTest() {
|
|
// Set up a mixed version sharded cluster, where shard0's nodes are initialized to the last-lts
|
|
// binary version (4.4) and shard1's nodes are initialized to the latest binary version.
|
|
const st = new ShardingTest({
|
|
shards: {
|
|
rs0: {nodes: [{binVersion: "last-lts"}, {binVersion: "last-lts"}]},
|
|
rs1: {nodes: [{binVersion: "latest"}, {binVersion: "latest"}]}
|
|
},
|
|
other: {mongosOptions: {binVersion: "last-lts"}}
|
|
});
|
|
|
|
// Test that indexes are maintained properly during chunk migration. More precisely, verify
|
|
// that when a chunk from a shard consisting of 4.4 nodes with a haystack index is moved to a
|
|
// shard consisting of nodes in the latest binary version, the haystack index is built
|
|
// correctly on the shard in the latest binary version.
|
|
const mongos = st.s;
|
|
const ns = dbName + "." + collName;
|
|
|
|
// Create a sharded collection with two chunks: [MinKey, 1), [1, MaxKey], both on shard0.
|
|
assert.commandWorked(mongos.adminCommand({enableSharding: dbName}));
|
|
assert.commandWorked(mongos.adminCommand({movePrimary: dbName, to: st.shard0.shardName}));
|
|
assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {_id: 1}}));
|
|
assert.commandWorked(mongos.adminCommand({split: ns, middle: {_id: 1}}));
|
|
|
|
// Insert some documents and create a haystack index.
|
|
const db = mongos.getDB(dbName);
|
|
const coll = db[collName];
|
|
insertInitialDocuments(coll);
|
|
assert.commandWorked(coll.createIndex(geoIndexKey, {name: geoIndexName, bucketSize: 1}));
|
|
|
|
// Wait for shard0 to finish replicating its documents and building the index.
|
|
st.rs0.awaitReplication();
|
|
|
|
// Move the [1, MaxKey] chunk to shard1.
|
|
assert.commandWorked(mongos.adminCommand(
|
|
{moveChunk: ns, find: {_id: 1}, to: st.shard1.shardName, _waitForDelete: true}));
|
|
st.rs1.awaitReplication();
|
|
|
|
// Verify that shard1 has the haystack index after the chunk was moved.
|
|
const shard1primary = st.rs1.getPrimary();
|
|
const shard1DB = shard1primary.getDB(dbName);
|
|
const shard1Coll = shard1DB[collName];
|
|
IndexBuildTest.assertIndexes(shard1Coll, indexList.length, indexList);
|
|
|
|
validateAndAssertCorrectIndexKeys(coll);
|
|
|
|
// Verify that inserting documents into a shard consisting of nodes in the latest version with
|
|
// an existing haystack index will create the correct index keys for the index.
|
|
assert.commandWorked(
|
|
coll.insert([{_id: 4, loc: [4, 4], x: "baz"}, {_id: 5, loc: [5, 5], x: "blah"}],
|
|
{writeConcern: {w: 2}}));
|
|
|
|
validateAndAssertCorrectIndexKeys(coll);
|
|
|
|
// Creating a new haystack index against a sharded cluster with at least one shard upgraded to
|
|
// the latest version should fail.
|
|
assert.commandWorked(
|
|
db.runCommand({"dropIndexes": collName, index: geoIndexName, writeConcern: {w: 2}}));
|
|
assert.commandFailedWithCode(coll.createIndex(geoIndexKey, {name: geoIndexName, bucketSize: 1}),
|
|
ErrorCodes.CannotCreateIndex);
|
|
|
|
// Though the command failed, the haystack index will still be created on shard0 since it is in
|
|
// version 4.4.
|
|
const shard0DB = st.rs0.getPrimary().getDB(dbName);
|
|
const shard0coll = shard0DB[collName];
|
|
IndexBuildTest.assertIndexes(shard0coll, indexList.length, indexList);
|
|
|
|
// Since shard1 is in the latest version, it will not have the geoHaystack index.
|
|
IndexBuildTest.assertIndexes(shard1Coll, nonGeoIndexList.length, nonGeoIndexList);
|
|
|
|
// Though the 'dropIndexes' command will fail because shard1 does not have the haystack
|
|
// index, it should still remove the haystack index on shard0.
|
|
assert.commandFailedWithCode(
|
|
mongos.getDB(dbName).runCommand(
|
|
{"dropIndexes": collName, index: geoIndexName, writeConcern: {w: 2}}),
|
|
ErrorCodes.IndexNotFound);
|
|
IndexBuildTest.assertIndexes(shard0coll, nonGeoIndexList.length, nonGeoIndexList);
|
|
st.stop();
|
|
}
|
|
|
|
runStandaloneTest();
|
|
runReplicaSetTest();
|
|
runShardingTest();
|
|
})(); |