diff --git a/arangod/Agency/Agent.cpp b/arangod/Agency/Agent.cpp index 4c08fe0606..8e81a098bb 100644 --- a/arangod/Agency/Agent.cpp +++ b/arangod/Agency/Agent.cpp @@ -682,7 +682,7 @@ inquire_ret_t Agent::inquire(query_t const& query) { } } - ret.result = builder; + ret = inquire_ret_t(true, id(), builder); return ret; } diff --git a/arangod/Agency/RestAgencyHandler.cpp b/arangod/Agency/RestAgencyHandler.cpp index bae129c919..adbf2b61fe 100644 --- a/arangod/Agency/RestAgencyHandler.cpp +++ b/arangod/Agency/RestAgencyHandler.cpp @@ -461,14 +461,20 @@ inline RestStatus RestAgencyHandler::handleInquire() { std::this_thread::sleep_for(duration_t(100)); } - inquire_ret_t ret = _agent->inquire(query); + inquire_ret_t ret; + try { + ret = _agent->inquire(query); + } catch (std::exception const& e) { + generateError( + rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, e.what()); + } if (ret.accepted) { // I am leading - generateResult(rest::ResponseCode::OK, ret.result->slice()); - + generateResult(rest::ResponseCode::OK, ret.result->slice()); + } else { // Redirect to leader - + if (_agent->leaderID() == NO_LEADER) { Builder body; body.openObject(); @@ -613,6 +619,8 @@ RestStatus RestAgencyHandler::execute() { return handleWrite(); } else if (suffixes[0] == "read") { return handleRead(); + } else if (suffixes[0] == "inquire") { + return handleInquire(); } else if (suffixes[0] == "transact") { return handleTransact(); } else if (suffixes[0] == "config") { diff --git a/arangod/Agency/State.cpp b/arangod/Agency/State.cpp index d20cabef94..0a7c16e4cc 100644 --- a/arangod/Agency/State.cpp +++ b/arangod/Agency/State.cpp @@ -135,7 +135,7 @@ std::vector State::log( std::shared_ptr> buf = std::make_shared>(); buf->append((char const*)i[0].begin(), i[0].byteSize()); - LOG(WARN) << i.length(); + if (i.length()==3) { clientId = i[2].copyString(); } @@ -145,8 +145,8 @@ std::vector State::log( _clientIdLookupTable.emplace( std::pair(clientId, idx[j])); persist(idx[j], term, i[0], clientId); // log to disk - ++j; } + ++j; } return idx; @@ -845,25 +845,34 @@ std::vector State::inquire(query_t const& query) const { MUTEX_LOCKER(mutexLocker, _logLock); // Cannot be read lock (Compaction) if (!query->slice().isArray()) { - LOG_TOPIC(WARN, Logger::AGENCY) - << "Inquire interface handles []. We got " << query->toJson(); + THROW_ARANGO_EXCEPTION_MESSAGE( + 210002, + std::string("Inquiry handles a list of string clientIds: [] ") + + ". We got " + query->toJson()); return result; } - + + size_t pos = 0; for (auto const& i : VPackArrayIterator(query->slice())) { if (!i.isString()) { - LOG_TOPIC(WARN, Logger::AGENCY) - << "ClientIds must be strings. We got " << i.toJson(); - continue; + THROW_ARANGO_EXCEPTION_MESSAGE( + 210002, std::string("ClientIds must be strings. On position ") + + std::to_string(pos) + " we got " + i.toJson()); } - + auto ret = _clientIdLookupTable.equal_range(i.copyString()); for (auto it = ret.first; it != ret.second; ++it) { + if (it->second < _log[0].index) { + continue; + } result.push_back(_log.at(it->second-_cur)); } + + pos++; + } - + return result; } diff --git a/js/client/tests/agency/agency-test.js b/js/client/tests/agency/agency-test.js index fe624c4a97..8911e2e503 100644 --- a/js/client/tests/agency/agency-test.js +++ b/js/client/tests/agency/agency-test.js @@ -294,7 +294,70 @@ function agencyTestSuite () { //////////////////////////////////////////////////////////////////////////////// testClientIds : function () { - writeAndCheck([[{"a":12},{},guid()]]); + var res; + + var id0 = guid(); + var query0 = {"a":12}; + var pre0 = {}; + writeAndCheck([[query0, pre0, id0]]); + res = accessAgency("inquire",[id0]).bodyParsed; + assertEqual(res.length, 1); + assertEqual(res[0].query, query0); + + var query1 = {"a":13}; + var pre1 = {"a":12} + writeAndCheck([[query1, pre1, id0]]); + res = accessAgency("inquire",[id0]).bodyParsed; + assertEqual(res.length, 2); + assertEqual(res[0].query, query0); + assertEqual(res[1].query, query1); + + var query2 = {"a":13}; + var pre2 = {"a":12} + var id2 = guid(); + res = accessAgency("write",[[query1, pre1, id2]]); + assertEqual(res.statusCode,412); + res = accessAgency("inquire",[id2]).bodyParsed; + assertEqual(res.length, 0); + + var id3 = guid(); + res = accessAgency("write",[[query0, pre0, id3],[query1, pre1, id3]]); + assertEqual(res.statusCode,200); + res = accessAgency("inquire",[id3]).bodyParsed; + assertEqual(res.length, 2); + assertEqual(res[0].query, query0); + assertEqual(res[1].query, query1); + + var id4 = guid(); + res = accessAgency("write",[[query0, pre0, id4], + [query1, pre1, id4], + [query2, pre2, id4]]); + assertEqual(res.statusCode,412); + res = accessAgency("inquire",[id4]).bodyParsed; + assertEqual(res.length, 2); + assertEqual(res[0].query, query0); + assertEqual(res[1].query, query1); + + var id5 = guid(); + res = accessAgency("write",[[query0, pre0, id5], + [query2, pre2, id5], + [query1, pre1, id5]]); + assertEqual(res.statusCode,412); + res = accessAgency("inquire",[id5]).bodyParsed; + assertEqual(res.length, 2); + assertEqual(res[0].query, query0); + assertEqual(res[1].query, query1); + + var id6 = guid(); + res = accessAgency("write",[[query2, pre2, id6], + [query0, pre0, id6], + [query1, pre1, id6]]); + assertEqual(res.statusCode,412); + res = accessAgency("inquire",[id6]).bodyParsed; + assertEqual(res.length, 2); + assertEqual(res[0].query, query0); + assertEqual(res[1].query, query1); + }, diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index d386b0e2c6..5a8f32e570 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -278,6 +278,7 @@ "ERROR_AGENCY_INFORM_MUST_CONTAIN_ID" : { "code" : 20013, "message" : "Inform message must contain string parameter 'id'" }, "ERROR_AGENCY_INFORM_MUST_CONTAIN_ACTIVE" : { "code" : 20014, "message" : "Inform message must contain array 'active'" }, "ERROR_AGENCY_INFORM_MUST_CONTAIN_POOL" : { "code" : 20015, "message" : "Inform message must contain object 'pool'" }, + "ERROR_AGENCY_INQUIRE_CLIENT_ID_MUST_BE_STRING" : { "code" : 20020, "message" : "Inquiry failed" }, "ERROR_DISPATCHER_IS_STOPPING" : { "code" : 21001, "message" : "dispatcher stopped" }, "ERROR_QUEUE_UNKNOWN" : { "code" : 21002, "message" : "named queue does not exist" }, "ERROR_QUEUE_FULL" : { "code" : 21003, "message" : "named queue is full" } diff --git a/lib/Basics/errors.dat b/lib/Basics/errors.dat index e609d4b2d3..8f25b67019 100755 --- a/lib/Basics/errors.dat +++ b/lib/Basics/errors.dat @@ -395,6 +395,7 @@ ERROR_AGENCY_INFORM_MUST_CONTAIN_TERM,20012,"Inform message must contain uint pa ERROR_AGENCY_INFORM_MUST_CONTAIN_ID,20013,"Inform message must contain string parameter 'id'","The inform message in the agency must contain a string parameter 'id'." ERROR_AGENCY_INFORM_MUST_CONTAIN_ACTIVE,20014,"Inform message must contain array 'active'","The inform message in the agency must contain an array 'active'." ERROR_AGENCY_INFORM_MUST_CONTAIN_POOL,20015,"Inform message must contain object 'pool'","The inform message in the agency must contain an object 'pool'." +ERROR_AGENCY_INQUIRE_CLIENT_ID_MUST_BE_STRING,20020,"Inquiry failed","Inquiry by clientId failed" ################################################################################ ## Dispatcher errors diff --git a/lib/Basics/voc-errors.cpp b/lib/Basics/voc-errors.cpp index 1755a3fe51..c2d8bf93f0 100644 --- a/lib/Basics/voc-errors.cpp +++ b/lib/Basics/voc-errors.cpp @@ -274,6 +274,7 @@ void TRI_InitializeErrorMessages () { REG_ERROR(ERROR_AGENCY_INFORM_MUST_CONTAIN_ID, "Inform message must contain string parameter 'id'"); REG_ERROR(ERROR_AGENCY_INFORM_MUST_CONTAIN_ACTIVE, "Inform message must contain array 'active'"); REG_ERROR(ERROR_AGENCY_INFORM_MUST_CONTAIN_POOL, "Inform message must contain object 'pool'"); + REG_ERROR(ERROR_AGENCY_INQUIRE_CLIENT_ID_MUST_BE_STRING, "Inquiry failed"); REG_ERROR(ERROR_DISPATCHER_IS_STOPPING, "dispatcher stopped"); REG_ERROR(ERROR_QUEUE_UNKNOWN, "named queue does not exist"); REG_ERROR(ERROR_QUEUE_FULL, "named queue is full"); diff --git a/lib/Basics/voc-errors.h b/lib/Basics/voc-errors.h index 40887c37f2..ee721aaac3 100644 --- a/lib/Basics/voc-errors.h +++ b/lib/Basics/voc-errors.h @@ -652,6 +652,8 @@ /// The inform message in the agency must contain an array 'active'. /// - 20015: @LIT{Inform message must contain object 'pool'} /// The inform message in the agency must contain an object 'pool'. +/// - 20020: @LIT{Inquiry failed} +/// Inquiry by clientId failed /// - 21001: @LIT{dispatcher stopped} /// Will be returned if a shutdown is in progress. /// - 21002: @LIT{named queue does not exist} @@ -3449,6 +3451,16 @@ void TRI_InitializeErrorMessages (); #define TRI_ERROR_AGENCY_INFORM_MUST_CONTAIN_POOL (20015) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 20020: ERROR_AGENCY_INQUIRE_CLIENT_ID_MUST_BE_STRING +/// +/// Inquiry failed +/// +/// Inquiry by clientId failed +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_AGENCY_INQUIRE_CLIENT_ID_MUST_BE_STRING (20020) + //////////////////////////////////////////////////////////////////////////////// /// @brief 21001: ERROR_DISPATCHER_IS_STOPPING ///