/// Load persisted configuration bool State::loadOrPersistConfiguration() { auto bindVars = std::make_shared<VPackBuilder>(); bindVars->openObject(); bindVars->close(); std::string const aql( std::string("FOR c in configuration FILTER c._key==\"0\" RETURN c.cfg")); arangodb::aql::Query query(false, _vocbase, aql.c_str(), aql.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); } VPackSlice result = queryResult.result->slice(); if (result.isArray() && result.length()) { // We already have a persisted conf try { LOG_TOPIC(DEBUG, Logger::AGENCY) << "Merging configuration " << result[0].resolveExternals().toJson(); _agent->mergeConfiguration(result[0].resolveExternals()); } catch (std::exception const& e) { LOG_TOPIC(ERR, Logger::AGENCY) << "Failed to merge persisted configuration into runtime " "configuration: " << e.what(); FATAL_ERROR_EXIT(); } } else { // Fresh start LOG_TOPIC(DEBUG, Logger::AGENCY) << "New agency!"; TRI_ASSERT(_agent != nullptr); _agent->id(to_string(boost::uuids::random_generator()())); auto transactionContext = std::make_shared<StandaloneTransactionContext>(_vocbase); SingleCollectionTransaction trx(transactionContext, "configuration", TRI_TRANSACTION_WRITE); int res = trx.begin(); OperationResult result; if (res != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION(res); } Builder doc; doc.openObject(); doc.add("_key", VPackValue("0")); doc.add("cfg", _agent->config().toBuilder()->slice()); doc.close(); try { result = trx.insert("configuration", doc.slice(), _options); } catch (std::exception const& e) { LOG_TOPIC(ERR, Logger::AGENCY) << "Failed to persist configuration entry:" << e.what(); FATAL_ERROR_EXIT(); } res = trx.finish(result.code); return (res == TRI_ERROR_NO_ERROR); } return true; }
ShortestPathOptions::ShortestPathOptions(VPackSlice const& slice) { VPackSlice obj = slice.get("shortestpathFlags"); weightAttribute = ""; if (obj.hasKey("weightAttribute")) { VPackSlice v = obj.get("weightAttribute"); if (v.isString()) { weightAttribute = v.copyString(); } } defaultWeight = 1; if (obj.hasKey("defaultWeight")) { VPackSlice v = obj.get("defaultWeight"); if (v.isNumber()) { defaultWeight = v.getNumericValue<double>(); } } }
v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate, VPackSlice const& slice, VPackOptions const* options, VPackSlice const* base) { switch (slice.type()) { case VPackValueType::Null: { return v8::Null(isolate); } case VPackValueType::Bool: { return v8::Boolean::New(isolate, slice.getBool()); } case VPackValueType::Double: { // convert NaN, +inf & -inf to null double value = slice.getDouble(); if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) { return v8::Null(isolate); } return v8::Number::New(isolate, slice.getDouble()); } case VPackValueType::Int: { int64_t value = slice.getInt(); if (value >= -2147483648LL && value <= 2147483647LL) { // value is within bounds of an int32_t return v8::Integer::New(isolate, static_cast<int32_t>(value)); } if (value >= 0 && value <= 4294967295LL) { // value is within bounds of a uint32_t return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value)); } // must use double to avoid truncation return v8::Number::New(isolate, static_cast<double>(slice.getInt())); } case VPackValueType::UInt: { uint64_t value = slice.getUInt(); if (value <= 4294967295ULL) { // value is within bounds of a uint32_t return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value)); } // must use double to avoid truncation return v8::Number::New(isolate, static_cast<double>(slice.getUInt())); } case VPackValueType::SmallInt: { return v8::Integer::New(isolate, slice.getNumericValue<int32_t>()); } case VPackValueType::String: { return ObjectVPackString(isolate, slice); } case VPackValueType::Array: { return ObjectVPackArray(isolate, slice, options, base); } case VPackValueType::Object: { return ObjectVPackObject(isolate, slice, options, base); } case VPackValueType::External: { // resolve external return TRI_VPackToV8(isolate, VPackSlice(slice.getExternal()), options, base); } case VPackValueType::Custom: { if (options == nullptr || options->customTypeHandler == nullptr || base == nullptr) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "Could not extract custom attribute."); } std::string id = options->customTypeHandler->toString(slice, options, *base); return TRI_V8_STD_STRING(id); } case VPackValueType::None: default: { return v8::Undefined(isolate); } } }
/// @brief Call to election void Constituent::callElection() { std::vector<bool> votes(size(), false); votes.at(_id) = true; // vote for myself _cast = true; if (_role == CANDIDATE) { this->term(_term + 1); // raise my term } std::string body; std::vector<OperationID> operationIDs(config().endpoints.size()); std::stringstream path; path << "/_api/agency_priv/requestVote?term=" << _term << "&candidateId=" << _id << "&prevLogIndex=" << _agent->lastLog().index << "&prevLogTerm=" << _agent->lastLog().term; // Ask everyone for their vote for (arangodb::consensus::id_t i = 0; i < config().endpoints.size(); ++i) { if (i != _id && endpoint(i) != "") { auto headerFields = std::make_unique<std::unordered_map<std::string, std::string>>(); operationIDs[i] = arangodb::ClusterComm::instance()->asyncRequest( "1", 1, config().endpoints[i], GeneralRequest::RequestType::GET, path.str(), std::make_shared<std::string>(body), headerFields, nullptr, config().minPing, true); } } // Wait randomized timeout std::this_thread::sleep_for( sleepFor(.5 * config().minPing, .8 * config().minPing)); // Collect votes // FIXME: This code can be improved: One can wait for an arbitrary // result by creating a coordinatorID and waiting for a pattern. for (arangodb::consensus::id_t i = 0; i < config().endpoints.size(); ++i) { if (i != _id && endpoint(i) != "") { ClusterCommResult res = arangodb::ClusterComm::instance()->enquire(operationIDs[i]); if (res.status == CL_COMM_SENT) { // Request successfully sent res = arangodb::ClusterComm::instance()->wait( "1", 1, operationIDs[i], "1"); std::shared_ptr<Builder> body = res.result->getBodyVelocyPack(); if (body->isEmpty()) { // body empty continue; } else { if (body->slice().isObject()) { // body VPackSlice slc = body->slice(); if (slc.hasKey("term") && slc.hasKey("voteGranted")) { // OK term_t t = slc.get("term").getUInt(); if (t > _term) { // follow? follow(t); break; } votes[i] = slc.get("voteGranted").getBool(); // Get vote } } } } else { // Request failed votes[i] = false; } } } // Count votes size_t yea = 0; for (size_t i = 0; i < size(); ++i) { if (votes[i]) { yea++; } } // Evaluate election results if (yea > size() / 2) { lead(votes); } else { follow(_term); } }
int Syncer::handleStateResponse(VPackSlice const& slice, std::string& errorMsg) { std::string const endpointString = " from endpoint '" + _masterInfo._endpoint + "'"; // process "state" section VPackSlice const state = slice.get("state"); if (!state.isObject()) { errorMsg = "state section is missing in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } // state."lastLogTick" VPackSlice const tick = state.get("lastLogTick"); if (!tick.isString()) { errorMsg = "lastLogTick is missing in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_voc_tick_t const lastLogTick = VelocyPackHelper::stringUInt64(tick); // state."running" bool running = VelocyPackHelper::getBooleanValue(state, "running", false); // process "server" section VPackSlice const server = slice.get("server"); if (!server.isObject()) { errorMsg = "server section is missing in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } // server."version" VPackSlice const version = server.get("version"); if (!version.isString()) { errorMsg = "server version is missing in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } // server."serverId" VPackSlice const serverId = server.get("serverId"); if (!serverId.isString()) { errorMsg = "server id is missing in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } // validate all values we got std::string const masterIdString(serverId.copyString()); TRI_server_id_t const masterId = StringUtils::uint64(masterIdString); if (masterId == 0) { // invalid master id errorMsg = "invalid server id in response" + endpointString; return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } if (masterIdString == _localServerIdString) { // master and replica are the same instance. this is not supported. errorMsg = "got same server id (" + _localServerIdString + ")" + endpointString + " as the local applier server's id"; return TRI_ERROR_REPLICATION_LOOP; } int major = 0; int minor = 0; std::string const versionString(version.copyString()); if (sscanf(versionString.c_str(), "%d.%d", &major, &minor) != 2) { errorMsg = "invalid master version info" + endpointString + ": '" + versionString + "'"; return TRI_ERROR_REPLICATION_MASTER_INCOMPATIBLE; } if (major != 3) { // we can connect to 3.x only errorMsg = "got incompatible master version" + endpointString + ": '" + versionString + "'"; return TRI_ERROR_REPLICATION_MASTER_INCOMPATIBLE; } _masterInfo._majorVersion = major; _masterInfo._minorVersion = minor; _masterInfo._serverId = masterId; _masterInfo._lastLogTick = lastLogTick; _masterInfo._active = running; LOG_TOPIC(INFO, Logger::REPLICATION) << "connected to master at " << _masterInfo._endpoint << ", id " << _masterInfo._serverId << ", version " << _masterInfo._majorVersion << "." << _masterInfo._minorVersion << ", last log tick " << _masterInfo._lastLogTick; return TRI_ERROR_NO_ERROR; }
/// @brief Call to election void Constituent::callElection() { std::map<std::string, bool> votes; std::vector<std::string> active = _agent->config().active(); // Get copy of active votes[_id] = true; // vote for myself term_t savedTerm; { MUTEX_LOCKER(locker, _castLock); this->termNoLock(_term + 1); // raise my term _cast = true; _votedFor = _id; savedTerm = _term; LOG_TOPIC(DEBUG, Logger::AGENCY) << "Set _leaderID to NO_LEADER" << " in term " << _term; _leaderID = NO_LEADER; } std::string body; std::map<std::string, OperationID> operationIDs; std::stringstream path; path << "/_api/agency_priv/requestVote?term=" << savedTerm << "&candidateId=" << _id << "&prevLogIndex=" << _agent->lastLog().index << "&prevLogTerm=" << _agent->lastLog().term; double minPing = _agent->config().minPing(); double respTimeout = 0.9 * minPing; double initTimeout = 0.5 * minPing; // Ask everyone for their vote for (auto const& i : active) { if (i != _id) { auto headerFields = std::make_unique<std::unordered_map<std::string, std::string>>(); operationIDs[i] = ClusterComm::instance()->asyncRequest( "1", 1, _agent->config().poolAt(i), rest::RequestType::GET, path.str(), std::make_shared<std::string>(body), headerFields, nullptr, respTimeout, true, initTimeout); } } // Wait randomized timeout std::this_thread::sleep_for(sleepFor(initTimeout, respTimeout)); // Collect votes for (const auto& i : active) { if (i != _id) { ClusterCommResult res = arangodb::ClusterComm::instance()->enquire(operationIDs[i]); if (res.status == CL_COMM_SENT) { // Request successfully sent res = ClusterComm::instance()->wait("1", 1, operationIDs[i], "1"); std::shared_ptr<Builder> body = res.result->getBodyVelocyPack(); if (body->isEmpty()) { // body empty continue; } else { if (body->slice().isObject()) { // body VPackSlice slc = body->slice(); if (slc.hasKey("term") && slc.hasKey("voteGranted")) { // OK term_t t = slc.get("term").getUInt(); if (t > _term) { // follow? follow(t); break; } votes[i] = slc.get("voteGranted").getBool(); // Get vote } } } } else { // Request failed votes[i] = false; } } } // Count votes size_t yea = 0; for (auto const& i : votes) { if (i.second) { ++yea; } } { MUTEX_LOCKER(locker, _castLock); if (savedTerm != _term) { followNoLock(_term); return; } } // Evaluate election results if (yea > size() / 2) { lead(savedTerm, votes); } else { follow(_term); } }
/// @brief create the block from VelocyPack, note that this can throw AqlItemBlock::AqlItemBlock(VPackSlice const slice) { bool exhausted = VelocyPackHelper::getBooleanValue(slice, "exhausted", false); if (exhausted) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "exhausted must be false"); } _nrItems = VelocyPackHelper::getNumericValue<size_t>(slice, "nrItems", 0); if (_nrItems == 0) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "nrItems must be > 0"); } _nrRegs = VelocyPackHelper::getNumericValue<RegisterId>(slice, "nrRegs", 0); // Initialize the data vector: if (_nrRegs > 0) { _data.resize(_nrItems * _nrRegs); } // Now put in the data: VPackSlice data = slice.get("data"); VPackSlice raw = slice.get("raw"); std::vector<AqlValue> madeHere; madeHere.reserve(static_cast<size_t>(raw.length())); madeHere.emplace_back(); // an empty AqlValue madeHere.emplace_back(); // another empty AqlValue, indices start w. 2 try { size_t posInRaw = 2; size_t posInData = 0; int64_t emptyRun = 0; for (RegisterId column = 0; column < _nrRegs; column++) { for (size_t i = 0; i < _nrItems; i++) { if (emptyRun > 0) { emptyRun--; } else { VPackSlice dataEntry = data.at(posInData++); if (!dataEntry.isNumber()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "data must contain only numbers"); } int64_t n = dataEntry.getNumericValue<int64_t>(); if (n == 0) { // empty, do nothing here } else if (n == -1) { // empty run: VPackSlice runLength = data.at(posInData++); TRI_ASSERT(runLength.isNumber()); emptyRun = runLength.getNumericValue<int64_t>(); emptyRun--; } else if (n == -2) { // a range VPackSlice lowBound = data.at(posInData++); VPackSlice highBound = data.at(posInData++); int64_t low = VelocyPackHelper::getNumericValue<int64_t>(lowBound, 0); int64_t high = VelocyPackHelper::getNumericValue<int64_t>(highBound, 0); AqlValue a(low, high); try { setValue(i, column, a); } catch (...) { a.destroy(); throw; } } else if (n == 1) { // a VelocyPack value AqlValue a(raw.at(posInRaw++)); try { setValue(i, column, a); // if this throws, a is destroyed again } catch (...) { a.destroy(); throw; } madeHere.emplace_back(a); } else if (n >= 2) { setValue(i, column, madeHere[static_cast<size_t>(n)]); // If this throws, all is OK, because it was already put into // the block elsewhere. } else { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "found undefined data value"); } } } } } catch (...) { destroy(); } }
arangodb::traverser::TraverserOptions::LookupInfo::LookupInfo( arangodb::aql::Query* query, VPackSlice const& info, VPackSlice const& shards) { TRI_ASSERT(shards.isArray()); idxHandles.reserve(shards.length()); conditionNeedUpdate = arangodb::basics::VelocyPackHelper::getBooleanValue( info, "condNeedUpdate", false); conditionMemberToUpdate = arangodb::basics::VelocyPackHelper::getNumericValue<size_t>( info, "condMemberToUpdate", 0); VPackSlice read = info.get("handle"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires handle to be an object"); } read = read.get("id"); if (!read.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each handle requires id to be a string"); } std::string idxId = read.copyString(); auto trx = query->trx(); for (auto const& it : VPackArrayIterator(shards)) { if (!it.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Shards have to be a list of strings"); } idxHandles.emplace_back(trx->getIndexByIdentifier(it.copyString(), idxId)); } read = info.get("expression"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires expression to be an object"); } expression = new aql::Expression(query->ast(), read); read = info.get("condition"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires condition to be an object"); } indexCondition = new aql::AstNode(query->ast(), read); }
ShortestPathNode::ShortestPathNode(ExecutionPlan* plan, arangodb::velocypack::Slice const& base) : ExecutionNode(plan, base), _vocbase(plan->getAst()->query()->vocbase()), _vertexOutVariable(nullptr), _edgeOutVariable(nullptr), _inStartVariable(nullptr), _inTargetVariable(nullptr), _graphObj(nullptr) { // Directions VPackSlice dirList = base.get("directions"); for (auto const& it : VPackArrayIterator(dirList)) { uint64_t dir = arangodb::basics::VelocyPackHelper::stringUInt64(it); TRI_edge_direction_e d; switch (dir) { case 0: d = TRI_EDGE_ANY; break; case 1: d = TRI_EDGE_IN; break; case 2: d = TRI_EDGE_OUT; break; default: THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "Invalid direction value"); break; } _directions.emplace_back(d); } // Start Vertex if (base.hasKey("startInVariable")) { _inStartVariable = varFromVPack(plan->getAst(), base, "startInVariable"); } else { VPackSlice v = base.get("startVertexId"); if (!v.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "start vertex must be a string"); } _startVertexId = v.copyString(); if (_startVertexId.empty()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "start vertex mustn't be empty"); } } // Target Vertex if (base.hasKey("targetInVariable")) { _inTargetVariable = varFromVPack(plan->getAst(), base, "targetInVariable"); } else { VPackSlice v = base.get("targetVertexId"); if (!v.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "target vertex must be a string"); } _targetVertexId = v.copyString(); if (_targetVertexId.empty()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "target vertex mustn't be empty"); } } std::string graphName; if (base.hasKey("graph") && (base.get("graph").isString())) { graphName = base.get("graph").copyString(); if (base.hasKey("graphDefinition")) { _graphObj = plan->getAst()->query()->lookupGraphByName(graphName); if (_graphObj == nullptr) { THROW_ARANGO_EXCEPTION(TRI_ERROR_GRAPH_NOT_FOUND); } auto eColls = _graphObj->edgeCollections(); for (auto const& n : eColls) { _edgeColls.push_back(n); } } else { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "missing graphDefinition."); } } else { _graphInfo.add(base.get("graph")); if (!_graphInfo.slice().isArray()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "graph has to be an array."); } // List of edge collection names for (auto const& it : VPackArrayIterator(_graphInfo.slice())) { if (!it.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_BAD_JSON_PLAN, "graph has to be an array of strings."); } _edgeColls.emplace_back(it.copyString()); } if (_edgeColls.empty()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_QUERY_BAD_JSON_PLAN, "graph has to be a non empty array of strings."); } } // Out variables if (base.hasKey("vertexOutVariable")) { _vertexOutVariable = varFromVPack(plan->getAst(), base, "vertexOutVariable"); } if (base.hasKey("edgeOutVariable")) { _edgeOutVariable = varFromVPack(plan->getAst(), base, "edgeOutVariable"); } // Flags if (base.hasKey("shortestPathFlags")) { _options = ShortestPathOptions(base); } }
static void JS_JsonCursor(v8::FunctionCallbackInfo<v8::Value> const& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } if (args.Length() != 1) { TRI_V8_THROW_EXCEPTION_USAGE("JSON_CURSOR(<id>)"); } std::string const id = TRI_ObjectToString(args[0]); auto cursorId = static_cast<arangodb::CursorId>( arangodb::basics::StringUtils::uint64(id)); // find the cursor auto cursors = vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); bool busy; auto cursor = cursors->find(cursorId, Cursor::CURSOR_VPACK, busy); if (cursor == nullptr) { if (busy) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_CURSOR_BUSY); } TRI_V8_THROW_EXCEPTION(TRI_ERROR_CURSOR_NOT_FOUND); } try { auto result = v8::Object::New(isolate); // build documents auto docs = v8::Array::New(isolate); size_t const n = cursor->batchSize(); for (size_t i = 0; i < n; ++i) { if (!cursor->hasNext()) { break; } auto row = cursor->next(); if (row.isNone()) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } docs->Set(static_cast<uint32_t>(i), TRI_VPackToV8(isolate, row)); } result->ForceSet(TRI_V8_ASCII_STRING("result"), docs); bool hasCount = cursor->hasCount(); size_t count = cursor->count(); bool hasNext = cursor->hasNext(); VPackSlice const extra = cursor->extra(); result->ForceSet(TRI_V8_ASCII_STRING("hasMore"), v8::Boolean::New(isolate, hasNext)); if (hasNext) { result->ForceSet(TRI_V8_ASCII_STRING("id"), V8TickId(isolate, cursor->id())); } if (hasCount) { result->ForceSet(TRI_V8_ASCII_STRING("count"), v8::Number::New(isolate, static_cast<double>(count))); } if (!extra.isNone()) { result->ForceSet(TRI_V8_ASCII_STRING("extra"), TRI_VPackToV8(isolate, extra)); } cursors->release(cursor); TRI_V8_RETURN(result); } catch (...) { cursors->release(cursor); TRI_V8_THROW_EXCEPTION_MEMORY(); } TRI_V8_TRY_CATCH_END }
arangodb::traverser::TraverserOptions::TraverserOptions( arangodb::aql::Query* query, VPackSlice info, VPackSlice collections) : _trx(query->trx()), _baseVertexExpression(nullptr), _tmpVar(nullptr), _ctx(new aql::FixedVarExpressionContext()), _isCoordinator(arangodb::ServerState::instance()->isCoordinator()), minDepth(1), maxDepth(1), useBreadthFirst(false), uniqueVertices(UniquenessLevel::NONE), uniqueEdges(UniquenessLevel::PATH) { // NOTE collections is an array of arrays of strings VPackSlice read = info.get("minDepth"); if (!read.isInteger()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a minDepth"); } minDepth = read.getNumber<uint64_t>(); read = info.get("maxDepth"); if (!read.isInteger()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a maxDepth"); } maxDepth = read.getNumber<uint64_t>(); read = info.get("bfs"); if (!read.isBoolean()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a bfs"); } useBreadthFirst = read.getBool(); read = info.get("tmpVar"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a tmpVar"); } _tmpVar = query->ast()->variables()->createVariable(read); read = info.get("uniqueVertices"); if (!read.isInteger()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a uniqueVertices"); } size_t i = read.getNumber<size_t>(); switch (i) { case 0: uniqueVertices = UniquenessLevel::NONE; break; case 1: uniqueVertices = UniquenessLevel::PATH; break; case 2: uniqueVertices = UniquenessLevel::GLOBAL; break; default: THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a uniqueVertices"); } read = info.get("uniqueEdges"); if (!read.isInteger()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a uniqueEdges"); } i = read.getNumber<size_t>(); switch (i) { case 0: uniqueEdges = UniquenessLevel::NONE; break; case 1: uniqueEdges = UniquenessLevel::PATH; break; case 2: uniqueEdges = UniquenessLevel::GLOBAL; break; default: THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a uniqueEdges"); } read = info.get("baseLookupInfos"); if (!read.isArray()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "The options require a baseLookupInfos"); } size_t length = read.length(); TRI_ASSERT(read.length() == collections.length()); _baseLookupInfos.reserve(length); for (size_t j = 0; j < length; ++j) { _baseLookupInfos.emplace_back(query, read.at(j), collections.at(j)); } read = info.get("depthLookupInfo"); if (!read.isNone()) { if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "The options require depthLookupInfo to be an object"); } _depthLookupInfo.reserve(read.length()); for (auto const& depth : VPackObjectIterator(read)) { size_t d = basics::StringUtils::uint64(depth.key.copyString()); auto it = _depthLookupInfo.emplace(d, std::vector<LookupInfo>()); TRI_ASSERT(it.second); VPackSlice list = depth.value; TRI_ASSERT(length == list.length()); it.first->second.reserve(length); for (size_t j = 0; j < length; ++j) { it.first->second.emplace_back(query, list.at(j), collections.at(j)); } } } read = info.get("vertexExpressions"); if (!read.isNone()) { if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "The options require vertexExpressions to be an object"); } _vertexExpressions.reserve(read.length()); for (auto const& info : VPackObjectIterator(read)) { size_t d = basics::StringUtils::uint64(info.key.copyString()); #ifdef ARANGODB_ENABLE_MAINAINER_MODE auto it = _vertexExpressions.emplace( d, new aql::Expression(query->ast(), info.value)); TRI_ASSERT(it.second); #else _vertexExpressions.emplace( d, new aql::Expression(query->ast(), info.value)); #endif } } read = info.get("baseVertexExpression"); if (!read.isNone()) { if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "The options require vertexExpressions to be an object"); } _baseVertexExpression = new aql::Expression(query->ast(), read); } // Check for illegal option combination: TRI_ASSERT(uniqueEdges != arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL); TRI_ASSERT( uniqueVertices != arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL || useBreadthFirst); }
void VelocyPackCursor::dump(arangodb::basics::StringBuffer& buffer) { buffer.appendText("\"result\":["); size_t const n = batchSize(); // reserve 48 bytes per result document by default, but only // if the specified batch size does not get out of hand // otherwise specifying a very high batch size would make the allocation fail // in every case, even if there were much less documents in the collection size_t num = n; if (num == 0) { num = 1; } else if (num >= 10000) { num = 10000; } int res = buffer.reserve(num * 48); if (res != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION(res); } arangodb::basics::VelocyPackDumper dumper(&buffer, _result.context->getVPackOptions()); try { for (size_t i = 0; i < n; ++i) { if (!hasNext()) { break; } if (i > 0) { buffer.appendChar(','); } auto row = next(); if (row.isNone()) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } dumper.dumpValue(row); } } catch (arangodb::basics::Exception const& ex) { THROW_ARANGO_EXCEPTION_MESSAGE(ex.code(), ex.what()); } catch (std::exception const& ex) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what()); } catch (...) { THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } buffer.appendText("],\"hasMore\":"); buffer.appendText(hasNext() ? "true" : "false"); if (hasNext()) { // only return cursor id if there are more documents buffer.appendText(",\"id\":\""); buffer.appendInteger(id()); buffer.appendText("\""); } if (hasCount()) { buffer.appendText(",\"count\":"); buffer.appendInteger(static_cast<uint64_t>(count())); } VPackSlice const extraSlice = extra(); if (extraSlice.isObject()) { buffer.appendText(",\"extra\":"); dumper.dumpValue(extraSlice); } buffer.appendText(",\"cached\":"); buffer.appendText(_cached ? "true" : "false"); if (!hasNext()) { // mark the cursor as deleted this->deleted(); } }
void RestWalHandler::properties() { auto l = arangodb::wal::LogfileManager::instance(); if (_request->requestType() == rest::RequestType::PUT) { std::shared_ptr<VPackBuilder> parsedRequest; VPackSlice slice; try { slice = _request->payload(); } catch (...) { generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid body value. expecting object"); return; } if (!slice.isObject()) { generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid body value. expecting object"); } if (slice.hasKey("allowOversizeEntries")) { bool value = slice.get("allowOversizeEntries").getBoolean(); l->allowOversizeEntries(value); } if (slice.hasKey("logfileSize")) { uint32_t value = slice.get("logfileSize").getNumericValue<uint32_t>(); l->filesize(value); } if (slice.hasKey("historicLogfiles")) { uint32_t value = slice.get("historicLogfiles").getNumericValue<uint32_t>(); l->historicLogfiles(value); } if (slice.hasKey("reserveLogfiles")) { uint32_t value = slice.get("reserveLogfiles").getNumericValue<uint32_t>(); l->reserveLogfiles(value); } if (slice.hasKey("throttleWait")) { uint64_t value = slice.get("throttleWait").getNumericValue<uint64_t>(); l->maxThrottleWait(value); } if (slice.hasKey("throttleWhenPending")) { uint64_t value = slice.get("throttleWhenPending").getNumericValue<uint64_t>(); l->throttleWhenPending(value); } } VPackBuilder builder; builder.openObject(); builder.add("allowOversizeEntries", VPackValue(l->allowOversizeEntries())); builder.add("logfileSize", VPackValue(l->filesize())); builder.add("historicLogfiles", VPackValue(l->historicLogfiles())); builder.add("reserveLogfiles", VPackValue(l->reserveLogfiles())); builder.add("syncInterval", VPackValue(l->syncInterval())); builder.add("throttleWait", VPackValue(l->maxThrottleWait())); builder.add("throttleWhenPending", VPackValue(l->throttleWhenPending())); builder.close(); generateResult(rest::ResponseCode::OK, builder.slice()); }
void RestWalHandler::flush() { std::shared_ptr<VPackBuilder> parsedRequest; VPackSlice slice; try { slice = _request->payload(); } catch (...) { generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid body value. expecting object"); return; } if (!slice.isObject() && !slice.isNone()) { generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid body value. expecting object"); } bool waitForSync = false; bool waitForCollector = false; if (slice.isObject()) { // got a request body VPackSlice value = slice.get("waitForSync"); if (value.isString()) { waitForSync = (value.copyString() == "true"); } else if (value.isBoolean()) { waitForSync = value.getBoolean(); } value = slice.get("waitForCollector"); if (value.isString()) { waitForCollector = (value.copyString() == "true"); } else if (value.isBoolean()) { waitForCollector = value.getBoolean(); } } else { // no request body bool found; { std::string const& v = _request->value("waitForSync", found); if (found) { waitForSync = (v == "1" || v == "true"); } } { std::string const& v = _request->value("waitForCollector", found); if (found) { waitForCollector = (v == "1" || v == "true"); } } } int res; if (ServerState::instance()->isCoordinator()) { res = flushWalOnAllDBServers(waitForSync, waitForCollector); } else { res = arangodb::wal::LogfileManager::instance()->flush( waitForSync, waitForCollector, false); } if (res != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION(res); } generateResult(rest::ResponseCode::OK, basics::VelocyPackHelper::EmptyObjectValue()); }
// Check all coordinators, guarded above doChecks std::vector<check_t> Supervision::checkCoordinators() { std::vector<check_t> ret; Node::Children const& machinesPlanned = _snapshot(planCoordinatorsPrefix).children(); Node::Children const serversRegistered = _snapshot(currentServersRegisteredPrefix).children(); std::string currentFoxxmaster; try { currentFoxxmaster = _snapshot(foxxmaster).getString(); } catch (...) { } std::string goodServerId; bool foxxmasterOk = false; std::vector<std::string> todelete; for (auto const& machine : _snapshot(healthPrefix).children()) { if (machine.first.substr(0, 2) == "Co") { todelete.push_back(machine.first); } } for (auto const& machine : machinesPlanned) { bool good = false; std::string lastHeartbeatTime, lastHeartbeatAcked, lastStatus, heartbeatTime, heartbeatStatus, serverID; serverID = machine.first; heartbeatTime = _snapshot(syncPrefix + serverID + "/time").toJson(); heartbeatStatus = _snapshot(syncPrefix + serverID + "/status").toJson(); todelete.erase(std::remove(todelete.begin(), todelete.end(), serverID), todelete.end()); try { // Existing lastHeartbeatTime = _snapshot(healthPrefix + serverID + "/LastHeartbeatSent").toJson(); lastStatus = _snapshot(healthPrefix + serverID + "/Status").toJson(); if (lastHeartbeatTime != heartbeatTime) { // Update good = true; } } catch (...) { // New server good = true; } query_t report = std::make_shared<Builder>(); report->openArray(); report->openArray(); report->openObject(); report->add(_agencyPrefix + healthPrefix + serverID, VPackValue(VPackValueType::Object)); report->add("LastHeartbeatSent", VPackValue(heartbeatTime)); report->add("LastHeartbeatStatus", VPackValue(heartbeatStatus)); report->add("Role", VPackValue("Coordinator")); auto endpoint = serversRegistered.find(serverID); if (endpoint != serversRegistered.end()) { endpoint = endpoint->second->children().find("endpoint"); if (endpoint != endpoint->second->children().end()) { if (endpoint->second->children().size() == 0) { VPackSlice epString = endpoint->second->slice(); if (epString.isString()) { report->add("Endpoint", epString); } } } } if (good) { if (goodServerId.empty()) { goodServerId = serverID; } if (serverID == currentFoxxmaster) { foxxmasterOk = true; } report->add( "LastHeartbeatAcked", VPackValue(timepointToString(std::chrono::system_clock::now()))); report->add("Status", VPackValue(Supervision::HEALTH_STATUS_GOOD)); } else { std::chrono::seconds t{0}; t = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now() - stringToTimepoint(lastHeartbeatAcked)); if (t.count() > _gracePeriod) { // Failure if (lastStatus == Supervision::HEALTH_STATUS_BAD) { report->add("Status", VPackValue(Supervision::HEALTH_STATUS_FAILED)); } } else { report->add("Status", VPackValue(Supervision::HEALTH_STATUS_BAD)); } } report->close(); report->close(); report->close(); report->close(); if (!this->isStopping()) { _agent->write(report); } } if (!todelete.empty()) { query_t del = std::make_shared<Builder>(); del->openArray(); del->openArray(); del->openObject(); for (auto const& srv : todelete) { del->add(_agencyPrefix + healthPrefix + srv, VPackValue(VPackValueType::Object)); del->add("op", VPackValue("delete")); del->close(); } del->close(); del->close(); del->close(); _agent->write(del); } if (!foxxmasterOk && !goodServerId.empty()) { query_t create = std::make_shared<Builder>(); create->openArray(); create->openArray(); create->openObject(); create->add(_agencyPrefix + foxxmaster, VPackValue(goodServerId)); create->close(); create->close(); create->close(); _agent->write(create); } return ret; }
/// @brief local helper to throw an exception if a HTTP request went wrong static bool throwExceptionAfterBadSyncRequest(ClusterCommResult* res, bool isShutdown) { DEBUG_BEGIN_BLOCK(); if (res->status == CL_COMM_TIMEOUT || res->status == CL_COMM_BACKEND_UNAVAILABLE) { THROW_ARANGO_EXCEPTION_MESSAGE(res->getErrorCode(), res->stringifyErrorMessage()); } if (res->status == CL_COMM_ERROR) { std::string errorMessage; TRI_ASSERT(nullptr != res->result); arangodb::basics::StringBuffer const& responseBodyBuf(res->result->getBody()); // extract error number and message from response int errorNum = TRI_ERROR_NO_ERROR; std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson( responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); if (!slice.hasKey("error") || slice.get("error").getBoolean()) { errorNum = TRI_ERROR_INTERNAL; errorMessage = std::string("Error message received from shard '") + std::string(res->shardID) + std::string("' on cluster node '") + std::string(res->serverID) + std::string("': "); } if (slice.isObject()) { VPackSlice v = slice.get("errorNum"); if (v.isNumber()) { if (v.getNumericValue<int>() != TRI_ERROR_NO_ERROR) { /* if we've got an error num, error has to be true. */ TRI_ASSERT(errorNum == TRI_ERROR_INTERNAL); errorNum = v.getNumericValue<int>(); } } v = slice.get("errorMessage"); if (v.isString()) { errorMessage += v.copyString(); } else { errorMessage += std::string("(no valid error in response)"); } } else { errorMessage += std::string("(no valid response)"); } if (isShutdown && errorNum == TRI_ERROR_QUERY_NOT_FOUND) { // this error may happen on shutdown and is thus tolerated // pass the info to the caller who can opt to ignore this error return true; } // In this case a proper HTTP error was reported by the DBserver, if (errorNum > 0 && !errorMessage.empty()) { THROW_ARANGO_EXCEPTION_MESSAGE(errorNum, errorMessage); } // default error THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_AQL_COMMUNICATION); } return false; // cppcheck-suppress style DEBUG_END_BLOCK(); }
static void raceForClusterBootstrap() { AgencyComm agency; auto ci = ClusterInfo::instance(); while (true) { AgencyCommResult result = agency.getValues("Bootstrap"); if (!result.successful()) { // Error in communication, note that value not found is not an error LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: no agency communication"; sleep(1); continue; } VPackSlice value = result.slice()[0].get( std::vector<std::string>({agency.prefix(), "Bootstrap"})); if (value.isString()) { // key was found and is a string if (value.copyString().find("done") != std::string::npos) { // all done, let's get out of here: LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: bootstrap already done"; return; } LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: somebody else does the bootstrap"; sleep(1); continue; } // No value set, we try to do the bootstrap ourselves: VPackBuilder b; b.add(VPackValue(arangodb::ServerState::instance()->getId())); result = agency.casValue("Bootstrap", b.slice(), false, 300, 15); if (!result.successful()) { LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: lost race, somebody else will bootstrap"; // Cannot get foot into the door, try again later: sleep(1); continue; } // OK, we handle things now, let's see whether a DBserver is there: auto dbservers = ci->getCurrentDBServers(); if (dbservers.size() == 0) { LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: no DBservers, waiting"; agency.removeValues("Bootstrap", false); sleep(1); continue; } LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: race won, we do the bootstrap"; auto vocbase = DatabaseFeature::DATABASE->systemDatabase(); V8DealerFeature::DEALER->loadJavascriptFiles(vocbase, "server/bootstrap/cluster-bootstrap.js", 0); LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: bootstrap done"; b.clear(); b.add(VPackValue(arangodb::ServerState::instance()->getId() + ": done")); result = agency.setValue("Bootstrap", b.slice(), 0); if (result.successful()) { return; } LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: could not indicate success"; sleep(1); } }
/// @brief shutdown, will be called exactly once for the whole query int RemoteBlock::shutdown(int errorCode) { DEBUG_BEGIN_BLOCK(); if (!_isResponsibleForInitializeCursor) { // do nothing... return TRI_ERROR_NO_ERROR; } // For every call we simply forward via HTTP std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/shutdown/", std::string("{\"code\":" + std::to_string(errorCode) + "}")); if (throwExceptionAfterBadSyncRequest(res.get(), true)) { // artificially ignore error in case query was not found during shutdown return TRI_ERROR_NO_ERROR; } StringBuffer const& responseBodyBuf(res->result->getBody()); std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson(responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); // read "warnings" attribute if present and add it to our query if (slice.isObject()) { VPackSlice warnings = slice.get("warnings"); if (warnings.isArray()) { auto query = _engine->getQuery(); for (auto const& it : VPackArrayIterator(warnings)) { if (it.isObject()) { VPackSlice code = it.get("code"); VPackSlice message = it.get("message"); if (code.isNumber() && message.isString()) { query->registerWarning(code.getNumericValue<int>(), message.copyString().c_str()); } } } } } if (slice.hasKey("code")) { return slice.get("code").getNumericValue<int>(); } return TRI_ERROR_INTERNAL; // cppcheck-suppress style DEBUG_END_BLOCK(); }
/// Get persisted information and run election process void Constituent::run() { // single instance _id = _agent->config().id(); TRI_ASSERT(_vocbase != nullptr); auto bindVars = std::make_shared<VPackBuilder>(); bindVars->openObject(); bindVars->close(); // Most recent vote std::string const aql("FOR l IN election SORT l._key DESC LIMIT 1 RETURN l"); arangodb::aql::Query query(false, _vocbase, aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.execute(_queryRegistry); if (queryResult.code != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION_MESSAGE(queryResult.code, queryResult.details); } VPackSlice result = queryResult.result->slice(); if (result.isArray()) { for (auto const& i : VPackArrayIterator(result)) { auto ii = i.resolveExternals(); try { MUTEX_LOCKER(locker, _castLock); _term = ii.get("term").getUInt(); _votedFor = ii.get("voted_for").copyString(); } catch (std::exception const&) { LOG_TOPIC(ERR, Logger::AGENCY) << "Persisted election entries corrupt! Defaulting term,vote (0,0)"; } } } std::vector<std::string> act = _agent->config().active(); while ( !this->isStopping() // Obvious && (!_agent->ready() || find(act.begin(), act.end(), _id) == act.end())) { // Active agent CONDITION_LOCKER(guardv, _cv); _cv.wait(50000); act = _agent->config().active(); } if (size() == 1) { _leaderID = _agent->config().id(); LOG_TOPIC(DEBUG, Logger::AGENCY) << "Set _leaderID to " << _leaderID << " in term " << _term; } else { while (!this->isStopping()) { if (_role == FOLLOWER) { static double const M = 1.0e6; int64_t a = static_cast<int64_t>(M * _agent->config().minPing()); int64_t b = static_cast<int64_t>(M * _agent->config().maxPing()); int64_t randTimeout = RandomGenerator::interval(a, b); int64_t randWait = randTimeout; { MUTEX_LOCKER(guard, _castLock); // in the beginning, pure random if (_lastHeartbeatSeen > 0.0) { double now = TRI_microtime(); randWait -= static_cast<int64_t>(M * (now - _lastHeartbeatSeen)); } } LOG_TOPIC(DEBUG, Logger::AGENCY) << "Random timeout: " << randTimeout << ", wait: " << randWait; if (randWait > 0.0) { CONDITION_LOCKER(guardv, _cv); _cv.wait(randWait); } bool isTimeout = false; { MUTEX_LOCKER(guard, _castLock); if (_lastHeartbeatSeen <= 0.0) { LOG_TOPIC(TRACE, Logger::AGENCY) << "no heartbeat seen"; isTimeout = true; } else { double diff = TRI_microtime() - _lastHeartbeatSeen; LOG_TOPIC(TRACE, Logger::AGENCY) << "last heartbeat: " << diff << "sec ago"; isTimeout = (static_cast<int32_t>(M * diff) > randTimeout); } } if (isTimeout) { LOG_TOPIC(TRACE, Logger::AGENCY) << "timeout, calling an election"; candidate(); } } else if (_role == CANDIDATE) { callElection(); // Run for office } else { int32_t left = static_cast<int32_t>(100000.0 * _agent->config().minPing()); long randTimeout = static_cast<long>(left); { CONDITION_LOCKER(guardv, _cv); _cv.wait(randTimeout); } } } } }
/// @brief sendToClient: for each row of the incoming AqlItemBlock use the /// attributes <shardKeys> of the Aql value <val> to determine to which shard /// the row should be sent and return its clientId size_t DistributeBlock::sendToClient(AqlItemBlock* cur) { DEBUG_BEGIN_BLOCK(); // inspect cur in row _pos and check to which shard it should be sent . . AqlValue val = cur->getValueReference(_pos, _regId); VPackSlice input = val.slice(); // will throw when wrong type bool usedAlternativeRegId = false; if (input.isNull() && _alternativeRegId != ExecutionNode::MaxRegisterId) { // value is set, but null // check if there is a second input register available (UPSERT makes use of // two input registers, // one for the search document, the other for the insert document) val = cur->getValueReference(_pos, _alternativeRegId); input = val.slice(); // will throw when wrong type usedAlternativeRegId = true; } VPackSlice value = input; VPackBuilder builder; VPackBuilder builder2; bool hasCreatedKeyAttribute = false; if (input.isString() && static_cast<DistributeNode const*>(_exeNode) ->_allowKeyConversionToObject) { builder.openObject(); builder.add(StaticStrings::KeyString, input); builder.close(); // clear the previous value cur->destroyValue(_pos, _regId); // overwrite with new value cur->setValue(_pos, _regId, AqlValue(builder)); value = builder.slice(); hasCreatedKeyAttribute = true; } else if (!input.isObject()) { THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID); } TRI_ASSERT(value.isObject()); if (static_cast<DistributeNode const*>(_exeNode)->_createKeys) { // we are responsible for creating keys if none present if (_usesDefaultSharding) { // the collection is sharded by _key... if (!hasCreatedKeyAttribute && !value.hasKey(StaticStrings::KeyString)) { // there is no _key attribute present, so we are responsible for // creating one VPackBuilder temp; temp.openObject(); temp.add(StaticStrings::KeyString, VPackValue(createKey(value))); temp.close(); builder2 = VPackCollection::merge(input, temp.slice(), true); // clear the previous value and overwrite with new value: if (usedAlternativeRegId) { cur->destroyValue(_pos, _alternativeRegId); cur->setValue(_pos, _alternativeRegId, AqlValue(builder2)); } else { cur->destroyValue(_pos, _regId); cur->setValue(_pos, _regId, AqlValue(builder2)); } value = builder2.slice(); } } else { // the collection is not sharded by _key if (hasCreatedKeyAttribute || value.hasKey(StaticStrings::KeyString)) { // a _key was given, but user is not allowed to specify _key if (usedAlternativeRegId || !_allowSpecifiedKeys) { THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_MUST_NOT_SPECIFY_KEY); } } else { VPackBuilder temp; temp.openObject(); temp.add(StaticStrings::KeyString, VPackValue(createKey(value))); temp.close(); builder2 = VPackCollection::merge(input, temp.slice(), true); // clear the previous value and overwrite with new value: if (usedAlternativeRegId) { cur->destroyValue(_pos, _alternativeRegId); cur->setValue(_pos, _alternativeRegId, AqlValue(builder2.slice())); } else { cur->destroyValue(_pos, _regId); cur->setValue(_pos, _regId, AqlValue(builder2.slice())); } value = builder2.slice(); } } } std::string shardId; bool usesDefaultShardingAttributes; auto clusterInfo = arangodb::ClusterInfo::instance(); auto collInfo = _collection->getCollection(); int res = clusterInfo->getResponsibleShard(collInfo.get(), value, true, shardId, usesDefaultShardingAttributes); // std::cout << "SHARDID: " << shardId << "\n"; if (res != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION(res); } TRI_ASSERT(!shardId.empty()); return getClientId(shardId); // cppcheck-suppress style DEBUG_END_BLOCK(); }
bool TraverserExpression::matchesCheck(arangodb::Transaction* trx, VPackSlice const& element) const { TRI_ASSERT(trx != nullptr); VPackSlice base = arangodb::basics::VelocyPackHelper::EmptyObjectValue(); VPackSlice value = element.resolveExternal(); // initialize compare value to Null VPackSlice result = arangodb::basics::VelocyPackHelper::NullValue(); // perform recursive check. this may modify value if (recursiveCheck(varAccess, value, base)) { result = value; } // hack for _id attribute TransactionBuilderLeaser builder(trx); if (result.isCustom() && base.isObject()) { builder->add(VPackValue(trx->extractIdString(base))); result = builder->slice(); } TRI_ASSERT(compareTo != nullptr); VPackOptions* options = trx->transactionContext()->getVPackOptions(); switch (comparisonType) { case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), false, options) == 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_NE: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), false, options) != 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_LT: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), true, options) < 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_LE: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), true, options) <= 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_GE: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), true, options) >= 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_GT: return arangodb::basics::VelocyPackHelper::compare(result, compareTo->slice(), true, options) > 0; case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN: { // In means any of the elements in compareTo is identical VPackSlice compareArray = compareTo->slice(); for (auto const& cmp : VPackArrayIterator(compareArray)) { if (arangodb::basics::VelocyPackHelper::compare(result, cmp, false, options) == 0) { // One is identical return true; } } // If we get here non is identical return false; } case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_NIN: { // NIN means none of the elements in compareTo is identical VPackSlice compareArray = compareTo->slice(); for (auto const& cmp : VPackArrayIterator(compareArray)) { if (arangodb::basics::VelocyPackHelper::compare(result, cmp, false, options) == 0) { // One is identical return false; } } // If we get here non is identical return true; } default: TRI_ASSERT(false); } return false; }
size_t VelocyPackHelper::VPackHash::operator()(VPackSlice const& slice) const { return static_cast<size_t>(slice.normalizedHash()); };
/// Get persisted information and run election process void Constituent::run() { TRI_ASSERT(_vocbase != nullptr); auto bindVars = std::make_shared<VPackBuilder>(); bindVars->openObject(); bindVars->close(); // Most recent vote std::string const aql("FOR l IN election SORT l._key DESC LIMIT 1 RETURN l"); arangodb::aql::Query query(false, _vocbase, aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.execute(_queryRegistry); if (queryResult.code != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION_MESSAGE(queryResult.code, queryResult.details); } VPackSlice result = queryResult.result->slice(); if (result.isArray()) { for (auto const& i : VPackArrayIterator(result)) { try { _term = i.get("term").getUInt(); _votedFor = static_cast<decltype(_votedFor)>(i.get("voted_for").getUInt()); } catch (std::exception const&) { LOG_TOPIC(ERR, Logger::AGENCY) << "Persisted election entries corrupt! Defaulting term,vote (0,0)"; } } } // Always start off as follower while (!this->isStopping() && size() > 1) { if (_role == FOLLOWER) { bool cast = false; { MUTEX_LOCKER(guard, _castLock); _cast = false; // New round set not cast vote } int32_t left = 1000000*config().minPing, right = 1000000*config().maxPing; long rand_wait = static_cast<long>(RandomGenerator::interval(left, right)); { CONDITION_LOCKER(guardv, _cv); _cv.wait(rand_wait); } { MUTEX_LOCKER(guard, _castLock); cast = _cast; } if (!cast) { candidate(); // Next round, we are running } } else { callElection(); // Run for office } } }
size_t VelocyPackHelper::VPackStringHash::operator()(VPackSlice const& slice) const noexcept { return static_cast<size_t>(slice.hashString()); };
void SingleServerTraverser::addEdgeToVelocyPack(VPackSlice edge, VPackBuilder& result) { result.addExternal(edge.begin()); }
int VelocyPackHelper::compare(VPackSlice lhs, VPackSlice rhs, bool useUTF8, VPackOptions const* options, VPackSlice const* lhsBase, VPackSlice const* rhsBase) { { // will resolve externals... int lWeight = TypeWeight(lhs); int rWeight = TypeWeight(rhs); if (lWeight < rWeight) { return -1; } if (lWeight > rWeight) { return 1; } TRI_ASSERT(lWeight == rWeight); } lhs = lhs.resolveExternal(); // follow externals rhs = rhs.resolveExternal(); // follow externals // lhs and rhs have equal weights if (lhs.isNone() || rhs.isNone()) { // either lhs or rhs is none. we cannot be sure here that both are // nones. // there can also exist the situation that lhs is a none and rhs is a // null value // (or vice versa). Anyway, the compare value is the same for both, return 0; } auto lhsType = lhs.type(); switch (lhsType) { case VPackValueType::Illegal: case VPackValueType::MinKey: case VPackValueType::MaxKey: case VPackValueType::None: case VPackValueType::Null: return 0; case VPackValueType::Bool: { bool left = lhs.getBoolean(); bool right = rhs.getBoolean(); if (left == right) { return 0; } if (!left && right) { return -1; } return 1; } case VPackValueType::Double: case VPackValueType::Int: case VPackValueType::UInt: case VPackValueType::SmallInt: { return compareNumberValues(lhsType, lhs, rhs); } case VPackValueType::Custom: case VPackValueType::String: { std::string lhsString; VPackValueLength nl; char const* left; if (lhs.isCustom()) { if (lhsBase == nullptr || options == nullptr || options->customTypeHandler == nullptr) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "Could not extract custom attribute."); } lhsString.assign(options->customTypeHandler->toString(lhs, options, *lhsBase)); left = lhsString.c_str(); nl = lhsString.size(); } else { left = lhs.getString(nl); } TRI_ASSERT(left != nullptr); std::string rhsString; VPackValueLength nr; char const* right; if (rhs.isCustom()) { if (rhsBase == nullptr || options == nullptr || options->customTypeHandler == nullptr) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "Could not extract custom attribute."); } rhsString.assign(options->customTypeHandler->toString(rhs, options, *rhsBase)); right = rhsString.c_str(); nr = rhsString.size(); } else { right = rhs.getString(nr); } TRI_ASSERT(right != nullptr); int res; if (useUTF8) { res = TRI_compare_utf8(left, static_cast<size_t>(nl), right, static_cast<size_t>(nr)); } else { size_t len = static_cast<size_t>(nl < nr ? nl : nr); res = memcmp(left, right, len); } if (res < 0) { return -1; } if (res > 0) { return 1; } // res == 0 if (nl == nr) { return 0; } // res == 0, but different string lengths return nl < nr ? -1 : 1; } case VPackValueType::Array: { VPackValueLength const nl = lhs.length(); VPackValueLength const nr = rhs.length(); VPackValueLength const n = (std::max)(nr, nl); for (VPackValueLength i = 0; i < n; ++i) { VPackSlice lhsValue; if (i < nl) { lhsValue = lhs.at(i).resolveExternal(); } VPackSlice rhsValue; if (i < nr) { rhsValue = rhs.at(i).resolveExternal(); } int result = compare(lhsValue, rhsValue, useUTF8, options, &lhs, &rhs); if (result != 0) { return result; } } return 0; } case VPackValueType::Object: { std::set<std::string, AttributeSorterUTF8> keys; VPackCollection::keys(lhs, keys); VPackCollection::keys(rhs, keys); for (auto const& key : keys) { VPackSlice lhsValue = lhs.get(key).resolveExternal(); if (lhsValue.isNone()) { // not present => null lhsValue = VPackSlice::nullSlice(); } VPackSlice rhsValue = rhs.get(key).resolveExternal(); if (rhsValue.isNone()) { // not present => null rhsValue = VPackSlice::nullSlice(); } int result = compare(lhsValue, rhsValue, useUTF8, options, &lhs, &rhs); if (result != 0) { return result; } } return 0; } default: // Contains all other ValueTypes of VelocyPack. // They are not used in ArangoDB so this cannot occur TRI_ASSERT(false); return 0; } }
int RestoreFeature::processInputDirectory(std::string& errorMsg) { // create a lookup table for collections std::map<std::string, bool> restrictList; for (size_t i = 0; i < _collections.size(); ++i) { restrictList.insert(std::pair<std::string, bool>(_collections[i], true)); } try { std::vector<std::string> const files = FileUtils::listFiles(_inputDirectory); std::string const suffix = std::string(".structure.json"); std::vector<std::shared_ptr<VPackBuilder>> collectionBuilders; std::vector<VPackSlice> collections; // Step 1 determine all collections to process { // loop over all files in InputDirectory, and look for all structure.json // files for (std::string const& file : files) { size_t const nameLength = file.size(); if (nameLength <= suffix.size() || file.substr(file.size() - suffix.size()) != suffix) { // some other file continue; } // found a structure.json file std::string name = file.substr(0, file.size() - suffix.size()); if (!_includeSystemCollections && name[0] == '_') { continue; } std::string const fqn = _inputDirectory + TRI_DIR_SEPARATOR_STR + file; std::shared_ptr<VPackBuilder> fileContentBuilder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(fqn); VPackSlice const fileContent = fileContentBuilder->slice(); if (!fileContent.isObject()) { errorMsg = "could not read collection structure file '" + fqn + "'"; return TRI_ERROR_INTERNAL; } VPackSlice const parameters = fileContent.get("parameters"); VPackSlice const indexes = fileContent.get("indexes"); if (!parameters.isObject() || !indexes.isArray()) { errorMsg = "could not read collection structure file '" + fqn + "'"; return TRI_ERROR_INTERNAL; } std::string const cname = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name", ""); bool overwriteName = false; if (cname != name && name != (cname + "_" + arangodb::rest::SslInterface::sslMD5(cname))) { // file has a different name than found in structure file if (_importStructure) { // we cannot go on if there is a mismatch errorMsg = "collection name mismatch in collection structure file '" + fqn + "' (offending value: '" + cname + "')"; return TRI_ERROR_INTERNAL; } else { // we can patch the name in our array and go on std::cout << "ignoring collection name mismatch in collection " "structure file '" + fqn + "' (offending value: '" + cname + "')" << std::endl; overwriteName = true; } } if (!restrictList.empty() && restrictList.find(cname) == restrictList.end()) { // collection name not in list continue; } if (overwriteName) { // TODO MAX // Situation: // Ich habe ein Json-Object von Datei (teile des Inhalts im Zweifel // unbekannt) // Es gibt ein Sub-Json-Object "parameters" mit einem Attribute "name" // der gesetzt ist. // Ich muss nur diesen namen überschreiben, der Rest soll identisch // bleiben. } else { collectionBuilders.emplace_back(fileContentBuilder); collections.emplace_back(fileContent); } } } std::sort(collections.begin(), collections.end(), SortCollections); StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE); // step2: run the actual import for (VPackSlice const& collection : collections) { VPackSlice const parameters = collection.get("parameters"); VPackSlice const indexes = collection.get("indexes"); std::string const cname = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name", ""); int type = arangodb::basics::VelocyPackHelper::getNumericValue<int>( parameters, "type", 2); std::string const collectionType(type == 2 ? "document" : "edge"); if (_importStructure) { // re-create collection if (_progress) { if (_overwrite) { std::cout << "# Re-creating " << collectionType << " collection '" << cname << "'..." << std::endl; } else { std::cout << "# Creating " << collectionType << " collection '" << cname << "'..." << std::endl; } } int res = sendRestoreCollection(collection, cname, errorMsg); if (res != TRI_ERROR_NO_ERROR) { if (_force) { std::cerr << errorMsg << std::endl; continue; } return TRI_ERROR_INTERNAL; } } _stats._totalCollections++; if (_importData) { // import data. check if we have a datafile std::string datafile = _inputDirectory + TRI_DIR_SEPARATOR_STR + cname + "_" + arangodb::rest::SslInterface::sslMD5(cname) + ".data.json"; if (!TRI_ExistsFile(datafile.c_str())) { datafile = _inputDirectory + TRI_DIR_SEPARATOR_STR + cname + ".data.json"; } if (TRI_ExistsFile(datafile.c_str())) { // found a datafile if (_progress) { std::cout << "# Loading data into " << collectionType << " collection '" << cname << "'..." << std::endl; } int fd = TRI_OPEN(datafile.c_str(), O_RDONLY | TRI_O_CLOEXEC); if (fd < 0) { errorMsg = "cannot open collection data file '" + datafile + "'"; return TRI_ERROR_INTERNAL; } buffer.clear(); while (true) { if (buffer.reserve(16384) != TRI_ERROR_NO_ERROR) { TRI_CLOSE(fd); errorMsg = "out of memory"; return TRI_ERROR_OUT_OF_MEMORY; } ssize_t numRead = TRI_READ(fd, buffer.end(), 16384); if (numRead < 0) { // error while reading int res = TRI_errno(); TRI_CLOSE(fd); errorMsg = std::string(TRI_errno_string(res)); return res; } // read something buffer.increaseLength(numRead); _stats._totalRead += (uint64_t)numRead; if (buffer.length() < _chunkSize && numRead > 0) { // still continue reading continue; } // do we have a buffer? if (buffer.length() > 0) { // look for the last \n in the buffer char* found = (char*)memrchr((const void*)buffer.begin(), '\n', buffer.length()); size_t length; if (found == nullptr) { // no \n found... if (numRead == 0) { // we're at the end. send the complete buffer anyway length = buffer.length(); } else { // read more continue; } } else { // found a \n somewhere length = found - buffer.begin(); } TRI_ASSERT(length > 0); _stats._totalBatches++; int res = sendRestoreData(cname, buffer.begin(), length, errorMsg); if (res != TRI_ERROR_NO_ERROR) { TRI_CLOSE(fd); if (errorMsg.empty()) { errorMsg = std::string(TRI_errno_string(res)); } else { errorMsg = std::string(TRI_errno_string(res)) + ": " + errorMsg; } if (_force) { std::cerr << errorMsg << std::endl; continue; } return res; } buffer.erase_front(length); } if (numRead == 0) { // EOF break; } } TRI_CLOSE(fd); } } if (_importStructure) { // re-create indexes if (indexes.length() > 0) { // we actually have indexes if (_progress) { std::cout << "# Creating indexes for collection '" << cname << "'..." << std::endl; } int res = sendRestoreIndexes(collection, errorMsg); if (res != TRI_ERROR_NO_ERROR) { if (_force) { std::cerr << errorMsg << std::endl; continue; } return TRI_ERROR_INTERNAL; } } } } } catch (...) { errorMsg = "out of memory"; return TRI_ERROR_OUT_OF_MEMORY; } return TRI_ERROR_NO_ERROR; }
// Check all DB servers, guarded above doChecks std::vector<check_t> Supervision::checkDBServers() { std::vector<check_t> ret; Node::Children const& machinesPlanned = _snapshot(planDBServersPrefix).children(); Node::Children const serversRegistered = _snapshot(currentServersRegisteredPrefix).children(); std::vector<std::string> todelete; for (auto const& machine : _snapshot(healthPrefix).children()) { if (machine.first.substr(0, 2) == "DB") { todelete.push_back(machine.first); } } for (auto const& machine : machinesPlanned) { bool good = false; std::string lastHeartbeatTime, lastHeartbeatAcked, lastStatus, heartbeatTime, heartbeatStatus, serverID; serverID = machine.first; heartbeatTime = _snapshot(syncPrefix + serverID + "/time").toJson(); heartbeatStatus = _snapshot(syncPrefix + serverID + "/status").toJson(); todelete.erase(std::remove(todelete.begin(), todelete.end(), serverID), todelete.end()); try { // Existing lastHeartbeatTime = _snapshot(healthPrefix + serverID + "/LastHeartbeatSent").toJson(); lastHeartbeatAcked = _snapshot(healthPrefix + serverID + "/LastHeartbeatAcked").toJson(); lastStatus = _snapshot(healthPrefix + serverID + "/Status").toJson(); if (lastHeartbeatTime != heartbeatTime) { // Update good = true; } } catch (...) { // New server good = true; } query_t report = std::make_shared<Builder>(); report->openArray(); report->openArray(); report->openObject(); report->add(_agencyPrefix + healthPrefix + serverID, VPackValue(VPackValueType::Object)); report->add("LastHeartbeatSent", VPackValue(heartbeatTime)); report->add("LastHeartbeatStatus", VPackValue(heartbeatStatus)); report->add("Role", VPackValue("DBServer")); auto endpoint = serversRegistered.find(serverID); if (endpoint != serversRegistered.end()) { endpoint = endpoint->second->children().find("endpoint"); if (endpoint != endpoint->second->children().end()) { if (endpoint->second->children().size() == 0) { VPackSlice epString = endpoint->second->slice(); if (epString.isString()) { report->add("Endpoint", epString); } } } } if (good) { report->add( "LastHeartbeatAcked", VPackValue(timepointToString(std::chrono::system_clock::now()))); report->add("Status", VPackValue(Supervision::HEALTH_STATUS_GOOD)); std::string failedServerPath = failedServersPrefix + "/" + serverID; if (_snapshot.exists(failedServerPath).size() == 3) { Builder del; del.openArray(); del.openObject(); del.add(_agencyPrefix + failedServerPath, VPackValue(VPackValueType::Object)); del.add("op", VPackValue("delete")); del.close(); del.close(); del.close(); transact(_agent, del); } } else { std::chrono::seconds t{0}; t = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now() - stringToTimepoint(lastHeartbeatAcked)); if (t.count() > _gracePeriod) { // Failure if (lastStatus == "BAD") { report->add("Status", VPackValue("FAILED")); FailedServer fsj(_snapshot, _agent, std::to_string(_jobId++), "supervision", _agencyPrefix, serverID); } } else { report->add("Status", VPackValue("BAD")); } } report->close(); report->close(); report->close(); report->close(); if (!this->isStopping()) { _agent->write(report); } } if (!todelete.empty()) { query_t del = std::make_shared<Builder>(); del->openArray(); del->openArray(); del->openObject(); for (auto const& srv : todelete) { del->add(_agencyPrefix + healthPrefix + srv, VPackValue(VPackValueType::Object)); del->add("op", VPackValue("delete")); del->close(); } del->close(); del->close(); del->close(); _agent->write(del); } return ret; }
static AuthEntry CreateAuthEntry(VPackSlice const& slice) { if (slice.isNone() || !slice.isObject()) { return AuthEntry(); } // extract "user" attribute VPackSlice const userSlice = slice.get("user"); if (!userSlice.isString()) { LOG(DEBUG) << "cannot extract username"; return AuthEntry(); } VPackSlice const authDataSlice = slice.get("authData"); if (!authDataSlice.isObject()) { LOG(DEBUG) << "cannot extract authData"; return AuthEntry(); } VPackSlice const simpleSlice = authDataSlice.get("simple"); if (!simpleSlice.isObject()) { LOG(DEBUG) << "cannot extract simple"; return AuthEntry(); } VPackSlice const methodSlice = simpleSlice.get("method"); VPackSlice const saltSlice = simpleSlice.get("salt"); VPackSlice const hashSlice = simpleSlice.get("hash"); if (!methodSlice.isString() || !saltSlice.isString() || !hashSlice.isString()) { LOG(DEBUG) << "cannot extract password internals"; return AuthEntry(); } // extract "active" attribute bool active; VPackSlice const activeSlice = authDataSlice.get("active"); if (!activeSlice.isBoolean()) { LOG(DEBUG) << "cannot extract active flag"; return AuthEntry(); } active = activeSlice.getBool(); // extract "changePassword" attribute bool mustChange = VelocyPackHelper::getBooleanValue(authDataSlice, "changePassword", false); // extract "databases" attribute VPackSlice const databasesSlice = slice.get("databases"); std::unordered_map<std::string, AuthLevel> databases; AuthLevel allDatabases = AuthLevel::NONE; if (databasesSlice.isObject()) { for (auto const& obj : VPackObjectIterator(databasesSlice)) { std::string const key = obj.key.copyString(); ValueLength length; char const* value = obj.value.getString(length); if (TRI_CaseEqualString(value, "rw", 2)) { if (key == "*") { allDatabases = AuthLevel::RW; } else { databases.emplace(key, AuthLevel::RW); } } else if (TRI_CaseEqualString(value, "ro", 2)) { if (key == "*") { allDatabases = AuthLevel::RO; } else { databases.emplace(key, AuthLevel::RO); } } } } // build authentication entry return AuthEntry(userSlice.copyString(), methodSlice.copyString(), saltSlice.copyString(), hashSlice.copyString(), databases, allDatabases, active, mustChange); }
size_t State::removeConflicts(query_t const& transactions) { // Under MUTEX in Agent VPackSlice slices = transactions->slice(); TRI_ASSERT(slices.isArray()); size_t ndups = 0; if (slices.length() > 0) { auto bindVars = std::make_shared<VPackBuilder>(); bindVars->openObject(); bindVars->close(); try { MUTEX_LOCKER(logLock, _logLock); auto idx = slices[0].get("index").getUInt(); auto pos = idx - _cur; if (pos < _log.size()) { for (auto const& slice : VPackArrayIterator(slices)) { auto trm = slice.get("term").getUInt(); idx = slice.get("index").getUInt(); pos = idx - _cur; if (pos < _log.size()) { if (idx == _log.at(pos).index && trm != _log.at(pos).term) { LOG_TOPIC(DEBUG, Logger::AGENCY) << "Removing " << _log.size() - pos << " entries from log starting with " << idx << "==" << _log.at(pos).index << " and " << trm << "=" << _log.at(pos).term; // persisted logs std::string const aql(std::string("FOR l IN log FILTER l._key >= '") + stringify(idx) + "' REMOVE l IN log"); arangodb::aql::Query query( false, _vocbase, aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.execute(_queryRegistry); if (queryResult.code != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION_MESSAGE(queryResult.code, queryResult.details); } // volatile logs _log.erase(_log.begin() + pos, _log.end()); break; } else { ++ndups; } } } } } catch (std::exception const& e) { LOG_TOPIC(DEBUG, Logger::AGENCY) << e.what() << " " << __FILE__ << __LINE__; } } return ndups; }