Merge pull request #2641 from atn34/atn34/configure-locked

Allow a new database to be configured locked
This commit is contained in:
Meng Xu 2020-02-13 09:47:46 -08:00 committed by GitHub
commit 5e78d0ad1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 9 deletions

View File

@ -1774,6 +1774,10 @@ ACTOR Future<bool> configure( Database db, std::vector<StringRef> tokens, Refere
printf("Configuration changed\n");
ret=false;
break;
case ConfigurationResult::LOCKED_NOT_NEW:
printf("ERROR: `only new databases can be configured as locked`\n");
ret = true;
break;
default:
ASSERT(false);
ret=true;

View File

@ -52,6 +52,13 @@ std::map<std::string, std::string> configForToken( std::string const& mode ) {
return out;
}
if (mode == "locked") {
// Setting this key is interpreted as an instruction to use the normal version-stamp-based mechanism for locking
// the database.
out[databaseLockedKey.toString()] = deterministicRandom()->randomUniqueID().toString();
return out;
}
size_t pos;
// key:=value is unvalidated and unchecked
@ -297,6 +304,17 @@ ACTOR Future<ConfigurationResult::Type> changeConfig( Database cx, std::map<std:
// make sure we have essential configuration options
std::string initKey = configKeysPrefix.toString() + "initialized";
state bool creating = m.count( initKey ) != 0;
state Optional<UID> locked;
{
auto iter = m.find(databaseLockedKey.toString());
if (iter != m.end()) {
if (!creating) {
return ConfigurationResult::LOCKED_NOT_NEW;
}
locked = UID::fromString(iter->second);
m.erase(iter);
}
}
if (creating) {
m[initIdKey.toString()] = deterministicRandom()->randomUniqueID().toString();
if (!isCompleteConfiguration(m)) {
@ -484,7 +502,16 @@ ACTOR Future<ConfigurationResult::Type> changeConfig( Database cx, std::map<std:
tr.addReadConflictRange( singleKeyRange(m.begin()->first) );
}
for(auto i=m.begin(); i!=m.end(); ++i)
if (locked.present()) {
ASSERT(creating);
tr.atomicOp(databaseLockedKey,
BinaryWriter::toValue(locked.get(), Unversioned())
.withPrefix(LiteralStringRef("0123456789"))
.withSuffix(LiteralStringRef("\x00\x00\x00\x00")),
MutationRef::SetVersionstampedValue);
}
for (auto i = m.begin(); i != m.end(); ++i)
tr.set( StringRef(i->first), StringRef(i->second) );
tr.addReadConflictRange( singleKeyRange(moveKeysLockOwnerKey) );

View File

@ -61,7 +61,8 @@ public:
NOT_ENOUGH_WORKERS,
REGION_REPLICATION_MISMATCH,
DCID_MISSING,
SUCCESS
LOCKED_NOT_NEW,
SUCCESS,
};
};

View File

@ -1088,11 +1088,14 @@ void SimulationConfig::generateNormalConfig(int minimumReplication, int minimumR
void setupSimulatedSystem(vector<Future<Void>>* systemActors, std::string baseFolder, int* pTesterCount,
Optional<ClusterConnectionString>* pConnString, Standalone<StringRef>* pStartingConfiguration,
int extraDB, int minimumReplication, int minimumRegions, Reference<TLSOptions> tlsOptions,
std::string whitelistBinPaths) {
std::string whitelistBinPaths, bool configureLocked) {
// SOMEDAY: this does not test multi-interface configurations
SimulationConfig simconfig(extraDB, minimumReplication, minimumRegions);
StatusObject startingConfigJSON = simconfig.db.toJSON(true);
std::string startingConfigString = "new";
if (configureLocked) {
startingConfigString += " locked";
}
for( auto kv : startingConfigJSON) {
startingConfigString += " ";
if( kv.second.type() == json_spirit::int_type ) {
@ -1351,7 +1354,8 @@ void setupSimulatedSystem(vector<Future<Void>>* systemActors, std::string baseFo
.detail("StartingConfiguration", pStartingConfiguration->toString());
}
void checkExtraDB(const char *testFile, int &extraDB, int &minimumReplication, int &minimumRegions) {
void checkTestConf(const char* testFile, int& extraDB, int& minimumReplication, int& minimumRegions,
int& configureLocked) {
std::ifstream ifs;
ifs.open(testFile, std::ifstream::in);
if (!ifs.good())
@ -1383,6 +1387,10 @@ void checkExtraDB(const char *testFile, int &extraDB, int &minimumReplication, i
if (attrib == "minimumRegions") {
sscanf( value.c_str(), "%d", &minimumRegions );
}
if (attrib == "configureLocked") {
sscanf(value.c_str(), "%d", &configureLocked);
}
}
ifs.close();
@ -1396,7 +1404,8 @@ ACTOR void setupAndRun(std::string dataFolder, const char *testFile, bool reboot
state int extraDB = 0;
state int minimumReplication = 0;
state int minimumRegions = 0;
checkExtraDB(testFile, extraDB, minimumReplication, minimumRegions);
state int configureLocked = 0;
checkTestConf(testFile, extraDB, minimumReplication, minimumRegions, configureLocked);
// TODO (IPv6) Use IPv6?
wait(g_simulator.onProcess(
@ -1427,7 +1436,7 @@ ACTOR void setupAndRun(std::string dataFolder, const char *testFile, bool reboot
else {
g_expect_full_pointermap = 1;
setupSimulatedSystem(&systemActors, dataFolder, &testerCount, &connFile, &startingConfiguration, extraDB,
minimumReplication, minimumRegions, tlsOptions, whitelistBinPaths);
minimumReplication, minimumRegions, tlsOptions, whitelistBinPaths, configureLocked);
wait( delay(1.0) ); // FIXME: WHY!!! //wait for machines to boot
}
std::string clusterFileDir = joinPath( dataFolder, deterministicRandom()->randomUniqueID().toString() );

View File

@ -970,6 +970,8 @@ vector<TestSpec> readTests( ifstream& ifs ) {
TraceEvent("TestParserTest").detail("ParsedSimDrAgents", spec.simDrAgents);
} else if( attrib == "extraDB" ) {
TraceEvent("TestParserTest").detail("ParsedExtraDB", "");
} else if ( attrib == "configureLocked" ) {
TraceEvent("TestParserTest").detail("ParsedConfigureLocked", "");
} else if( attrib == "minimumReplication" ) {
TraceEvent("TestParserTest").detail("ParsedMinimumReplication", "");
} else if( attrib == "minimumRegions" ) {

View File

@ -27,12 +27,14 @@
struct LockDatabaseWorkload : TestWorkload {
double lockAfter, unlockAfter;
bool ok;
bool onlyCheckLocked;
LockDatabaseWorkload(WorkloadContext const& wcx)
: TestWorkload(wcx), ok(true)
{
lockAfter = getOption( options, LiteralStringRef("lockAfter"), 0.0 );
unlockAfter = getOption( options, LiteralStringRef("unlockAfter"), 10.0 );
onlyCheckLocked = getOption(options, LiteralStringRef("onlyCheckLocked"), false);
ASSERT(unlockAfter > lockAfter);
}
@ -42,9 +44,8 @@ struct LockDatabaseWorkload : TestWorkload {
return Void();
}
virtual Future<Void> start( Database const& cx ) {
if( clientId == 0 )
return lockWorker( cx, this );
virtual Future<Void> start(Database const& cx) {
if (clientId == 0) return onlyCheckLocked ? timeout(checkLocked(cx, this), 60, Void()) : lockWorker(cx, this);
return Void();
}
@ -110,6 +111,7 @@ struct LockDatabaseWorkload : TestWorkload {
self->ok = false;
return Void();
} catch( Error &e ) {
TEST(e.code() == error_code_database_locked); // Database confirmed locked
wait( tr.onError(e) );
}
}

View File

@ -100,6 +100,7 @@ if(WITH_PYTHON)
add_fdb_test(TEST_FILES fast/BackupToDBCorrectness.txt)
add_fdb_test(TEST_FILES fast/BackupToDBCorrectnessClean.txt)
add_fdb_test(TEST_FILES fast/CloggedSideband.txt)
add_fdb_test(TEST_FILES fast/ConfigureLocked.txt)
add_fdb_test(TEST_FILES fast/ConstrainedRandomSelector.txt)
add_fdb_test(TEST_FILES fast/CycleAndLock.txt)
add_fdb_test(TEST_FILES fast/CycleTest.txt)

View File

@ -0,0 +1,6 @@
testTitle=ConfigureLocked
testName=LockDatabase
configureLocked=1
onlyCheckLocked=true
runConsistencyCheck=false
clearAfterTest=false