mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-24 00:17:37 +01:00
164 lines
8.0 KiB
JavaScript
164 lines
8.0 KiB
JavaScript
export var ReadWriteConcernDefaultsPropagation = (function() {
|
|
const kDefaultReadConcernField = "defaultReadConcern";
|
|
const kDefaultWriteConcernField = "defaultWriteConcern";
|
|
const kUpdateOpTimeField = "updateOpTime";
|
|
const kUpdateWallClockTimeField = "updateWallClockTime";
|
|
const kLocalUpdateWallClockTimeField = "localUpdateWallClockTime";
|
|
|
|
const kDefaultRWCFields = [kDefaultReadConcernField, kDefaultWriteConcernField];
|
|
const kExtraSetFields = [kUpdateOpTimeField, kUpdateWallClockTimeField];
|
|
const kExtraLocalFields = [kLocalUpdateWallClockTimeField];
|
|
const kExtraFields = [...kExtraSetFields, ...kExtraLocalFields];
|
|
const kSetFields = [...kDefaultRWCFields, ...kExtraSetFields];
|
|
|
|
const timeoutSecs = 2 * 60;
|
|
const intervalSecs = 5;
|
|
|
|
// Check that setting the defaults on setConn propagates correctly across checkConns.
|
|
function setDefaultsAndVerifyPropagation(setConn, checkConns, inMemory) {
|
|
// Get the current defaults from setConn.
|
|
var initialSetConnDefaults =
|
|
assert.commandWorked(setConn.adminCommand({getDefaultRWConcern: 1}));
|
|
|
|
// Ensure that all checkConns agree with this. Use a loop in case the initial defaults were
|
|
// recently set and have not yet propagated to all nodes.
|
|
var checkConnsDefaults = [];
|
|
var initialCheckConnsDefaults = [];
|
|
assert.soon(
|
|
() => {
|
|
initialCheckConnsDefaults = checkConns.map(
|
|
conn => assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})));
|
|
return initialCheckConnsDefaults.every(
|
|
checkConnDefaults =>
|
|
kSetFields.every(field => friendlyEqual(checkConnDefaults[field],
|
|
initialSetConnDefaults[field])));
|
|
},
|
|
() => "expected initial defaults to be present on all nodes within" + timeoutSecs +
|
|
" secs. Expected defaults: " + tojson(initialSetConnDefaults) + ", checkConns: " +
|
|
tojson(checkConns) + ", current state: " + tojson(initialCheckConnsDefaults),
|
|
timeoutSecs * 1000,
|
|
intervalSecs * 1000,
|
|
{runHangAnalyzer: false});
|
|
|
|
// Set new defaults on setConn.
|
|
var newDefaults = {
|
|
defaultReadConcern: {level: "majority"},
|
|
defaultWriteConcern: {w: 2, wtimeout: 0}
|
|
};
|
|
// If these happen to match what's already there, adjust them.
|
|
if (initialSetConnDefaults.defaultReadConcern &&
|
|
friendlyEqual(initialSetConnDefaults.defaultReadConcern,
|
|
newDefaults.defaultReadConcern)) {
|
|
newDefaults.defaultReadConcern.level = "local";
|
|
}
|
|
if (initialSetConnDefaults.defaultWriteConcern &&
|
|
friendlyEqual(initialSetConnDefaults.defaultWriteConcern,
|
|
newDefaults.defaultWriteConcern)) {
|
|
newDefaults.defaultWriteConcern.w++;
|
|
}
|
|
var cmd = {setDefaultRWConcern: 1};
|
|
Object.extend(cmd, newDefaults);
|
|
cmd.writeConcern = {
|
|
w: 1
|
|
}; // Prevent any existing default WC (which may be unsatisfiable) from being applied.
|
|
var newDefaultsRes = assert.commandWorked(setConn.adminCommand(cmd));
|
|
kDefaultRWCFields.forEach(field => assert.eq(newDefaultsRes[field],
|
|
newDefaults[field],
|
|
field + " was not set correctly"));
|
|
assert.hasFields(
|
|
newDefaultsRes, kExtraFields, "missing field in result of setDefaultRWConcern");
|
|
|
|
// Check that updateOpTime has increased. Since everything is running on one host, we can
|
|
// also check that each of kUpdateOpTime and localUpdateWallClockTime have increased.
|
|
kExtraFields.forEach(field => {
|
|
if (field in initialSetConnDefaults) {
|
|
assert.gt(newDefaultsRes[field],
|
|
initialSetConnDefaults[field],
|
|
field + " did not increase after setting new defaults");
|
|
}
|
|
});
|
|
|
|
// Ensure that all checkConns agree with this.
|
|
assert.soon(
|
|
function() {
|
|
// Get the defaults from all the connections.
|
|
checkConnsDefaults = checkConns.map(conn => assert.commandWorked(conn.adminCommand(
|
|
{getDefaultRWConcern: 1, inMemory})));
|
|
|
|
// Check if they all match the recently-set values.
|
|
for (var connDefault of checkConnsDefaults) {
|
|
if (inMemory) {
|
|
assert.eq(true, connDefault.inMemory, tojson(connDefault));
|
|
} else {
|
|
assert.eq(undefined, connDefault.inMemory, tojson(connDefault));
|
|
}
|
|
|
|
for (var field of kSetFields) {
|
|
if (!friendlyEqual(connDefault[field], newDefaultsRes[field])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
() => "updated defaults failed to propagate to all nodes within " + timeoutSecs +
|
|
" secs. Expected defaults: " + tojson(newDefaults) +
|
|
", checkConns: " + tojson(checkConns) +
|
|
", current state: " + tojson(checkConnsDefaults) + ", inMemory: " + inMemory,
|
|
timeoutSecs * 1000,
|
|
intervalSecs * 1000,
|
|
{runHangAnalyzer: false});
|
|
}
|
|
|
|
/**
|
|
* Tests propagation of RWC defaults across an environment. Updated RWC defaults are set using
|
|
* setConn, and then each connection in the checkConns array is checked to ensure that it
|
|
* becomes aware of the new defaults (within the acceptable window of 2 minutes).
|
|
*/
|
|
var runTests = function(setConn, checkConns, inMemory) {
|
|
// Since these connections are on a brand new replset/cluster, this checks the propagation
|
|
// of the initial setting of defaults.
|
|
setDefaultsAndVerifyPropagation(setConn, checkConns, inMemory);
|
|
|
|
// Do it again to check that updating the defaults also propagates correctly.
|
|
setDefaultsAndVerifyPropagation(setConn, checkConns, inMemory);
|
|
};
|
|
|
|
/**
|
|
* Asserts eventually all given nodes have no default RWC in their in-memory cache.
|
|
*/
|
|
function verifyPropgationOfNoDefaults(checkConns) {
|
|
assert.soon(() => checkConns.every(checkConn => {
|
|
const defaultsRes = assert.commandWorked(
|
|
checkConn.adminCommand({getDefaultRWConcern: 1, inMemory: true}));
|
|
|
|
// Note localUpdateWallClockTime is generated by the in-memory cache, so it will be
|
|
// present even if there are no defaults.
|
|
const unexpectedFields = kDefaultRWCFields.concat(kExtraSetFields).filter(field => {
|
|
return (field !== kDefaultWriteConcernField) && field !== kDefaultReadConcernField;
|
|
});
|
|
return unexpectedFields.every(field => !defaultsRes.hasOwnProperty(field));
|
|
}),
|
|
"deleted/dropped defaults failed to propagate to all nodes within " +
|
|
timeoutSecs + " secs. checkConns: " + tojson(checkConns),
|
|
timeoutSecs * 1000,
|
|
intervalSecs * 1000,
|
|
{runHangAnalyzer: false});
|
|
}
|
|
|
|
/**
|
|
* Tests that when the RWC defaults document is removed, either through a delete or drop of
|
|
* config.settings, the RWC defaults cache is invalidated.
|
|
*/
|
|
var runDropAndDeleteTests = function(mainConn, checkConns) {
|
|
// Set the defaults to some value other than the implicit server defaults. Then remove the
|
|
// defaults document and verify the cache is invalidated on all nodes.
|
|
setDefaultsAndVerifyPropagation(mainConn, checkConns);
|
|
assert.commandWorked(
|
|
mainConn.getDB("config").settings.remove({_id: "ReadWriteConcernDefaults"}));
|
|
verifyPropgationOfNoDefaults(checkConns);
|
|
};
|
|
|
|
return {runTests, runDropAndDeleteTests};
|
|
})();
|