diff --git a/arangod/Agency/Agent.cpp b/arangod/Agency/Agent.cpp index d641bc4fc1..9166adab21 100644 --- a/arangod/Agency/Agent.cpp +++ b/arangod/Agency/Agent.cpp @@ -238,7 +238,7 @@ append_entries_t Agent::sendAppendEntriesRPC (id_t slave_id) { bool Agent::load () { LOG_TOPIC(INFO, Logger::AGENCY) << "Loading persistent state."; if (!_state.loadCollections()) { - LOG(FATAL) << "Failed to load persistent state on statup."; + LOG_TOPIC(WARN, Logger::AGENCY) << "Failed to load persistent state on statup."; } LOG_TOPIC(INFO, Logger::AGENCY) << "Reassembling spearhead and read stores."; @@ -332,5 +332,12 @@ log_t const& Agent::lastLog() const { return _state.lastLog(); } +Store const& Agent::spearhead () const { + return _spearhead; +} + +Store const& Agent::readDB () const { + return _read_db; +} }} diff --git a/arangod/Agency/Agent.h b/arangod/Agency/Agent.h index 7ee4af8bdc..26a2cead53 100644 --- a/arangod/Agency/Agent.h +++ b/arangod/Agency/Agent.h @@ -126,6 +126,12 @@ class Agent : public arangodb::Thread { /// @brief State machine State const& state() const; + /// @brief Get read store + Store const& readDB() const; + + /// @brief Get spearhead store + Store const& spearhead() const; + private: Constituent _constituent; /**< @brief Leader election delegate */ State _state; /**< @brief Log replica */ diff --git a/arangod/Agency/State.cpp b/arangod/Agency/State.cpp index 4303d43b81..a12afad905 100644 --- a/arangod/Agency/State.cpp +++ b/arangod/Agency/State.cpp @@ -217,12 +217,11 @@ bool State::createCollection(std::string const& name) { } bool State::loadCollections() { - loadCollection("log"); - return true; + return loadCollection("log"); } bool State::loadCollection(std::string const& name) { - if (checkCollections()) { + if (checkCollection(name)) { // Path std::string path("/_api/cursor"); @@ -255,10 +254,11 @@ bool State::loadCollection(std::string const& name) { } } } - return true; - } else { + LOG_TOPIC (INFO, Logger::AGENCY) << "Couldn't find persisted log"; + createCollections(); + return false; } } diff --git a/arangod/Agency/Store.cpp b/arangod/Agency/Store.cpp index 5a349958a9..a94b126a8d 100644 --- a/arangod/Agency/Store.cpp +++ b/arangod/Agency/Store.cpp @@ -30,6 +30,8 @@ #include +#include +#include #include using namespace arangodb::consensus; @@ -96,7 +98,6 @@ Node& Node::operator= (VPackSlice const& slice) { // Assign value (become leaf) Node& Node::operator= (Node const& node) { // Assign node _node_name = node._node_name; - _type = node._type; _value = node._value; _children = node._children; return *this; @@ -394,6 +395,16 @@ std::ostream& Node::print (std::ostream& o) const { } else { o << ((slice().type() == ValueType::None) ? "NONE" : slice().toJson()) << std::endl; } + if (_time_table.size()) { + for (auto const& i : _time_table) { + o << i.second.get() << std::endl; + } + } + if (_table_time.size()) { + for (auto const& i : _table_time) { + o << i.first.get() << std::endl; + } + } return o; } @@ -560,9 +571,8 @@ void Store::beginShutdown() { } void Store::clearTimeTable () { - size_t deleted = 0; +// std::vector> deleted; for (auto it = _time_table.cbegin(); it != _time_table.cend(); ++it) { - // Remove expired from front if (it->first < std::chrono::system_clock::now()) { query_t tmp = std::make_shared(); tmp->openArray(); tmp->openArray(); tmp->openObject(); @@ -570,18 +580,42 @@ void Store::clearTimeTable () { tmp->add("op",VPackValue("delete")); tmp->close(); tmp->close(); tmp->close(); tmp->close(); _agent->write(tmp); - it->second->remove(); - deleted++; -// _time_table.erase(it++); } else { break; } } - for (size_t i = 0; i < deleted; ++i) { + +/* for (size_t i = 0; i < deleted; ++i) { + try { _table_time.erase(_table_time.find(_time_table.cbegin()->second)); _time_table.erase(_time_table.cbegin()); + } catch (std::exception const& e) { + std::cout << e.what() << std::endl; + }*/ +} + + +void Store::dumpToBuilder (Builder& builder) const { + MUTEX_LOCKER(storeLocker, _storeLock); + toBuilder(builder); + { + VPackObjectBuilder guard(&builder); + for (auto const& i : _time_table) { + auto in_time_t = std::chrono::system_clock::to_time_t(i.first); + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + builder.add(ss.str(), VPackValue((size_t)i.second.get())); + } + } + { + VPackObjectBuilder guard(&builder); + for (auto const& i : _table_time) { + auto in_time_t = std::chrono::system_clock::to_time_t(i.second); + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + builder.add(std::to_string((size_t)i.first.get()), VPackValue(ss.str())); + } } - } bool Store::start () { @@ -601,6 +635,3 @@ void Store::run() { clearTimeTable(); } } - - - diff --git a/arangod/Agency/Store.h b/arangod/Agency/Store.h index 9f42bc71a6..08b992376f 100644 --- a/arangod/Agency/Store.h +++ b/arangod/Agency/Store.h @@ -158,7 +158,6 @@ protected: TableTime _table_time; Buffer _value; - NodeType _type; std::string _node_name; }; @@ -201,6 +200,9 @@ public: /// @brief Set name void name (std::string const& name); + /// @brief Dump everything to builder + void dumpToBuilder (Builder&) const; + private: /// @brief Read individual entry specified in slice into builder bool read (arangodb::velocypack::Slice const&, diff --git a/arangod/RestHandler/RestAgencyHandler.cpp b/arangod/RestHandler/RestAgencyHandler.cpp index d3f667987a..e6ec704acd 100644 --- a/arangod/RestHandler/RestAgencyHandler.cpp +++ b/arangod/RestHandler/RestAgencyHandler.cpp @@ -80,8 +80,26 @@ void RestAgencyHandler::redirectRequest(id_t leaderId) { _response->setHeaderNC(location, rendpoint); } -inline HttpHandler::status_t RestAgencyHandler::handleWrite() { - arangodb::velocypack::Options options; // TODO: User not wait. +HttpHandler::status_t RestAgencyHandler::handleStores () { + if (_request->requestType() == GeneralRequest::RequestType::GET) { + Builder body; + body.openObject(); + body.add("spearhead", VPackValue(VPackValueType::Array)); + _agent->spearhead().dumpToBuilder(body); + body.close(); + body.add("read_db", VPackValue(VPackValueType::Array)); + _agent->readDB().dumpToBuilder(body); + body.close(); + body.close(); + generateResult(body.slice()); + } else { + generateError(HttpResponse::BAD,400); + } + return HttpHandler::status_t(HANDLER_DONE); +} + +HttpHandler::status_t RestAgencyHandler::handleWrite () { + arangodb::velocypack::Options options; // TODO: User not wait. if (_request->requestType() == GeneralRequest::RequestType::POST) { query_t query; @@ -228,6 +246,8 @@ HttpHandler::status_t RestAgencyHandler::execute() { return reportMethodNotAllowed(); } return handleState(); + } else if (_request->suffix()[0] == "stores") { + return handleStores(); } else { return reportUnknownMethod(); } diff --git a/arangod/RestHandler/RestAgencyHandler.h b/arangod/RestHandler/RestAgencyHandler.h index 8329c0d8dc..9d736e8bb2 100644 --- a/arangod/RestHandler/RestAgencyHandler.h +++ b/arangod/RestHandler/RestAgencyHandler.h @@ -45,6 +45,7 @@ class RestAgencyHandler : public RestBaseHandler { status_t reportErrorEmptyRequest(); status_t reportTooManySuffices(); status_t reportUnknownMethod(); + status_t handleStores(); status_t handleRead(); status_t handleWrite(); status_t handleConfig(); diff --git a/js/client/tests/agency/agency-test.js b/js/client/tests/agency/agency-test.js index de9fd3eb37..ef55726a7e 100644 --- a/js/client/tests/agency/agency-test.js +++ b/js/client/tests/agency/agency-test.js @@ -193,6 +193,11 @@ function agencyTestSuite () { assertEqual(readAndCheck([["a/y"]]), [{"a":{"y":12}}]); sleep(1100); assertEqual(readAndCheck([["a/y"]]), [{}]); + writeAndCheck([[{"a/y":{"op":"set","new":12, "ttl": 1}}]]); + writeAndCheck([[{"a/y":{"op":"set","new":12}}]]); + assertEqual(readAndCheck([["a/y"]]), [{"a":{"y":12}}]); + sleep(1100); + assertEqual(readAndCheck([["a/y"]]), [{"a":{"y":12}}]); }, testOpNew : function () {