1
0
Fork 0

Sort out race for update in configuration collection in Agency.

This only came up in the RocksDB engine, since only there can two write
operations report a conflict if transactions are running concurrently.
This commit is contained in:
Max Neunhoeffer 2017-05-03 15:37:43 +02:00
parent fb40a0c0ec
commit 9df8b5835b
3 changed files with 39 additions and 23 deletions

View File

@ -513,8 +513,9 @@ bool Agent::activateAgency() {
}
bool persisted = false;
try {
persisted = _state.persistActiveAgents(_config.activeToBuilder(),
_config.poolToBuilder());
_state.persistActiveAgents(_config.activeToBuilder(),
_config.poolToBuilder());
persisted = true;
} catch (std::exception const& e) {
LOG_TOPIC(FATAL, Logger::AGENCY)
<< "Failed to persist active agency: " << e.what();

View File

@ -605,6 +605,8 @@ bool State::loadOrPersistConfiguration() {
} else { // Fresh start
MUTEX_LOCKER(guard, _configurationWriteLock);
LOG_TOPIC(DEBUG, Logger::AGENCY) << "New agency!";
TRI_ASSERT(_agent != nullptr);
@ -830,28 +832,39 @@ bool State::persistReadDB(arangodb::consensus::index_t cind) {
return false;
}
bool State::persistActiveAgents(query_t const& active, query_t const& pool) {
auto bindVars = std::make_shared<VPackBuilder>();
bindVars->openObject();
bindVars->close();
void State::persistActiveAgents(query_t const& active, query_t const& pool) {
TRI_ASSERT(_vocbase != nullptr);
std::stringstream aql;
aql << "FOR c IN configuration UPDATE {_key:c._key} WITH {cfg:{active:";
aql << active->slice().toJson();
aql << ", pool:";
aql << pool->slice().toJson();
aql << "}} IN configuration";
std::string aqlStr = aql.str();
arangodb::aql::Query query(false, _vocbase, aqlStr.c_str(), aqlStr.size(),
bindVars, nullptr, arangodb::aql::PART_MAIN);
auto queryResult = query.execute(QueryRegistryFeature::QUERY_REGISTRY);
if (queryResult.code != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION_MESSAGE(queryResult.code, queryResult.details);
Builder builder;
{ VPackObjectBuilder guard(&builder);
builder.add("_key", VPackValue("0"));
builder.add(VPackValue("cfg"));
{ VPackObjectBuilder guard2(&builder);
builder.add("active", active->slice());
builder.add("pool", pool->slice());
}
}
return true;
MUTEX_LOCKER(guard, _configurationWriteLock);
auto transactionContext =
std::make_shared<transaction::StandaloneContext>(_vocbase);
SingleCollectionTransaction trx(
transactionContext, "configuration", AccessMode::Type::WRITE);
Result res = trx.begin();
if (!res.ok()) {
THROW_ARANGO_EXCEPTION(res);
}
auto result = trx.update("configuration", builder.slice(), _options);
if (!result.successful()) {
THROW_ARANGO_EXCEPTION_MESSAGE(result.code, result.errorMessage);
}
res = trx.finish(result.code);
if (!res.ok()) {
THROW_ARANGO_EXCEPTION_MESSAGE(res.errorNumber(), res.errorMessage());
}
}
query_t State::allLogs() const {

View File

@ -134,8 +134,8 @@ class State {
/// exists are overwritten
size_t removeConflicts(query_t const&);
/// @brief Persist active agency in pool
bool persistActiveAgents(query_t const& active, query_t const& pool);
/// @brief Persist active agency in pool, throws an exception in case of error
void persistActiveAgents(query_t const& active, query_t const& pool);
/// @brief Get everything from the state machine
query_t allLogs() const;
@ -205,6 +205,8 @@ class State {
/// @brief Empty log entry;
static log_t emptyLog;
/// @brief Protect writing into configuration collection
arangodb::Mutex _configurationWriteLock;
};
}