From a3a3954e6e894baf19f60b2455433df635c17e5b Mon Sep 17 00:00:00 2001 From: Igor Gaponenko Date: Thu, 23 Nov 2023 02:48:18 +0000 Subject: [PATCH] Temporary commit: Switched the control plane protocol --- src/replica/AddReplicaQservHttpMgtRequest.cc | 75 --- src/replica/AddReplicaQservHttpMgtRequest.h | 110 ---- src/replica/AddReplicaQservMgtRequest.cc | 67 +-- src/replica/AddReplicaQservMgtRequest.h | 37 +- src/replica/CMakeLists.txt | 9 - src/replica/GetConfigQservHttpMgtRequest.cc | 60 --- src/replica/GetConfigQservHttpMgtRequest.h | 86 ---- src/replica/GetConfigQservMgtRequest.cc | 78 +-- src/replica/GetConfigQservMgtRequest.h | 60 +-- src/replica/GetDbStatusQservHttpMgtRequest.cc | 60 --- src/replica/GetDbStatusQservHttpMgtRequest.h | 86 ---- src/replica/GetDbStatusQservMgtRequest.cc | 84 +--- src/replica/GetDbStatusQservMgtRequest.h | 59 +-- src/replica/GetReplicasQservHttpMgtRequest.cc | 105 ---- src/replica/GetReplicasQservHttpMgtRequest.h | 123 ----- src/replica/GetReplicasQservMgtRequest.cc | 97 +--- src/replica/GetReplicasQservMgtRequest.h | 40 +- src/replica/GetStatusQservHttpMgtRequest.cc | 63 --- src/replica/GetStatusQservHttpMgtRequest.h | 91 ---- src/replica/GetStatusQservMgtRequest.cc | 87 +--- src/replica/GetStatusQservMgtRequest.h | 63 +-- src/replica/QservHttpMgtRequest.cc | 356 ------------- src/replica/QservHttpMgtRequest.h | 391 -------------- src/replica/QservMgtRequest.cc | 274 ++++++---- src/replica/QservMgtRequest.h | 319 ++++++------ src/replica/QservMgtServices.cc | 475 +++--------------- src/replica/QservMgtServices.h | 171 +++---- .../RemoveReplicaQservHttpMgtRequest.cc | 82 --- .../RemoveReplicaQservHttpMgtRequest.h | 115 ----- src/replica/RemoveReplicaQservMgtRequest.cc | 68 +-- src/replica/RemoveReplicaQservMgtRequest.h | 38 +- src/replica/SetReplicasQservHttpMgtRequest.cc | 122 ----- src/replica/SetReplicasQservHttpMgtRequest.h | 129 ----- src/replica/SetReplicasQservMgtRequest.cc | 100 ++-- src/replica/SetReplicasQservMgtRequest.h | 58 ++- src/replica/TestEchoQservHttpMgtRequest.cc | 83 --- src/replica/TestEchoQservHttpMgtRequest.h | 114 ----- src/replica/TestEchoQservMgtRequest.cc | 74 +-- src/replica/TestEchoQservMgtRequest.h | 57 +-- 39 files changed, 735 insertions(+), 3831 deletions(-) delete mode 100644 src/replica/AddReplicaQservHttpMgtRequest.cc delete mode 100644 src/replica/AddReplicaQservHttpMgtRequest.h delete mode 100644 src/replica/GetConfigQservHttpMgtRequest.cc delete mode 100644 src/replica/GetConfigQservHttpMgtRequest.h delete mode 100644 src/replica/GetDbStatusQservHttpMgtRequest.cc delete mode 100644 src/replica/GetDbStatusQservHttpMgtRequest.h delete mode 100644 src/replica/GetReplicasQservHttpMgtRequest.cc delete mode 100644 src/replica/GetReplicasQservHttpMgtRequest.h delete mode 100644 src/replica/GetStatusQservHttpMgtRequest.cc delete mode 100644 src/replica/GetStatusQservHttpMgtRequest.h delete mode 100644 src/replica/QservHttpMgtRequest.cc delete mode 100644 src/replica/QservHttpMgtRequest.h delete mode 100644 src/replica/RemoveReplicaQservHttpMgtRequest.cc delete mode 100644 src/replica/RemoveReplicaQservHttpMgtRequest.h delete mode 100644 src/replica/SetReplicasQservHttpMgtRequest.cc delete mode 100644 src/replica/SetReplicasQservHttpMgtRequest.h delete mode 100644 src/replica/TestEchoQservHttpMgtRequest.cc delete mode 100644 src/replica/TestEchoQservHttpMgtRequest.h diff --git a/src/replica/AddReplicaQservHttpMgtRequest.cc b/src/replica/AddReplicaQservHttpMgtRequest.cc deleted file mode 100644 index 6201d1a44d..0000000000 --- a/src/replica/AddReplicaQservHttpMgtRequest.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/AddReplicaQservHttpMgtRequest.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.AddReplicaQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -AddReplicaQservHttpMgtRequest::Ptr AddReplicaQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, - vector const& databases, AddReplicaQservHttpMgtRequest::CallbackType const& onFinish) { - return AddReplicaQservHttpMgtRequest::Ptr( - new AddReplicaQservHttpMgtRequest(serviceProvider, worker, chunk, databases, onFinish)); -} - -AddReplicaQservHttpMgtRequest::AddReplicaQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, - vector const& databases, AddReplicaQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_ADD_REPLICA", worker), - _chunk(chunk), - _databases(databases), - _onFinish(onFinish) {} - -list> AddReplicaQservHttpMgtRequest::extendedPersistentState() const { - list> result; - result.emplace_back("chunk", to_string(chunk())); - for (auto&& database : databases()) { - result.emplace_back("database", database); - } - return result; -} - -void AddReplicaQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const method = "POST"; - string const target = "/replica"; - json const data = json::object({{"chunk", _chunk}, {"databases", _databases}}); - createHttpReq(lock, method, target, data); -} - -void AddReplicaQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/AddReplicaQservHttpMgtRequest.h b/src/replica/AddReplicaQservHttpMgtRequest.h deleted file mode 100644 index 9e3293639f..0000000000 --- a/src/replica/AddReplicaQservHttpMgtRequest.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_ADDREPLICAQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_ADDREPLICAQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include -#include - -// Third party headers -#include "nlohmann/json.hpp" - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations - -namespace lsst::qserv::replica { - -/** - * Class AddReplicaQservHttpMgtRequest implements a request notifying Qserv workers - * on new chunks added to the database. - */ -class AddReplicaQservHttpMgtRequest : public QservHttpMgtRequest { -public: - typedef std::shared_ptr Ptr; - - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; - - AddReplicaQservHttpMgtRequest() = delete; - AddReplicaQservHttpMgtRequest(AddReplicaQservHttpMgtRequest const&) = delete; - AddReplicaQservHttpMgtRequest& operator=(AddReplicaQservHttpMgtRequest const&) = delete; - - virtual ~AddReplicaQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param chunk The chunk number. - * @param databases The names of databases. - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static Ptr create(std::shared_ptr const& serviceProvider, std::string const& worker, - unsigned int chunk, std::vector const& databases, - CallbackType const& onFinish = nullptr); - - /// @return the chunk number - unsigned int chunk() const { return _chunk; } - - /// @return names of databases - std::vector const& databases() const { return _databases; } - - /// @see QservHttpMgtRequest::extendedPersistentState() - virtual std::list> extendedPersistentState() const final; - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::notify - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see AddReplicaQservHttpMgtRequest::create() - AddReplicaQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, unsigned int chunk, - std::vector const& databases, CallbackType const& onFinish); - - // Input parameters - - unsigned int const _chunk; - std::vector const _databases; - CallbackType _onFinish; ///< The callback is reset when the request finishes. -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_ADDREPLICAQSERVHTTPMGTREQUEST_H diff --git a/src/replica/AddReplicaQservMgtRequest.cc b/src/replica/AddReplicaQservMgtRequest.cc index e85d9264e5..24edcf1566 100644 --- a/src/replica/AddReplicaQservMgtRequest.cc +++ b/src/replica/AddReplicaQservMgtRequest.cc @@ -22,19 +22,10 @@ // Class header #include "replica/AddReplicaQservMgtRequest.h" -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" - // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; namespace { @@ -46,21 +37,20 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.AddReplicaQservMgtRequest"); namespace lsst::qserv::replica { AddReplicaQservMgtRequest::Ptr AddReplicaQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, unsigned int chunk, + shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, vector const& databases, AddReplicaQservMgtRequest::CallbackType const& onFinish) { return AddReplicaQservMgtRequest::Ptr( new AddReplicaQservMgtRequest(serviceProvider, worker, chunk, databases, onFinish)); } -AddReplicaQservMgtRequest::AddReplicaQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, +AddReplicaQservMgtRequest::AddReplicaQservMgtRequest(shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, vector const& databases, AddReplicaQservMgtRequest::CallbackType const& onFinish) : QservMgtRequest(serviceProvider, "QSERV_ADD_REPLICA", worker), _chunk(chunk), _databases(databases), - _onFinish(onFinish), - _qservRequest(nullptr) {} + _onFinish(onFinish) {} list> AddReplicaQservMgtRequest::extendedPersistentState() const { list> result; @@ -71,52 +61,15 @@ list> AddReplicaQservMgtRequest::extendedPersistentState() return result; } -void AddReplicaQservMgtRequest::startImpl(replica::Lock const& lock) { - auto const request = shared_from_base(); - - _qservRequest = xrdreq::AddChunkGroupQservRequest::create( - chunk(), databases(), [request](proto::WorkerCommandStatus::Code code, string const& error) { - if (request->state() == State::FINISHED) return; - replica::Lock lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - break; - case proto::WorkerCommandStatus::INVALID: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD, error); - break; - case proto::WorkerCommandStatus::IN_USE: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_CHUNK_IN_USE, error); - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error("AddReplicaQservMgtRequest::" + string(__func__) + - " unhandled request completion code: " + - proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void AddReplicaQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +void AddReplicaQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const method = "POST"; + string const target = "/replica"; + json const data = json::object({{"chunk", _chunk}, {"databases", _databases}}); + createHttpReq(lock, method, target, data); } void AddReplicaQservMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - + LOGS(_log, LOG_LVL_TRACE, context() << __func__); notifyDefaultImpl(lock, _onFinish); } diff --git a/src/replica/AddReplicaQservMgtRequest.h b/src/replica/AddReplicaQservMgtRequest.h index ba1c3b5509..7672d8d5a9 100644 --- a/src/replica/AddReplicaQservMgtRequest.h +++ b/src/replica/AddReplicaQservMgtRequest.h @@ -22,14 +22,21 @@ #define LSST_QSERV_REPLICA_ADDREPLICAQSERVMGTREQUEST_H // System headers +#include #include #include #include +#include + +// Third party headers +#include "nlohmann/json.hpp" // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/ChunkGroupQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations @@ -50,7 +57,7 @@ class AddReplicaQservMgtRequest : public QservMgtRequest { AddReplicaQservMgtRequest(AddReplicaQservMgtRequest const&) = delete; AddReplicaQservMgtRequest& operator=(AddReplicaQservMgtRequest const&) = delete; - ~AddReplicaQservMgtRequest() final = default; + virtual ~AddReplicaQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -65,7 +72,7 @@ class AddReplicaQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, + static Ptr create(std::shared_ptr const& serviceProvider, std::string const& worker, unsigned int chunk, std::vector const& databases, CallbackType const& onFinish = nullptr); @@ -76,32 +83,26 @@ class AddReplicaQservMgtRequest : public QservMgtRequest { std::vector const& databases() const { return _databases; } /// @see QservMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const final; + virtual std::list> extendedPersistentState() const final; protected: - /// @see QservMgtRequest::startImpl - void startImpl(replica::Lock const& lock) final; - - /// @see QservMgtRequest::finishImpl - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl + virtual void createHttpReqImpl(replica::Lock const& lock) final; /// @see QservMgtRequest::notify - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see AddReplicaQservMgtRequest::create() - AddReplicaQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - unsigned int chunk, std::vector const& databases, - CallbackType const& onFinish); + AddReplicaQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, unsigned int chunk, + std::vector const& databases, CallbackType const& onFinish); // Input parameters unsigned int const _chunk; std::vector const _databases; - CallbackType _onFinish; /// @note is reset when the request finishes - - /// A request to the remote services - xrdreq::AddChunkGroupQservRequest::Ptr _qservRequest; + CallbackType _onFinish; ///< The callback is reset when the request finishes. }; } // namespace lsst::qserv::replica diff --git a/src/replica/CMakeLists.txt b/src/replica/CMakeLists.txt index 10b1b1bdff..991dc20150 100644 --- a/src/replica/CMakeLists.txt +++ b/src/replica/CMakeLists.txt @@ -11,7 +11,6 @@ target_sources(replica PRIVATE ${REPLICA_PB_HDRS} AbortTransactionApp.cc AbortTransactionJob.cc - AddReplicaQservHttpMgtRequest.cc AddReplicaQservMgtRequest.cc AdminApp.cc Application.cc @@ -74,13 +73,9 @@ target_sources(replica PRIVATE FindRequest.cc FixUpApp.cc FixUpJob.cc - GetReplicasQservHttpMgtRequest.cc GetReplicasQservMgtRequest.cc - GetDbStatusQservHttpMgtRequest.cc GetDbStatusQservMgtRequest.cc - GetConfigQservHttpMgtRequest.cc GetConfigQservMgtRequest.cc - GetStatusQservHttpMgtRequest.cc GetStatusQservMgtRequest.cc HealthMonitorTask.cc HttpAsyncReqApp.cc @@ -135,7 +130,6 @@ target_sources(replica PRIVATE PurgeJob.cc QhttpTestApp.cc QservGetReplicasJob.cc - QservHttpMgtRequest.cc QservMgtRequest.cc QservMgtServices.cc QservStatusJob.cc @@ -149,7 +143,6 @@ target_sources(replica PRIVATE RegistryHttpSvc.cc RegistryHttpSvcMod.cc RegistryWorkers.cc - RemoveReplicaQservHttpMgtRequest.cc RemoveReplicaQservMgtRequest.cc ReplicaInfo.cc ReplicateApp.cc @@ -163,7 +156,6 @@ target_sources(replica PRIVATE ServiceManagementRequest.cc ServiceManagementRequestBase.cc ServiceProvider.cc - SetReplicasQservHttpMgtRequest.cc SetReplicasQservMgtRequest.cc SqlAlterTablesJob.cc SqlAlterTablesRequest.cc @@ -210,7 +202,6 @@ target_sources(replica PRIVATE SuccessRateGenerator.cc SyncApp.cc Task.cc - TestEchoQservHttpMgtRequest.cc TestEchoQservMgtRequest.cc TransactionContrib.cc TransactionsApp.cc diff --git a/src/replica/GetConfigQservHttpMgtRequest.cc b/src/replica/GetConfigQservHttpMgtRequest.cc deleted file mode 100644 index 6f4c5140ec..0000000000 --- a/src/replica/GetConfigQservHttpMgtRequest.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/GetConfigQservHttpMgtRequest.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetConfigQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -shared_ptr GetConfigQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, - GetConfigQservHttpMgtRequest::CallbackType const& onFinish) { - return shared_ptr( - new GetConfigQservHttpMgtRequest(serviceProvider, worker, onFinish)); -} - -GetConfigQservHttpMgtRequest::GetConfigQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, - GetConfigQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_GET_DATABASE_STATUS", worker), _onFinish(onFinish) {} - -void GetConfigQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const service = "/config"; - createHttpReq(lock, service); -} - -void GetConfigQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/GetConfigQservHttpMgtRequest.h b/src/replica/GetConfigQservHttpMgtRequest.h deleted file mode 100644 index b40902ae7a..0000000000 --- a/src/replica/GetConfigQservHttpMgtRequest.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_GETCONFIGQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_GETCONFIGQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class GetConfigQservHttpMgtRequest is a request for obtaining various info - * on the database service of the Qserv worker. - */ -class GetConfigQservHttpMgtRequest : public QservHttpMgtRequest { -public: - /// The function type for notifications on the completion of the request - typedef std::function const&)> CallbackType; - - GetConfigQservHttpMgtRequest() = delete; - GetConfigQservHttpMgtRequest(GetConfigQservHttpMgtRequest const&) = delete; - GetConfigQservHttpMgtRequest& operator=(GetConfigQservHttpMgtRequest const&) = delete; - - virtual ~GetConfigQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static std::shared_ptr create( - std::shared_ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish = nullptr); - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::notify() - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see GetConfigQservHttpMgtRequest::create() - GetConfigQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, CallbackType const& onFinish); - - // Input parameters - - CallbackType _onFinish; ///< This callback is reset after finishing the request. -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_GETCONFIGQSERVHTTPMGTREQUEST_H diff --git a/src/replica/GetConfigQservMgtRequest.cc b/src/replica/GetConfigQservMgtRequest.cc index 7f06ead055..1c43deb02e 100644 --- a/src/replica/GetConfigQservMgtRequest.cc +++ b/src/replica/GetConfigQservMgtRequest.cc @@ -22,23 +22,9 @@ // Class header #include "replica/GetConfigQservMgtRequest.h" -// System headers -#include -#include - -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/ServiceProvider.h" - // LSST headers #include "lsst/log/Log.h" -using namespace nlohmann; using namespace std; namespace { @@ -49,65 +35,21 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetConfigQservMgtRequest"); namespace lsst::qserv::replica { -GetConfigQservMgtRequest::Ptr GetConfigQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, +shared_ptr GetConfigQservMgtRequest::create( + shared_ptr const& serviceProvider, string const& worker, GetConfigQservMgtRequest::CallbackType const& onFinish) { - return GetConfigQservMgtRequest::Ptr(new GetConfigQservMgtRequest(serviceProvider, worker, onFinish)); + return shared_ptr( + new GetConfigQservMgtRequest(serviceProvider, worker, onFinish)); } -GetConfigQservMgtRequest::GetConfigQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, +GetConfigQservMgtRequest::GetConfigQservMgtRequest(shared_ptr const& serviceProvider, string const& worker, GetConfigQservMgtRequest::CallbackType const& onFinish) : QservMgtRequest(serviceProvider, "QSERV_GET_DATABASE_STATUS", worker), _onFinish(onFinish) {} -json const& GetConfigQservMgtRequest::info() const { - if (!((state() == State::FINISHED) && (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("GetConfigQservMgtRequest::" + string(__func__) + - " no info available in state: " + state2string(state(), extendedState())); - } - return _info; -} - -void GetConfigQservMgtRequest::startImpl(replica::Lock const& lock) { - auto const request = shared_from_base(); - _qservRequest = xrdreq::GetConfigQservRequest::create([request](proto::WorkerCommandStatus::Code code, - string const& error, string const& info) { - if (request->state() == State::FINISHED) return; - replica::Lock const lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - try { - request->_setInfo(lock, info); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - } catch (exception const& ex) { - string const msg = "failed to parse worker response, ex: " + string(ex.what()); - LOGS(_log, LOG_LVL_ERROR, "GetConfigQservMgtRequest::" << __func__ << " " << msg); - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD_RESPONSE, msg); - } - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error("GetConfigQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void GetConfigQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +void GetConfigQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const service = "/config"; + createHttpReq(lock, service); } void GetConfigQservMgtRequest::notify(replica::Lock const& lock) { @@ -115,8 +57,4 @@ void GetConfigQservMgtRequest::notify(replica::Lock const& lock) { notifyDefaultImpl(lock, _onFinish); } -void GetConfigQservMgtRequest::_setInfo(replica::Lock const& lock, string const& info) { - _info = json::parse(info); -} - } // namespace lsst::qserv::replica diff --git a/src/replica/GetConfigQservMgtRequest.h b/src/replica/GetConfigQservMgtRequest.h index fc75dd0383..6c3e0c445f 100644 --- a/src/replica/GetConfigQservMgtRequest.h +++ b/src/replica/GetConfigQservMgtRequest.h @@ -25,33 +25,30 @@ #include #include -// Third party headers -#include "nlohmann/json.hpp" - // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/GetConfigQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { /** - * Class GetConfigQservMgtRequest is a request for obtaining configuration - * parameters of the Qserv worker. + * Class GetConfigQservMgtRequest is a request for obtaining various info + * on the database service of the Qserv worker. */ class GetConfigQservMgtRequest : public QservMgtRequest { public: - typedef std::shared_ptr Ptr; - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; + typedef std::function const&)> CallbackType; GetConfigQservMgtRequest() = delete; GetConfigQservMgtRequest(GetConfigQservMgtRequest const&) = delete; GetConfigQservMgtRequest& operator=(GetConfigQservMgtRequest const&) = delete; - virtual ~GetConfigQservMgtRequest() = default; + virtual ~GetConfigQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -63,48 +60,25 @@ class GetConfigQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish = nullptr); - - /** - * @return The info object returned back by the worker. - * @note The method will throw exception std::logic_error if called before - * the request finishes or if it's finished with any status but SUCCESS. - */ - nlohmann::json const& info() const; + static std::shared_ptr create( + std::shared_ptr const& serviceProvider, std::string const& worker, + CallbackType const& onFinish = nullptr); protected: - /// @see QservMgtRequest::startImpl() - virtual void startImpl(replica::Lock const& lock); - - /// @see QservMgtRequest::finishImpl() - virtual void finishImpl(replica::Lock const& lock); + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; /// @see QservMgtRequest::notify() - virtual void notify(replica::Lock const& lock); + virtual void notify(replica::Lock const& lock) final; private: /// @see GetConfigQservMgtRequest::create() - GetConfigQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish); - - /** - * Carry over results of the request into a local storage. - * @param lock A lock on QservMgtRequest::_mtx must be acquired by a caller of the method. - * @param info The data string returned by a worker. - */ - void _setInfo(replica::Lock const& lock, std::string const& info); + GetConfigQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, CallbackType const& onFinish); // Input parameters - std::string const _data; - CallbackType _onFinish; ///< this object is reset after finishing the request - - /// A request to the remote services - xrdreq::GetConfigQservRequest::Ptr _qservRequest; - - /// The info object returned by the Qserv worker - nlohmann::json _info; + CallbackType _onFinish; ///< This callback is reset after finishing the request. }; } // namespace lsst::qserv::replica diff --git a/src/replica/GetDbStatusQservHttpMgtRequest.cc b/src/replica/GetDbStatusQservHttpMgtRequest.cc deleted file mode 100644 index 075de27fdb..0000000000 --- a/src/replica/GetDbStatusQservHttpMgtRequest.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/GetDbStatusQservHttpMgtRequest.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetDbStatusQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -shared_ptr GetDbStatusQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, - GetDbStatusQservHttpMgtRequest::CallbackType const& onFinish) { - return shared_ptr( - new GetDbStatusQservHttpMgtRequest(serviceProvider, worker, onFinish)); -} - -GetDbStatusQservHttpMgtRequest::GetDbStatusQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, - GetDbStatusQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_GET_DATABASE_STATUS", worker), _onFinish(onFinish) {} - -void GetDbStatusQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const service = "/mysql"; - createHttpReq(lock, service); -} - -void GetDbStatusQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/GetDbStatusQservHttpMgtRequest.h b/src/replica/GetDbStatusQservHttpMgtRequest.h deleted file mode 100644 index 5b27420cf7..0000000000 --- a/src/replica/GetDbStatusQservHttpMgtRequest.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_GETDBSTATUSQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_GETDBSTATUSQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class GetDbStatusQservHttpMgtRequest is a request for obtaining various info - * on the database service of the Qserv worker. - */ -class GetDbStatusQservHttpMgtRequest : public QservHttpMgtRequest { -public: - /// The function type for notifications on the completion of the request - typedef std::function const&)> CallbackType; - - GetDbStatusQservHttpMgtRequest() = delete; - GetDbStatusQservHttpMgtRequest(GetDbStatusQservHttpMgtRequest const&) = delete; - GetDbStatusQservHttpMgtRequest& operator=(GetDbStatusQservHttpMgtRequest const&) = delete; - - virtual ~GetDbStatusQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static std::shared_ptr create( - std::shared_ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish = nullptr); - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::notify() - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see GetDbStatusQservHttpMgtRequest::create() - GetDbStatusQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, CallbackType const& onFinish); - - // Input parameters - - CallbackType _onFinish; ///< This callback is reset after finishing the request. -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_GETDBSTATUSQSERVHTTPMGTREQUEST_H diff --git a/src/replica/GetDbStatusQservMgtRequest.cc b/src/replica/GetDbStatusQservMgtRequest.cc index c1e89bd526..ee6987ea73 100644 --- a/src/replica/GetDbStatusQservMgtRequest.cc +++ b/src/replica/GetDbStatusQservMgtRequest.cc @@ -22,23 +22,9 @@ // Class header #include "replica/GetDbStatusQservMgtRequest.h" -// System headers -#include -#include - -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/ServiceProvider.h" - // LSST headers #include "lsst/log/Log.h" -using namespace nlohmann; using namespace std; namespace { @@ -49,71 +35,21 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetDbStatusQservMgtRequest"); namespace lsst::qserv::replica { -GetDbStatusQservMgtRequest::Ptr GetDbStatusQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, +shared_ptr GetDbStatusQservMgtRequest::create( + shared_ptr const& serviceProvider, string const& worker, GetDbStatusQservMgtRequest::CallbackType const& onFinish) { - return GetDbStatusQservMgtRequest::Ptr(new GetDbStatusQservMgtRequest(serviceProvider, worker, onFinish)); + return shared_ptr( + new GetDbStatusQservMgtRequest(serviceProvider, worker, onFinish)); } GetDbStatusQservMgtRequest::GetDbStatusQservMgtRequest( - ServiceProvider::Ptr const& serviceProvider, string const& worker, + shared_ptr const& serviceProvider, string const& worker, GetDbStatusQservMgtRequest::CallbackType const& onFinish) : QservMgtRequest(serviceProvider, "QSERV_GET_DATABASE_STATUS", worker), _onFinish(onFinish) {} -json const& GetDbStatusQservMgtRequest::info() const { - if (!((state() == State::FINISHED) && (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("GetDbStatusQservMgtRequest::" + string(__func__) + - " no info available in state: " + state2string(state(), extendedState())); - } - return _info; -} - -list> GetDbStatusQservMgtRequest::extendedPersistentState() const { - list> result; - return result; -} - -void GetDbStatusQservMgtRequest::startImpl(replica::Lock const& lock) { - auto const request = shared_from_base(); - _qservRequest = xrdreq::GetDbStatusQservRequest::create([request](proto::WorkerCommandStatus::Code code, - string const& error, - string const& info) { - if (request->state() == State::FINISHED) return; - replica::Lock const lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - try { - request->_setInfo(lock, info); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - } catch (exception const& ex) { - string const msg = "failed to parse worker response, ex: " + string(ex.what()); - LOGS(_log, LOG_LVL_ERROR, "GetDbStatusQservMgtRequest::" << __func__ << " " << msg); - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD_RESPONSE, msg); - } - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error("GetDbStatusQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void GetDbStatusQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +void GetDbStatusQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const service = "/mysql"; + createHttpReq(lock, service); } void GetDbStatusQservMgtRequest::notify(replica::Lock const& lock) { @@ -121,8 +57,4 @@ void GetDbStatusQservMgtRequest::notify(replica::Lock const& lock) { notifyDefaultImpl(lock, _onFinish); } -void GetDbStatusQservMgtRequest::_setInfo(replica::Lock const& lock, string const& info) { - _info = json::parse(info); -} - } // namespace lsst::qserv::replica diff --git a/src/replica/GetDbStatusQservMgtRequest.h b/src/replica/GetDbStatusQservMgtRequest.h index 57a7d8b42b..0ed93bede2 100644 --- a/src/replica/GetDbStatusQservMgtRequest.h +++ b/src/replica/GetDbStatusQservMgtRequest.h @@ -25,13 +25,12 @@ #include #include -// Third party headers -#include "nlohmann/json.hpp" - // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/GetDbStatusQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { @@ -42,16 +41,14 @@ namespace lsst::qserv::replica { */ class GetDbStatusQservMgtRequest : public QservMgtRequest { public: - typedef std::shared_ptr Ptr; - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; + typedef std::function const&)> CallbackType; GetDbStatusQservMgtRequest() = delete; GetDbStatusQservMgtRequest(GetDbStatusQservMgtRequest const&) = delete; GetDbStatusQservMgtRequest& operator=(GetDbStatusQservMgtRequest const&) = delete; - ~GetDbStatusQservMgtRequest() final = default; + virtual ~GetDbStatusQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -63,51 +60,25 @@ class GetDbStatusQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish = nullptr); - - /** - * @return The info object returned back by the worker. - * @note The method will throw exception std::logic_error if called before - * the request finishes or if it's finished with any status but SUCCESS. - */ - nlohmann::json const& info() const; - - /// @see QservMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const override; + static std::shared_ptr create( + std::shared_ptr const& serviceProvider, std::string const& worker, + CallbackType const& onFinish = nullptr); protected: - /// @see QservMgtRequest::startImpl() - void startImpl(replica::Lock const& lock) final; - - /// @see QservMgtRequest::finishImpl() - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; /// @see QservMgtRequest::notify() - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see GetDbStatusQservMgtRequest::create() - GetDbStatusQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - CallbackType const& onFinish); - - /** - * Carry over results of the request into a local storage. - * @param lock A lock on QservMgtRequest::_mtx must be acquired by a caller of the method. - * @param info The data string returned by a worker. - */ - void _setInfo(replica::Lock const& lock, std::string const& info); + GetDbStatusQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, CallbackType const& onFinish); // Input parameters - std::string const _data; - CallbackType _onFinish; ///< this object is reset after finishing the request - - /// A request to the remote services - xrdreq::GetDbStatusQservRequest::Ptr _qservRequest; - - /// The info object returned by the Qserv worker - nlohmann::json _info; + CallbackType _onFinish; ///< This callback is reset after finishing the request. }; } // namespace lsst::qserv::replica diff --git a/src/replica/GetReplicasQservHttpMgtRequest.cc b/src/replica/GetReplicasQservHttpMgtRequest.cc deleted file mode 100644 index 01b64bfbe7..0000000000 --- a/src/replica/GetReplicasQservHttpMgtRequest.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/GetReplicasQservHttpMgtRequest.h" - -// System headers -#include -#include - -// Qserv headers -#include "replica/Common.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetReplicasQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -GetReplicasQservHttpMgtRequest::Ptr GetReplicasQservHttpMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, string const& databaseFamily, - bool inUseOnly, GetReplicasQservHttpMgtRequest::CallbackType const& onFinish) { - return GetReplicasQservHttpMgtRequest::Ptr( - new GetReplicasQservHttpMgtRequest(serviceProvider, worker, databaseFamily, inUseOnly, onFinish)); -} - -GetReplicasQservHttpMgtRequest::GetReplicasQservHttpMgtRequest( - ServiceProvider::Ptr const& serviceProvider, string const& worker, string const& databaseFamily, - bool inUseOnly, GetReplicasQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_GET_REPLICAS", worker), - _databaseFamily(databaseFamily), - _inUseOnly(inUseOnly), - _onFinish(onFinish) {} - -QservReplicaCollection const& GetReplicasQservHttpMgtRequest::replicas() const { - if (!((state() == State::FINISHED) && (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("GetReplicasQservHttpMgtRequest::" + string(__func__) + - " replicas aren't available in state: " + state2string(state(), extendedState())); - } - return _replicas; -} - -list> GetReplicasQservHttpMgtRequest::extendedPersistentState() const { - list> result; - result.emplace_back("database_family", _databaseFamily); - result.emplace_back("in_use_only", replica::bool2str(_inUseOnly)); - return result; -} - -void GetReplicasQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const service = "/replicas"; - string query = "?in_use_only=" + string(_inUseOnly ? "1" : "0") + "&databases="; - for (auto&& database : serviceProvider()->config()->databases(_databaseFamily)) { - query += database + ","; - } - createHttpReq(lock, service, query); -} - -QservHttpMgtRequest::ExtendedState GetReplicasQservHttpMgtRequest::dataReady(replica::Lock const& lock, - json const& data) { - _replicas.clear(); - for (auto&& [database, chunks] : data.at("replicas").get().items()) { - for (auto&& chunkEntry : chunks) { - unsigned int const chunk = chunkEntry.at(0); - unsigned int const useCount = chunkEntry.at(1); - _replicas.emplace_back(QservReplica{chunk, database, useCount}); - } - } - return QservHttpMgtRequest::ExtendedState::SUCCESS; -} - -void GetReplicasQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/GetReplicasQservHttpMgtRequest.h b/src/replica/GetReplicasQservHttpMgtRequest.h deleted file mode 100644 index a9cd56fd2e..0000000000 --- a/src/replica/GetReplicasQservHttpMgtRequest.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_GET_REPLICAS_QSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_GET_REPLICAS_QSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include - -// Third party headers -#include "nlohmann/json.hpp" - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" -#include "replica/ReplicaInfo.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class GetReplicasQservHttpMgtRequest implements a request retrieving a list of - * replicas known to Qserv workers. - */ -class GetReplicasQservHttpMgtRequest : public QservHttpMgtRequest { -public: - typedef std::shared_ptr Ptr; - - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; - - GetReplicasQservHttpMgtRequest() = delete; - GetReplicasQservHttpMgtRequest(GetReplicasQservHttpMgtRequest const&) = delete; - GetReplicasQservHttpMgtRequest& operator=(GetReplicasQservHttpMgtRequest const&) = delete; - - virtual ~GetReplicasQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param databaseFamily The name of a database family. - * @param inUseOnly (optional) return replicas which are presently in use. - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - std::string const& databaseFamily, bool inUseOnly = false, - CallbackType const& onFinish = nullptr); - - /// @return name of a database family - std::string const& databaseFamily() const { return _databaseFamily; } - - /// @return flag indicating (if set) to report a subset of chunks which are in use - bool inUseOnly() const { return _inUseOnly; } - - /** - * @return A collection of replicas reported from the corresponding Qserv worker. - * @throw std::logic_error If called before the request finishes or if it's finished with - * any status but SUCCESS. - */ - QservReplicaCollection const& replicas() const; - - /// @see QservHttpMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const override; - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::dataReady() - virtual QservHttpMgtRequest::ExtendedState dataReady(replica::Lock const& lock, - nlohmann::json const& data) final; - - /// @see QservHttpMgtRequest::notify - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see GetReplicasQservHttpMgtRequest::create() - GetReplicasQservHttpMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - std::string const& databaseFamily, bool inUseOnly, - CallbackType const& onFinish); - - // Input parameters - - std::string const _databaseFamily; - bool const _inUseOnly; - CallbackType _onFinish; ///< The callback function is reset when the request finishes. - - /// A collection of replicas reported by the Qserr worker - QservReplicaCollection _replicas; -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_GET_REPLICAS_QSERVHTTPMGTREQUEST_H diff --git a/src/replica/GetReplicasQservMgtRequest.cc b/src/replica/GetReplicasQservMgtRequest.cc index 57c88e21a0..7c2964546b 100644 --- a/src/replica/GetReplicasQservMgtRequest.cc +++ b/src/replica/GetReplicasQservMgtRequest.cc @@ -26,19 +26,15 @@ #include #include -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - // Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" +#include "replica/Common.h" #include "replica/Configuration.h" #include "replica/ServiceProvider.h" // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; namespace { @@ -62,11 +58,10 @@ GetReplicasQservMgtRequest::GetReplicasQservMgtRequest( : QservMgtRequest(serviceProvider, "QSERV_GET_REPLICAS", worker), _databaseFamily(databaseFamily), _inUseOnly(inUseOnly), - _onFinish(onFinish), - _qservRequest(nullptr) {} + _onFinish(onFinish) {} QservReplicaCollection const& GetReplicasQservMgtRequest::replicas() const { - if (not((state() == State::FINISHED) and (extendedState() == ExtendedState::SUCCESS))) { + if (!((state() == State::FINISHED) && (extendedState() == ExtendedState::SUCCESS))) { throw logic_error("GetReplicasQservMgtRequest::" + string(__func__) + " replicas aren't available in state: " + state2string(state(), extendedState())); } @@ -75,81 +70,35 @@ QservReplicaCollection const& GetReplicasQservMgtRequest::replicas() const { list> GetReplicasQservMgtRequest::extendedPersistentState() const { list> result; - result.emplace_back("database_family", databaseFamily()); - result.emplace_back("in_use_only", bool2str(inUseOnly())); + result.emplace_back("database_family", _databaseFamily); + result.emplace_back("in_use_only", replica::bool2str(_inUseOnly)); return result; } -void GetReplicasQservMgtRequest::_setReplicas( - replica::Lock const& lock, xrdreq::GetChunkListQservRequest::ChunkCollection const& collection) { - // Filter results by databases participating in the family - - set databases; - for (auto&& database : serviceProvider()->config()->databases(databaseFamily())) { - databases.insert(database); - } - _replicas.clear(); - for (auto&& replica : collection) { - if (databases.count(replica.database)) { - _replicas.emplace_back(QservReplica{replica.chunk, replica.database, replica.use_count}); - } +void GetReplicasQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const service = "/replicas"; + string query = "?in_use_only=" + string(_inUseOnly ? "1" : "0") + "&databases="; + for (auto&& database : serviceProvider()->config()->databases(_databaseFamily)) { + query += database + ","; } + createHttpReq(lock, service, query); } -void GetReplicasQservMgtRequest::startImpl(replica::Lock const& lock) { - // Check if configuration parameters are valid - - if (not serviceProvider()->config()->isKnownDatabaseFamily(databaseFamily())) { - LOGS(_log, LOG_LVL_ERROR, - context() << __func__ << " ** MISCONFIGURED ** " - << " database family: '" << databaseFamily() << "'"); - - finish(lock, ExtendedState::CONFIG_ERROR); - return; - } - - // Submit the actual request - - auto const request = shared_from_base(); - - _qservRequest = xrdreq::GetChunkListQservRequest::create( - inUseOnly(), [request](proto::WorkerCommandStatus::Code code, string const& error, - xrdreq::GetChunkListQservRequest::ChunkCollection const& collection) { - if (request->state() == State::FINISHED) return; - replica::Lock lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - request->_setReplicas(lock, collection); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error( - "GetReplicasQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void GetReplicasQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; +QservMgtRequest::ExtendedState GetReplicasQservMgtRequest::dataReady(replica::Lock const& lock, + json const& data) { + _replicas.clear(); + for (auto&& [database, chunks] : data.at("replicas").get().items()) { + for (auto&& chunkEntry : chunks) { + unsigned int const chunk = chunkEntry.at(0); + unsigned int const useCount = chunkEntry.at(1); + _replicas.emplace_back(QservReplica{chunk, database, useCount}); + } } + return QservMgtRequest::ExtendedState::SUCCESS; } void GetReplicasQservMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); + LOGS(_log, LOG_LVL_TRACE, context() << __func__); notifyDefaultImpl(lock, _onFinish); } diff --git a/src/replica/GetReplicasQservMgtRequest.h b/src/replica/GetReplicasQservMgtRequest.h index 508bf75cc7..f98063a133 100644 --- a/src/replica/GetReplicasQservMgtRequest.h +++ b/src/replica/GetReplicasQservMgtRequest.h @@ -22,15 +22,21 @@ #define LSST_QSERV_REPLICA_GET_REPLICAS_QSERVMGTREQUEST_H // System headers +#include #include #include -#include +#include + +// Third party headers +#include "nlohmann/json.hpp" // Qserv headers #include "replica/QservMgtRequest.h" #include "replica/ReplicaInfo.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/GetChunkListQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { @@ -50,7 +56,7 @@ class GetReplicasQservMgtRequest : public QservMgtRequest { GetReplicasQservMgtRequest(GetReplicasQservMgtRequest const&) = delete; GetReplicasQservMgtRequest& operator=(GetReplicasQservMgtRequest const&) = delete; - ~GetReplicasQservMgtRequest() final = default; + virtual ~GetReplicasQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -86,14 +92,15 @@ class GetReplicasQservMgtRequest : public QservMgtRequest { std::list> extendedPersistentState() const override; protected: - /// @see QservMgtRequest::startImpl - void startImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; - /// @see QservMgtRequest::finishImpl - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::dataReady() + virtual QservMgtRequest::ExtendedState dataReady(replica::Lock const& lock, + nlohmann::json const& data) final; /// @see QservMgtRequest::notify - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see GetReplicasQservMgtRequest::create() @@ -101,24 +108,11 @@ class GetReplicasQservMgtRequest : public QservMgtRequest { std::string const& databaseFamily, bool inUseOnly, CallbackType const& onFinish); - /** - * Carry over results of the request into a local collection. Filter results - * by databases participating in the family. - * - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling this method - * @param collection The input collection of replicas. - */ - void _setReplicas(replica::Lock const& lock, - xrdreq::GetChunkListQservRequest::ChunkCollection const& collection); - // Input parameters std::string const _databaseFamily; bool const _inUseOnly; - CallbackType _onFinish; /// @note is reset when the request finishes - - /// A request to the remote services - xrdreq::GetChunkListQservRequest::Ptr _qservRequest; + CallbackType _onFinish; ///< The callback function is reset when the request finishes. /// A collection of replicas reported by the Qserr worker QservReplicaCollection _replicas; diff --git a/src/replica/GetStatusQservHttpMgtRequest.cc b/src/replica/GetStatusQservHttpMgtRequest.cc deleted file mode 100644 index 9d83c184f2..0000000000 --- a/src/replica/GetStatusQservHttpMgtRequest.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/GetStatusQservHttpMgtRequest.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetStatusQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -shared_ptr GetStatusQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, - wbase::TaskSelector const& taskSelector, GetStatusQservHttpMgtRequest::CallbackType const& onFinish) { - return shared_ptr( - new GetStatusQservHttpMgtRequest(serviceProvider, worker, taskSelector, onFinish)); -} - -GetStatusQservHttpMgtRequest::GetStatusQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, - wbase::TaskSelector const& taskSelector, GetStatusQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_GET_STATUS", worker), - _taskSelector(taskSelector), - _onFinish(onFinish) {} - -void GetStatusQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const service = "/status"; - string const query = wbase::taskSelectorToHttpQuery(_taskSelector); - createHttpReq(lock, service, query); -} - -void GetStatusQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/GetStatusQservHttpMgtRequest.h b/src/replica/GetStatusQservHttpMgtRequest.h deleted file mode 100644 index e2dd9bd8e0..0000000000 --- a/src/replica/GetStatusQservHttpMgtRequest.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_GETSTATUSQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_GETSTATUSQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" -#include "wbase/TaskState.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class GetStatusQservHttpMgtRequest is a request for obtaining various info - * (status, counters, monitoring) reported the Qserv workers. - */ -class GetStatusQservHttpMgtRequest : public QservHttpMgtRequest { -public: - /// The function type for notifications on the completion of the request - typedef std::function const&)> CallbackType; - - GetStatusQservHttpMgtRequest() = delete; - GetStatusQservHttpMgtRequest(GetStatusQservHttpMgtRequest const&) = delete; - GetStatusQservHttpMgtRequest& operator=(GetStatusQservHttpMgtRequest const&) = delete; - - virtual ~GetStatusQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param taskSelector (optional) task selection criterias - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static std::shared_ptr create( - std::shared_ptr const& serviceProvider, std::string const& worker, - wbase::TaskSelector const& taskSelector = wbase::TaskSelector(), - CallbackType const& onFinish = nullptr); - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::notify() - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see GetStatusQservHttpMgtRequest::create() - GetStatusQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, wbase::TaskSelector const& taskSelector, - CallbackType const& onFinish); - - // Input parameters - - wbase::TaskSelector const _taskSelector; - CallbackType _onFinish; ///< This callback is reset after finishing the request. -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_GETSTATUSQSERVHTTPMGTREQUEST_H diff --git a/src/replica/GetStatusQservMgtRequest.cc b/src/replica/GetStatusQservMgtRequest.cc index 06a3bec11e..2bc546455a 100644 --- a/src/replica/GetStatusQservMgtRequest.cc +++ b/src/replica/GetStatusQservMgtRequest.cc @@ -22,24 +22,9 @@ // Class header #include "replica/GetStatusQservMgtRequest.h" -// System headers -#include -#include - -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" - // LSST headers #include "lsst/log/Log.h" -using namespace nlohmann; using namespace std; namespace { @@ -50,14 +35,14 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.GetStatusQservMgtRequest"); namespace lsst::qserv::replica { -GetStatusQservMgtRequest::Ptr GetStatusQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, +shared_ptr GetStatusQservMgtRequest::create( + shared_ptr const& serviceProvider, string const& worker, wbase::TaskSelector const& taskSelector, GetStatusQservMgtRequest::CallbackType const& onFinish) { - return GetStatusQservMgtRequest::Ptr( + return shared_ptr( new GetStatusQservMgtRequest(serviceProvider, worker, taskSelector, onFinish)); } -GetStatusQservMgtRequest::GetStatusQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, +GetStatusQservMgtRequest::GetStatusQservMgtRequest(shared_ptr const& serviceProvider, string const& worker, wbase::TaskSelector const& taskSelector, GetStatusQservMgtRequest::CallbackType const& onFinish) @@ -65,62 +50,10 @@ GetStatusQservMgtRequest::GetStatusQservMgtRequest(ServiceProvider::Ptr const& s _taskSelector(taskSelector), _onFinish(onFinish) {} -json const& GetStatusQservMgtRequest::info() const { - if (not((state() == State::FINISHED) and (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("GetStatusQservMgtRequest::" + string(__func__) + - " no info available in state: " + state2string(state(), extendedState())); - } - return _info; -} - -list> GetStatusQservMgtRequest::extendedPersistentState() const { - list> result; - return result; -} - -void GetStatusQservMgtRequest::startImpl(replica::Lock const& lock) { - auto const request = shared_from_base(); - _qservRequest = xrdreq::GetStatusQservRequest::create( - _taskSelector, - [request](proto::WorkerCommandStatus::Code code, string const& error, string const& info) { - if (request->state() == State::FINISHED) return; - replica::Lock const lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - try { - request->_setInfo(lock, info); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - } catch (exception const& ex) { - string const msg = "failed to parse worker response, ex: " + string(ex.what()); - LOGS(_log, LOG_LVL_ERROR, - "GetStatusQservMgtRequest::" << __func__ << " " << msg); - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD_RESPONSE, msg); - } - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error( - "GetStatusQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void GetStatusQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +void GetStatusQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const service = "/status"; + string const query = wbase::taskSelectorToHttpQuery(_taskSelector); + createHttpReq(lock, service, query); } void GetStatusQservMgtRequest::notify(replica::Lock const& lock) { @@ -128,8 +61,4 @@ void GetStatusQservMgtRequest::notify(replica::Lock const& lock) { notifyDefaultImpl(lock, _onFinish); } -void GetStatusQservMgtRequest::_setInfo(replica::Lock const& lock, string const& info) { - _info = json::parse(info); -} - } // namespace lsst::qserv::replica diff --git a/src/replica/GetStatusQservMgtRequest.h b/src/replica/GetStatusQservMgtRequest.h index 4242906d53..3ba5bfb017 100644 --- a/src/replica/GetStatusQservMgtRequest.h +++ b/src/replica/GetStatusQservMgtRequest.h @@ -24,16 +24,14 @@ // System headers #include #include -#include - -// Third party headers -#include "nlohmann/json.hpp" // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" #include "wbase/TaskState.h" -#include "xrdreq/GetStatusQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { @@ -44,16 +42,14 @@ namespace lsst::qserv::replica { */ class GetStatusQservMgtRequest : public QservMgtRequest { public: - typedef std::shared_ptr Ptr; - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; + typedef std::function const&)> CallbackType; GetStatusQservMgtRequest() = delete; GetStatusQservMgtRequest(GetStatusQservMgtRequest const&) = delete; GetStatusQservMgtRequest& operator=(GetStatusQservMgtRequest const&) = delete; - ~GetStatusQservMgtRequest() final = default; + virtual ~GetStatusQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -66,53 +62,28 @@ class GetStatusQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - wbase::TaskSelector const& taskSelector = wbase::TaskSelector(), - CallbackType const& onFinish = nullptr); - - /** - * @return The info object returned back by the worker. - * @note The method will throw exception std::logic_error if called before - * the request finishes or if it's finished with any status but SUCCESS. - */ - nlohmann::json const& info() const; - - /// @see QservMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const override; + static std::shared_ptr create( + std::shared_ptr const& serviceProvider, std::string const& worker, + wbase::TaskSelector const& taskSelector = wbase::TaskSelector(), + CallbackType const& onFinish = nullptr); protected: - /// @see QservMgtRequest::startImpl() - void startImpl(replica::Lock const& lock) final; - - /// @see QservMgtRequest::finishImpl() - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; /// @see QservMgtRequest::notify() - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see GetStatusQservMgtRequest::create() - GetStatusQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - wbase::TaskSelector const& taskSelector, CallbackType const& onFinish); - - /** - * Carry over results of the request into a local storage. - * @param lock A lock on QservMgtRequest::_mtx must be acquired by a caller of the method. - * @param info The data string returned by a worker. - */ - void _setInfo(replica::Lock const& lock, std::string const& info); + GetStatusQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, wbase::TaskSelector const& taskSelector, + CallbackType const& onFinish); // Input parameters - std::string const _data; wbase::TaskSelector const _taskSelector; - CallbackType _onFinish; ///< this object is reset after finishing the request - - /// A request to the remote services - xrdreq::GetStatusQservRequest::Ptr _qservRequest; - - /// The info object returned by the Qserv worker - nlohmann::json _info; + CallbackType _onFinish; ///< This callback is reset after finishing the request. }; } // namespace lsst::qserv::replica diff --git a/src/replica/QservHttpMgtRequest.cc b/src/replica/QservHttpMgtRequest.cc deleted file mode 100644 index eb2c870eae..0000000000 --- a/src/replica/QservHttpMgtRequest.cc +++ /dev/null @@ -1,356 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/QservHttpMgtRequest.h" - -// System headers -#include -#include - -// Qserv headers -#include "http/MetaModule.h" -#include "replica/Configuration.h" -#include "replica/Common.h" -#include "replica/DatabaseServices.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.QservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -atomic QservHttpMgtRequest::_numClassInstances(0); - -string QservHttpMgtRequest::state2string(State state) { - switch (state) { - case State::CREATED: - return "CREATED"; - case State::IN_PROGRESS: - return "IN_PROGRESS"; - case State::FINISHED: - return "FINISHED"; - } - throw logic_error("QservHttpMgtRequest::" + string(__func__) + "(State) incomplete implementation"); -} - -string QservHttpMgtRequest::state2string(ExtendedState state) { - switch (state) { - case ExtendedState::NONE: - return "NONE"; - case ExtendedState::SUCCESS: - return "SUCCESS"; - case ExtendedState::CONFIG_ERROR: - return "CONFIG_ERROR"; - case ExtendedState::BODY_LIMIT_ERROR: - return "BODY_LIMIT_ERROR"; - case ExtendedState::SERVER_BAD: - return "SERVER_BAD"; - case ExtendedState::SERVER_CHUNK_IN_USE: - return "SERVER_CHUNK_IN_USE"; - case ExtendedState::SERVER_ERROR: - return "SERVER_ERROR"; - case ExtendedState::SERVER_BAD_RESPONSE: - return "SERVER_BAD_RESPONSE"; - case ExtendedState::TIMEOUT_EXPIRED: - return "TIMEOUT_EXPIRED"; - case ExtendedState::CANCELLED: - return "CANCELLED"; - } - throw logic_error("QservHttpMgtRequest::" + string(__func__) + - "(ExtendedState) incomplete implementation"); -} - -QservHttpMgtRequest::QservHttpMgtRequest(ServiceProvider::Ptr const& serviceProvider, string const& type, - string const& worker) - : _serviceProvider(serviceProvider), - _type(type), - _id(Generators::uniqueId()), - _worker(worker), - _state(State::CREATED), - _extendedState(ExtendedState::NONE) { - // This report is used solely for debugging purposes to allow tracking - // potential memory leaks within applications. - ++_numClassInstances; - LOGS(_log, LOG_LVL_TRACE, context() << "constructed instances: " << _numClassInstances); -} - -QservHttpMgtRequest::~QservHttpMgtRequest() { - --_numClassInstances; - LOGS(_log, LOG_LVL_TRACE, context() << "destructed instances: " << _numClassInstances); -} - -string QservHttpMgtRequest::state2string() const { - replica::Lock const lock(_mtx, context() + __func__); - return state2string(state(), extendedState()) + "::" + serverError(lock); -} - -string QservHttpMgtRequest::serverError() const { - replica::Lock const lock(_mtx, context() + __func__); - return serverError(lock); -} - -string QservHttpMgtRequest::serverError(replica::Lock const& lock) const { return _serverError; } - -string QservHttpMgtRequest::context() const { - return id() + " " + type() + " " + state2string(state(), extendedState()) + " "; -} - -Performance QservHttpMgtRequest::performance() const { - replica::Lock const lock(_mtx, context() + __func__); - return performance(lock); -} - -Performance QservHttpMgtRequest::performance(replica::Lock const& lock) const { return _performance; } - -void QservHttpMgtRequest::start(string const& jobId, unsigned int requestExpirationIvalSec) { - string const context_ = context() + __func__; - LOGS(_log, LOG_LVL_TRACE, context_); - - replica::Lock const lock(_mtx, context_); - _assertNotStarted(__func__); - - // This needs to be updated to override the default value of the counter - // which was created upon the object construction. - _performance.setUpdateStart(); - - // Check if configuration parameters are valid - auto const config = _serviceProvider->config(); - if (!config->isKnownWorker(_worker)) { - LOGS(_log, LOG_LVL_ERROR, context_ << " ** MISCONFIGURED ** unknown worker: '" << _worker << "'."); - _setState(lock, State::FINISHED, ExtendedState::CONFIG_ERROR); - notify(lock); - return; - } - - // Build an association with the corresponding parent job (optional). - _jobId = jobId; - - // Adjust the default value of the expiration ival (if requested) before - // creating and starting the request. - unsigned int actualExpirationIvalSec = requestExpirationIvalSec; - if (0 == actualExpirationIvalSec) { - actualExpirationIvalSec = config->get("xrootd", "request-timeout-sec"); - } - - createHttpReqImpl(lock); - - _httpRequest->setExpirationIval(actualExpirationIvalSec); - _httpRequest->start(); - - _setState(lock, State::IN_PROGRESS); -} - -void QservHttpMgtRequest::wait() { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - if (_state == State::FINISHED) return; - unique_lock onFinishLock(_onFinishMtx); - _onFinishCv.wait(onFinishLock, [&] { return _finished; }); -} - -string const& QservHttpMgtRequest::jobId() const { - _assertStarted(__func__); - return _jobId; -} - -json const& QservHttpMgtRequest::info() const { - if (!((_state == State::FINISHED) && (_extendedState == ExtendedState::SUCCESS))) { - throw logic_error("QservHttpMgtRequest::" + string(__func__) + - " no info available in state: " + state2string(_state, _extendedState)); - } - return _info; -} - -void QservHttpMgtRequest::cancel() { - _assertStarted(__func__); - // No HTTP request would be sent if the request creation failed for some - // reason (like misconfiguration, etc.). Hence, there is nothing to cancel. - { - replica::Lock const lock(_mtx, context() + __func__); - if (_httpRequest == nullptr) return; - } - _httpRequest->cancel(); -} - -void QservHttpMgtRequest::createHttpReq(replica::Lock const& lock, string const& service, - string const& query) { - _assertNotStarted(__func__); - string const target = service + query + string(query.empty() ? "?" : "&") + "id" + _id + - "&instance_id=" + _serviceProvider->instanceId() + "&worker=" + _worker + - "&version=" + to_string(http::MetaModule::version); - _httpRequest = http::AsyncReq::create( - _serviceProvider->io_service(), - [self = shared_from_this()](shared_ptr const&) { self->_processResponse(); }, - "GET", _getHostPortTracker(), target); -} - -void QservHttpMgtRequest::createHttpReq(replica::Lock const& lock, string const& method, string const& target, - json const& body) { - _assertNotStarted(__func__); - json data = body; - data["id"] = _id; - data["instance_id"] = _serviceProvider->instanceId(); - data["worker"] = _worker; - data["auth_key"] = _serviceProvider->authKey(); - data["admin_auth_key"] = _serviceProvider->adminAuthKey(); - data["version"] = http::MetaModule::version; - unordered_map const headers = {{"Content-Type", "application/json"}}; - _httpRequest = http::AsyncReq::create( - _serviceProvider->io_service(), - [self = shared_from_this()](shared_ptr const&) { self->_processResponse(); }, - method, _getHostPortTracker(), target, data.dump(), headers); -} - -void QservHttpMgtRequest::finish(replica::Lock const& lock, ExtendedState extendedState, - string const& serverError) { - string const context_ = context() + __func__; - LOGS(_log, LOG_LVL_DEBUG, context_ << " serverError:" << serverError); - - // Set the optional server error state as well. - // IMPORTANT: this needs to be done before performing the state transition to insure - // clients will get a consistent view onto the object state. - _serverError = serverError; - - // Set new state to make sure all event handlers will recognize - // this scenario and avoid making any modifications to the request's state. - _setState(lock, State::FINISHED, extendedState); - - // We have to update the timestamp before invoking a user provided - // callback on the completion of the operation. - _performance.setUpdateFinish(); - - // TODO: temporarily disabled while this class is not supported by - // the persistent backend. - // - // _serviceProvider->databaseServices()->saveState(*this, _performance, _serverError); - - notify(lock); - - // Unblock threads (if any) waiting on the synchronization call to the method wait(). - _finished = true; - _onFinishCv.notify_all(); -} - -http::AsyncReq::GetHostPort QservHttpMgtRequest::_getHostPortTracker() const { - return [config = _serviceProvider->config(), - worker = _worker](http::AsyncReq::HostPort const&) -> http::AsyncReq::HostPort { - auto const info = config->workerInfo(worker); - return http::AsyncReq::HostPort{info.qservWorker.host.addr, info.qservWorker.port}; - }; -} - -void QservHttpMgtRequest::_processResponse() { - string const context_ = context() + string(__func__) + " "; - if (_state == State::FINISHED) return; - replica::Lock const lock(_mtx, context_); - if (_state == State::FINISHED) return; - - switch (_httpRequest->state()) { - case http::AsyncReq::State::FINISHED: - try { - _info = json::parse(_httpRequest->responseBody()); - if (_info.at("success").get() == 0) { - string const msg = "worker reported error: " + _info.at("error").get(); - auto extendedState = ExtendedState::SERVER_BAD; - // Check for optional markers in the optional extended error section that might - // clarify an actual reason behind the failure. - if (auto const itr = _info.find("error_ext"); itr != _info.end()) { - json const errorExt = *itr; - if (errorExt.contains("in_use")) { - extendedState = ExtendedState::SERVER_CHUNK_IN_USE; - } else if (errorExt.contains("invalid_param")) { - extendedState = ExtendedState::CONFIG_ERROR; - } - } - finish(lock, extendedState, msg); - } else { - // Let a subclass do the optional result validation and post processing. - // Note that the subclass has the final say on the completion status - // of the request. - finish(lock, dataReady(lock, _info)); - } - } catch (exception const& ex) { - string const msg = "failed to parse/process worker response, ex: " + string(ex.what()); - finish(lock, ExtendedState::SERVER_BAD_RESPONSE, msg); - } - break; - case http::AsyncReq::State::FAILED: - finish(lock, ExtendedState::SERVER_ERROR, - _httpRequest->errorMessage() + ", code: " + to_string(_httpRequest->responseCode())); - break; - case http::AsyncReq::State::BODY_LIMIT_ERROR: - finish(lock, ExtendedState::BODY_LIMIT_ERROR, - _httpRequest->errorMessage() + ", code: " + to_string(_httpRequest->responseCode())); - break; - case http::AsyncReq::State::CANCELLED: - finish(lock, ExtendedState::CANCELLED); - break; - case http::AsyncReq::State::EXPIRED: - finish(lock, ExtendedState::TIMEOUT_EXPIRED); - break; - default: - throw runtime_error(context_ + "unsupported state of the HTTP _httpRequest: " + - http::AsyncReq::state2str(_httpRequest->state())); - } -} - -void QservHttpMgtRequest::_assertStarted(string const& func, bool mustBeStarted) const { - string const context_ = context() + func; - LOGS(_log, LOG_LVL_TRACE, context_); - if (mustBeStarted) { - if (State::CREATED == _state) { - throw logic_error(context_ + " the request was not started."); - } - } else { - if (State::CREATED != _state) { - throw logic_error(context_ + " the request was already started."); - } - } -} - -void QservHttpMgtRequest::_setState(replica::Lock const& lock, State newState, - ExtendedState newExtendedState) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__ << " " << state2string(newState, newExtendedState)); - - // IMPORTANT: the top-level state is the last to be set when performing - // the state transition to insure clients will get a consistent view onto - // the object state. - { - unique_lock onFinishLock(_onFinishMtx); - _extendedState = newExtendedState; - _state = newState; - } - - // TODO: temporarily disabled while this class is not supported by - // the persistent backend. - // - // _serviceProvider->databaseServices()->saveState(*this, _performance, _serverError); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/QservHttpMgtRequest.h b/src/replica/QservHttpMgtRequest.h deleted file mode 100644 index 5cc1370e87..0000000000 --- a/src/replica/QservHttpMgtRequest.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_QSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_QSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include -#include -#include -#include - -// Third party headers -#include "nlohmann/json.hpp" - -// Qserv headers -#include "http/AsyncReq.h" -#include "replica/Mutex.h" -#include "replica/Performance.h" -#include "replica/ServiceProvider.h" - -// This header declarations -namespace lsst::qserv::replica { - -/** - * @brief QservHttpMgtRequest is a base class for a family of the Qserv worker - * management requests within the master server. - */ -class QservHttpMgtRequest : public std::enable_shared_from_this { -public: - typedef std::shared_ptr Ptr; - - /// The lock type used by the implementations - typedef std::lock_guard LockType; - - /// The type which represents the primary public state of the request - enum State { - CREATED, ///< The request has been constructed, and no attempt to execute - /// it has been made. - IN_PROGRESS, ///< The request is in a progress. - FINISHED ///< The request is finished. See extended status for more details - /// (the completion status, etc.) - }; - - /// @return the string representation of the primary state - static std::string state2string(State state); - - /// Type ExtendedState represents the refined public sub-state of the request - /// once it's FINISHED as per the above defined primary state. - enum ExtendedState { - NONE, ///< No extended state exists at this time. - SUCCESS, ///< The request has been fully implemented. - CONFIG_ERROR, ///< Problems with request configuration were detected. - BODY_LIMIT_ERROR, ///< Response's body is larger than requested. - SERVER_BAD, ///< Server reports that the request can not be implemented because - /// of configuration or request's parameters problems. - SERVER_CHUNK_IN_USE, ///< Server reports that the request can not be implemented because - /// some of the required remote resources (chunks, etc.) are in use. - SERVER_ERROR, ///< The request could not be implemented due to an unrecoverable - /// server-side error. - SERVER_BAD_RESPONSE, ///< Data received from a server can't be correctly interpreted. - TIMEOUT_EXPIRED, ///< Expired due to a timeout. - CANCELLED ///< Explicitly cancelled on the client-side. - }; - - /// @return the string representation of the extended state - static std::string state2string(ExtendedState state); - - /// @return the string representation of the combined state - static std::string state2string(State state, ExtendedState extendedState) { - return state2string(state) + "::" + state2string(extendedState); - } - - QservHttpMgtRequest() = delete; - QservHttpMgtRequest(QservHttpMgtRequest const&) = delete; - QservHttpMgtRequest& operator=(QservHttpMgtRequest const&) = delete; - - virtual ~QservHttpMgtRequest(); - - /// @return reference to a provider of services - std::shared_ptr const& serviceProvider() { return _serviceProvider; } - - /// @return string representing of the request type. - std::string const& type() const { return _type; } - - /// @return unique identifier of the request - std::string const& id() const { return _id; } - - /// @return name of a worker - std::string const& worker() const { return _worker; } - - /// @return primary status of the request - State state() const { return _state; } - - /// @return extended status of the request - ExtendedState extendedState() const { return _extendedState; } - - /// @return string representation of the combined state of the object - std::string state2string() const; - - /// @return error message (if any) reported by the remote service. - std::string serverError() const; - - /// @return performance info - Performance performance() const; - - /** - * @return An identifier if the owning job (if the request has started). - * @throws std::logic_error If the request hasn't started. - */ - std::string const& jobId() const; - - /** - * @return The info object returned by the worker. - * @throw std::logic_error if called before the request finishes or if it failed. - */ - nlohmann::json const& info() const; - - /** - * @brief Begin processing the request. - * @param jobId (Optional) identifier of a job specifying a context of the request. - * @param requestExpirationIvalSec (Optional) parameter (if differs from 0) allowing - * to override the default value of the corresponding parameter from the Configuration. - */ - void start(std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); - - /// Wait for the completion of the request - void wait(); - - /** - * @brief Explicitly cancel any asynchronous operation(s) and put the object into - * the FINISHED::CANCELLED state. This operation is very similar to the - * timeout-based request expiration, except it's requested explicitly. - */ - void cancel(); - - /// @return The context string for debugging and diagnostic printouts. - std::string context() const; - - /// @return A dictionary of parameters and the corresponding values to be stored - /// in a database for a request. - virtual std::list> extendedPersistentState() const { - return std::list>(); - } - -protected: - /** - * @brief Construct the request with the pointer to the services provider. - * @param serviceProvider Is required to access configuration services. - * @param type The type name of he request (used for debugging and error reporting). - * @param worker The name of a worker. - */ - QservHttpMgtRequest(std::shared_ptr const& serviceProvider, std::string const& type, - std::string const& worker); - - /// @return A shared pointer of the desired subclass (no dynamic type checking). - template - std::shared_ptr shared_from_base() { - return std::static_pointer_cast(shared_from_this()); - } - - /** - * @brief Create an HTTP request. - * - * The methods is required to be provided by subclasses for creating - * subclass-specific requests using the coresponding helper methods. - * - * @see QservHttpMgtRequest::createHttpReq - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - */ - virtual void createHttpReqImpl(replica::Lock const& lock) = 0; - - /** - * @brief Create an HTTP "GET" request, but do not start it yet. - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param service The REST service (w/o the query part) to be called. - * @param (optional) HTTP query for the request. - * @throw std::logic_error If the method is called while the curent state - * is not State::CREATED, or if the HTTP request was already created. - */ - void createHttpReq(replica::Lock const& lock, std::string const& service, - std::string const& query = std::string()); - - /** - * @brief Create an HTTP request ("POST", "PUT" or "DELETE") that has the JSON body, - * but do not start it yet. - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param method An HTTP method ("POST", "PUT" or "DELETE") for the request, - * @param service The complete target (including the REST service and the query part) to be called. - * @param body A JSON object to be sent in the request's body. - * @throw std::logic_error If the method is called while the curent state - * is not State::CREATED, or if the HTTP request was already created. - */ - void createHttpReq(replica::Lock const& lock, std::string const& method, std::string const& target, - nlohmann::json const& body); - - /** - * @brief Notify a subclass that a data object was was succesfully retrieved - * from the worker. - * - * This method allows subclasses to implement the optional result validation and processing, - * including a translation of the JSON object into the subclas-specific result type. - * - * @note Any exceptions thrown by the method will result in setting the status - * ExtendedState::SERVER_BAD_RESPONSE to indicate a problem with interpreting the data. - * The method is also required to report its final verdican on the status of the object. - * Normally, it's going to be ExtendedState::SUCCESS. However, a subclass may set - * a different status, depending on its findings. - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param data The JSON result to be processed by a subclass. - * @return The final verdict made by the subclass on the completion status. - */ - virtual ExtendedState dataReady(replica::Lock const& lock, nlohmann::json const& data) { - return ExtendedState::SUCCESS; - } - - /** - * @brief Finalize request processing (as reported by subclasses) - * @note This is supposed to be the last operation to be called by subclasses - * upon a completion of the request. - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param extendedState The new extended state. - * @param serverError (optional) error message from a Qserv worker service. - */ - void finish(replica::Lock const& lock, ExtendedState extendedState, std::string const& serverError = ""); - - /** - * @brief Start user-notification protocol (in case if user-defined notifiers - * were provided to a subclass). The callback is expected to be made - * asynchronously in a separate thread to avoid blocking the current thread. - * - * This method has to be provided by subclasses to forward - * notification on request completion to a client which initiated - * the request, etc. - * - * The standard implementation of this method in a context of some - * subclass 'T' should looks like this: - * @code - * void T::notify(replica::Lock const& lock) { - * notifyDefaultImpl(lock, _onFinish); - * } - * @code - * @see QservHttpMgtRequest::notifyDefaultImpl - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - */ - virtual void notify(replica::Lock const& lock) = 0; - - /** - * @brief The helper function which pushes up-stream notifications on behalf of - * subclasses. Upon a completion of this method the callback function - * object will get reset to 'nullptr'. - * @note This default implementation works for callback functions which - * accept a single parameter - a smart reference onto an object of - * the corresponding subclass. Subclasses with more complex signatures of - * their callbacks should have their own implementations which may look - * similarly to this one. - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param onFinish A callback function (if set) to be called. - */ - template - void notifyDefaultImpl(replica::Lock const& lock, typename T::CallbackType& onFinish) { - if (nullptr != onFinish) { - // Clearing the stored callback after finishing the up-stream notification - // has two purposes: - // 1. it guaranties (exactly) one time notification - // 2. it breaks the up-stream dependency on a caller object if a shared - // pointer to the object was mentioned as the lambda-function's closure - serviceProvider()->io_service().post(std::bind(std::move(onFinish), shared_from_base())); - onFinish = nullptr; - } - } - - /** - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @return A server error string (if any). - */ - std::string serverError(replica::Lock const& lock) const; - - /** - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @return The performance info. - */ - Performance performance(replica::Lock const& lock) const; - - /// Mutex guarding internal state (also used by subclasses) - mutable replica::Mutex _mtx; - -private: - /// @return The callback function for tracking connection parameters of the worker. - http::AsyncReq::GetHostPort _getHostPortTracker() const; - - /// Extract and process data of the completed request. Notify a subclass in case of success. - void _processResponse(); - - /** - * @brief Ensure the request is in the desired state. - * @note The method doesn't require a lock on the mutex _mtx to be acqured before - * being called neither it acquires the lock by itself since the implementation - * of the method relies on checking a value of the atomic variable representing - * the primary state of the request. - * @param func A context from which the state test is requested (for tracing - * and error reporting). - * @param mustBeStarted 'true' if the request is expected to be in any - * state past State::CREATED, or 'false' if it's expected to be exactly - * in State::CREATED. - * @throws std::logic_error If the request was not found in the desired state. - */ - void _assertStarted(std::string const& func, bool mustBeStarted) const; - - // Shortcut methods based on the above defined one. - - void _assertStarted(std::string const& func) const { _assertStarted(func, true); } - void _assertNotStarted(std::string const& func) const { _assertStarted(func, false); } - - /** - * @brief Set the desired primary and extended state. - * - * The change of the state is done via a method to allow extra actions - * at this step, such as: 1) reporting change state in a debug stream, - * or 2) verifying the correctness of the state transition. - * - * @param lock A lock on QservHttpMgtRequest::_mtx must be acquired before - * calling this method. - * @param state The primary state of the request. - * @param extendedState The extended state of the request. - */ - void _setState(replica::Lock const& lock, State state, ExtendedState extendedState = ExtendedState::NONE); - - /// The global counter for the number of instances of any subclass - static std::atomic _numClassInstances; - - // Input parameters - - std::shared_ptr const _serviceProvider; - - std::string const _type; - std::string const _id; - std::string const _worker; - - // Two-level state of a request - std::atomic _state; ///< The primary state. - std::atomic _extendedState; ///< The sub-state. - - /// Error message (if any) reported by the remote service - std::string _serverError; - - Performance _performance; ///< Performance counters. - std::string _jobId; ///< An identifier of the parent job which started the request. - - std::shared_ptr _httpRequest; ///< The actual request sent to the worker. - nlohmann::json _info; ///< The data object returned by the worker. - - // Synchronization primitives for implementing QservMgtRequest::wait() - - bool _finished = false; - std::mutex _onFinishMtx; - std::condition_variable _onFinishCv; -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_QSERVHTTPMGTREQUEST_H diff --git a/src/replica/QservMgtRequest.cc b/src/replica/QservMgtRequest.cc index 2323acefea..61d6551159 100644 --- a/src/replica/QservMgtRequest.cc +++ b/src/replica/QservMgtRequest.cc @@ -23,23 +23,20 @@ #include "replica/QservMgtRequest.h" // System headers -#include #include - -// Third party headers -#include "boost/date_time/posix_time/posix_time.hpp" +#include // Qserv headers +#include "http/MetaModule.h" #include "replica/Configuration.h" #include "replica/Common.h" #include "replica/DatabaseServices.h" -#include "replica/ServiceProvider.h" // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; -using namespace std::placeholders; namespace { @@ -71,6 +68,8 @@ string QservMgtRequest::state2string(ExtendedState state) { return "SUCCESS"; case ExtendedState::CONFIG_ERROR: return "CONFIG_ERROR"; + case ExtendedState::BODY_LIMIT_ERROR: + return "BODY_LIMIT_ERROR"; case ExtendedState::SERVER_BAD: return "SERVER_BAD"; case ExtendedState::SERVER_CHUNK_IN_USE: @@ -94,29 +93,25 @@ QservMgtRequest::QservMgtRequest(ServiceProvider::Ptr const& serviceProvider, st _id(Generators::uniqueId()), _worker(worker), _state(State::CREATED), - _extendedState(ExtendedState::NONE), - _service(nullptr), - _requestExpirationIvalSec( - serviceProvider->config()->get("xrootd", "request-timeout-sec")), - _requestExpirationTimer(serviceProvider->io_service()) { + _extendedState(ExtendedState::NONE) { // This report is used solely for debugging purposes to allow tracking // potential memory leaks within applications. ++_numClassInstances; - LOGS(_log, LOG_LVL_DEBUG, context() << "constructed instances: " << _numClassInstances); + LOGS(_log, LOG_LVL_TRACE, context() << "constructed instances: " << _numClassInstances); } QservMgtRequest::~QservMgtRequest() { --_numClassInstances; - LOGS(_log, LOG_LVL_DEBUG, context() << "destructed instances: " << _numClassInstances); + LOGS(_log, LOG_LVL_TRACE, context() << "destructed instances: " << _numClassInstances); } string QservMgtRequest::state2string() const { - replica::Lock lock(_mtx, context() + __func__); + replica::Lock const lock(_mtx, context() + __func__); return state2string(state(), extendedState()) + "::" + serverError(lock); } string QservMgtRequest::serverError() const { - replica::Lock lock(_mtx, context() + __func__); + replica::Lock const lock(_mtx, context() + __func__); return serverError(lock); } @@ -127,163 +122,218 @@ string QservMgtRequest::context() const { } Performance QservMgtRequest::performance() const { - replica::Lock lock(_mtx, context() + __func__); + replica::Lock const lock(_mtx, context() + __func__); return performance(lock); } Performance QservMgtRequest::performance(replica::Lock const& lock) const { return _performance; } -void QservMgtRequest::start(XrdSsiService* service, string const& jobId, - unsigned int requestExpirationIvalSec) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - - replica::Lock lock(_mtx, "QservMgtRequest::" + string(__func__)); +void QservMgtRequest::start(string const& jobId, unsigned int requestExpirationIvalSec) { + string const context_ = context() + __func__; + LOGS(_log, LOG_LVL_TRACE, context_); - assertState(State::CREATED, "QservMgtRequest::" + string(__func__)); + replica::Lock const lock(_mtx, context_); + _assertNotStarted(__func__); // This needs to be updated to override the default value of the counter // which was created upon the object construction. - _performance.setUpdateStart(); // Check if configuration parameters are valid - - if (not(serviceProvider()->config()->isKnownWorker(worker()) and (service != nullptr))) { - LOGS(_log, LOG_LVL_ERROR, - context() << __func__ << " ** MISCONFIGURED ** " - << " worker: '" << worker() << "'" - << " XrdSsiService pointer: " << service); - - setState(lock, State::FINISHED, ExtendedState::CONFIG_ERROR); - + auto const config = _serviceProvider->config(); + if (!config->isKnownWorker(_worker)) { + LOGS(_log, LOG_LVL_ERROR, context_ << " ** MISCONFIGURED ** unknown worker: '" << _worker << "'."); + _setState(lock, State::FINISHED, ExtendedState::CONFIG_ERROR); notify(lock); return; } - // Build associations with the corresponding service and - // the job (optional) - - _service = service; + // Build an association with the corresponding parent job (optional). _jobId = jobId; - // Change the default values of the expiration ival if requested - // before starting the timer. - - if (0 != requestExpirationIvalSec) { - _requestExpirationIvalSec = requestExpirationIvalSec; + // Adjust the default value of the expiration ival (if requested) before + // creating and starting the request. + unsigned int actualExpirationIvalSec = requestExpirationIvalSec; + if (0 == actualExpirationIvalSec) { + actualExpirationIvalSec = config->get("xrootd", "request-timeout-sec"); } - if (0 != _requestExpirationIvalSec) { - _requestExpirationTimer.cancel(); - _requestExpirationTimer.expires_from_now(boost::posix_time::seconds(_requestExpirationIvalSec)); - _requestExpirationTimer.async_wait(bind(&QservMgtRequest::expired, shared_from_this(), _1)); - } - - // Let a subclass to proceed with its own sequence of actions before - // finalizing state transition and updating the persistent state. - startImpl(lock); + createHttpReqImpl(lock); - if (state() == State::FINISHED) return; + _httpRequest->setExpirationIval(actualExpirationIvalSec); + _httpRequest->start(); - setState(lock, State::IN_PROGRESS); + _setState(lock, State::IN_PROGRESS); } void QservMgtRequest::wait() { LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - - if (state() == State::FINISHED) return; - + if (_state == State::FINISHED) return; unique_lock onFinishLock(_onFinishMtx); _onFinishCv.wait(onFinishLock, [&] { return _finished; }); } string const& QservMgtRequest::jobId() const { - if (_state == State::CREATED) { - throw logic_error("Job::" + string(__func__) + - " the Job Id is not available because the request has not started yet"); - } + _assertStarted(__func__); return _jobId; } -void QservMgtRequest::expired(boost::system::error_code const& ec) { - LOGS(_log, LOG_LVL_DEBUG, - context() << __func__ << (ec == boost::asio::error::operation_aborted ? " ** ABORTED **" : "")); - - // Ignore this event if the timer was aborted - - if (ec == boost::asio::error::operation_aborted) return; - - if (state() == State::FINISHED) return; - - replica::Lock lock(_mtx, context() + __func__); - - if (state() == State::FINISHED) return; - - finish(lock, ExtendedState::TIMEOUT_EXPIRED); +json const& QservMgtRequest::info() const { + if (!((_state == State::FINISHED) && (_extendedState == ExtendedState::SUCCESS))) { + throw logic_error("QservMgtRequest::" + string(__func__) + + " no info available in state: " + state2string(_state, _extendedState)); + } + return _info; } void QservMgtRequest::cancel() { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - - if (state() == State::FINISHED) return; - - replica::Lock lock(_mtx, context() + __func__); + _assertStarted(__func__); + // No HTTP request would be sent if the request creation failed for some + // reason (like misconfiguration, etc.). Hence, there is nothing to cancel. + { + replica::Lock const lock(_mtx, context() + __func__); + if (_httpRequest == nullptr) return; + } + _httpRequest->cancel(); +} - if (state() == State::FINISHED) return; +void QservMgtRequest::createHttpReq(replica::Lock const& lock, string const& service, string const& query) { + _assertNotStarted(__func__); + string const target = service + query + string(query.empty() ? "?" : "&") + "id" + _id + + "&instance_id=" + _serviceProvider->instanceId() + "&worker=" + _worker + + "&version=" + to_string(http::MetaModule::version); + _httpRequest = http::AsyncReq::create( + _serviceProvider->io_service(), + [self = shared_from_this()](shared_ptr const&) { self->_processResponse(); }, + "GET", _getHostPortTracker(), target); +} - finish(lock, ExtendedState::CANCELLED); +void QservMgtRequest::createHttpReq(replica::Lock const& lock, string const& method, string const& target, + json const& body) { + _assertNotStarted(__func__); + json data = body; + data["id"] = _id; + data["instance_id"] = _serviceProvider->instanceId(); + data["worker"] = _worker; + data["auth_key"] = _serviceProvider->authKey(); + data["admin_auth_key"] = _serviceProvider->adminAuthKey(); + data["version"] = http::MetaModule::version; + unordered_map const headers = {{"Content-Type", "application/json"}}; + _httpRequest = http::AsyncReq::create( + _serviceProvider->io_service(), + [self = shared_from_this()](shared_ptr const&) { self->_processResponse(); }, + method, _getHostPortTracker(), target, data.dump(), headers); } void QservMgtRequest::finish(replica::Lock const& lock, ExtendedState extendedState, string const& serverError) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); - - // Set the optional server error state as well - // - // IMPORTANT: this needs to be done before performing the state - // transition to insure clients will get a consistent view onto - // the object state. + string const context_ = context() + __func__; + LOGS(_log, LOG_LVL_DEBUG, context_ << " serverError:" << serverError); + // Set the optional server error state as well. + // IMPORTANT: this needs to be done before performing the state transition to insure + // clients will get a consistent view onto the object state. _serverError = serverError; // Set new state to make sure all event handlers will recognize // this scenario and avoid making any modifications to the request's state. - - setState(lock, State::FINISHED, extendedState); - - // Close all operations on BOOST ASIO if needed - - _requestExpirationTimer.cancel(); - - // Let a subclass to run its own finalization if needed - - finishImpl(lock); + _setState(lock, State::FINISHED, extendedState); // We have to update the timestamp before invoking a user provided // callback on the completion of the operation. - _performance.setUpdateFinish(); - serviceProvider()->databaseServices()->saveState(*this, _performance, _serverError); + // TODO: temporarily disabled while this class is not supported by + // the persistent backend. + // + // _serviceProvider->databaseServices()->saveState(*this, _performance, _serverError); notify(lock); - // Unblock threads (if any) waiting on the synchronization call - // to method QservMgtRequest::wait() - + // Unblock threads (if any) waiting on the synchronization call to the method wait(). _finished = true; _onFinishCv.notify_all(); } -void QservMgtRequest::assertState(State desiredState, string const& context) const { - if (desiredState != state()) { - throw logic_error(context + ": wrong state " + state2string(state()) + " instead of " + - state2string(desiredState)); +http::AsyncReq::GetHostPort QservMgtRequest::_getHostPortTracker() const { + return [config = _serviceProvider->config(), + worker = _worker](http::AsyncReq::HostPort const&) -> http::AsyncReq::HostPort { + auto const info = config->workerInfo(worker); + return http::AsyncReq::HostPort{info.qservWorker.host.addr, info.qservWorker.port}; + }; +} + +void QservMgtRequest::_processResponse() { + string const context_ = context() + string(__func__) + " "; + if (_state == State::FINISHED) return; + replica::Lock const lock(_mtx, context_); + if (_state == State::FINISHED) return; + + switch (_httpRequest->state()) { + case http::AsyncReq::State::FINISHED: + try { + _info = json::parse(_httpRequest->responseBody()); + if (_info.at("success").get() == 0) { + string const msg = "worker reported error: " + _info.at("error").get(); + auto extendedState = ExtendedState::SERVER_BAD; + // Check for optional markers in the optional extended error section that might + // clarify an actual reason behind the failure. + if (auto const itr = _info.find("error_ext"); itr != _info.end()) { + json const errorExt = *itr; + if (errorExt.contains("in_use")) { + extendedState = ExtendedState::SERVER_CHUNK_IN_USE; + } else if (errorExt.contains("invalid_param")) { + extendedState = ExtendedState::CONFIG_ERROR; + } + } + finish(lock, extendedState, msg); + } else { + // Let a subclass do the optional result validation and post processing. + // Note that the subclass has the final say on the completion status + // of the request. + finish(lock, dataReady(lock, _info)); + } + } catch (exception const& ex) { + string const msg = "failed to parse/process worker response, ex: " + string(ex.what()); + finish(lock, ExtendedState::SERVER_BAD_RESPONSE, msg); + } + break; + case http::AsyncReq::State::FAILED: + finish(lock, ExtendedState::SERVER_ERROR, + _httpRequest->errorMessage() + ", code: " + to_string(_httpRequest->responseCode())); + break; + case http::AsyncReq::State::BODY_LIMIT_ERROR: + finish(lock, ExtendedState::BODY_LIMIT_ERROR, + _httpRequest->errorMessage() + ", code: " + to_string(_httpRequest->responseCode())); + break; + case http::AsyncReq::State::CANCELLED: + finish(lock, ExtendedState::CANCELLED); + break; + case http::AsyncReq::State::EXPIRED: + finish(lock, ExtendedState::TIMEOUT_EXPIRED); + break; + default: + throw runtime_error(context_ + "unsupported state of the HTTP _httpRequest: " + + http::AsyncReq::state2str(_httpRequest->state())); } } -void QservMgtRequest::setState(replica::Lock const& lock, State newState, ExtendedState newExtendedState) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__ << " " << state2string(newState, newExtendedState)); +void QservMgtRequest::_assertStarted(string const& func, bool mustBeStarted) const { + string const context_ = context() + func; + LOGS(_log, LOG_LVL_TRACE, context_); + if (mustBeStarted) { + if (State::CREATED == _state) { + throw logic_error(context_ + " the request was not started."); + } + } else { + if (State::CREATED != _state) { + throw logic_error(context_ + " the request was already started."); + } + } +} + +void QservMgtRequest::_setState(replica::Lock const& lock, State newState, ExtendedState newExtendedState) { + LOGS(_log, LOG_LVL_TRACE, context() << __func__ << " " << state2string(newState, newExtendedState)); // IMPORTANT: the top-level state is the last to be set when performing // the state transition to insure clients will get a consistent view onto @@ -293,7 +343,11 @@ void QservMgtRequest::setState(replica::Lock const& lock, State newState, Extend _extendedState = newExtendedState; _state = newState; } - serviceProvider()->databaseServices()->saveState(*this, _performance, _serverError); + + // TODO: temporarily disabled while this class is not supported by + // the persistent backend. + // + // _serviceProvider->databaseServices()->saveState(*this, _performance, _serverError); } } // namespace lsst::qserv::replica diff --git a/src/replica/QservMgtRequest.h b/src/replica/QservMgtRequest.h index 6824f6a3df..5f25776270 100644 --- a/src/replica/QservMgtRequest.h +++ b/src/replica/QservMgtRequest.h @@ -26,27 +26,25 @@ #include #include #include +#include #include -#include #include -// THird party headers -#include "boost/asio.hpp" +// Third party headers +#include "nlohmann/json.hpp" // Qserv headers +#include "http/AsyncReq.h" +#include "replica/Mutex.h" #include "replica/Performance.h" #include "replica/ServiceProvider.h" -#include "replica/Mutex.h" - -// Forward declarations -class XrdSsiService; // This header declarations namespace lsst::qserv::replica { /** - * Class QservMgtRequest is a base class for a family of the Qserv worker - * management requests within the master server. + * @brief QservMgtRequest is a base class for a family of the Qserv worker + * management requests within the master server. */ class QservMgtRequest : public std::enable_shared_from_this { public: @@ -57,16 +55,11 @@ class QservMgtRequest : public std::enable_shared_from_this { /// The type which represents the primary public state of the request enum State { - /// The request has been constructed, and no attempt to execute it has - /// been made. - CREATED, - - /// The request is in a progress - IN_PROGRESS, - - /// The request is finished. See extended status for more details - /// (the completion status, etc.) - FINISHED + CREATED, ///< The request has been constructed, and no attempt to execute + /// it has been made. + IN_PROGRESS, ///< The request is in a progress. + FINISHED ///< The request is finished. See extended status for more details + /// (the completion status, etc.) }; /// @return the string representation of the primary state @@ -75,35 +68,19 @@ class QservMgtRequest : public std::enable_shared_from_this { /// Type ExtendedState represents the refined public sub-state of the request /// once it's FINISHED as per the above defined primary state. enum ExtendedState { - /// No extended state exists at this time - NONE, - - /// The request has been fully implemented - SUCCESS, - - /// Problems with request configuration found - CONFIG_ERROR, - - /// Server reports that the request can not be implemented due to incorrect - /// parameters, etc. - SERVER_BAD, - - /// Server reports that the request can not be implemented because - /// some of the required remote resources (chunks, etc.) are in use. - SERVER_CHUNK_IN_USE, - - /// The request could not be implemented due to an unrecoverable - /// server-side error. - SERVER_ERROR, - - /// Data received from a server can't be correctly interpreted - SERVER_BAD_RESPONSE, - - /// Expired due to a timeout (as per the Configuration) - TIMEOUT_EXPIRED, - - /// Explicitly cancelled on the client-side (similar to TIMEOUT_EXPIRED) - CANCELLED + NONE, ///< No extended state exists at this time. + SUCCESS, ///< The request has been fully implemented. + CONFIG_ERROR, ///< Problems with request configuration were detected. + BODY_LIMIT_ERROR, ///< Response's body is larger than requested. + SERVER_BAD, ///< Server reports that the request can not be implemented because + /// of configuration or request's parameters problems. + SERVER_CHUNK_IN_USE, ///< Server reports that the request can not be implemented because + /// some of the required remote resources (chunks, etc.) are in use. + SERVER_ERROR, ///< The request could not be implemented due to an unrecoverable + /// server-side error. + SERVER_BAD_RESPONSE, ///< Data received from a server can't be correctly interpreted. + TIMEOUT_EXPIRED, ///< Expired due to a timeout. + CANCELLED ///< Explicitly cancelled on the client-side. }; /// @return the string representation of the extended state @@ -121,7 +98,7 @@ class QservMgtRequest : public std::enable_shared_from_this { virtual ~QservMgtRequest(); /// @return reference to a provider of services - ServiceProvider::Ptr const& serviceProvider() { return _serviceProvider; } + std::shared_ptr const& serviceProvider() { return _serviceProvider; } /// @return string representing of the request type. std::string const& type() const { return _type; } @@ -148,59 +125,52 @@ class QservMgtRequest : public std::enable_shared_from_this { Performance performance() const; /** - * Return an identifier if the owning job (if the request has started) - * - * @throws std::logic_error - if the request hasn't started + * @return An identifier if the owning job (if the request has started). + * @throws std::logic_error If the request hasn't started. */ std::string const& jobId() const; /** - * Reset the state (if needed) and begin processing the request. - * - * This is supposed to be the first operation to be called upon a creation - * of the request. A caller is expected to provide a pointer to an instance - * of the XrdSsiService class for communications with the remote services. - * - * @param service - a pointer to an instance of the API object for - * submitting requests to remote services - * @param jobId - an optional identifier of a job specifying a context - * in which a request will be executed. - * @param requestExpirationIvalSec - an optional parameter (if differs from 0) - * allowing to override the default value of - * the corresponding parameter from the Configuration. + * @return The info object returned by the worker. + * @throw std::logic_error if called before the request finishes or if it failed. */ - void start(XrdSsiService* service, std::string const& jobId = "", - unsigned int requestExpirationIvalSec = 0); + nlohmann::json const& info() const; + + /** + * @brief Begin processing the request. + * @param jobId (Optional) identifier of a job specifying a context of the request. + * @param requestExpirationIvalSec (Optional) parameter (if differs from 0) allowing + * to override the default value of the corresponding parameter from the Configuration. + */ + void start(std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); /// Wait for the completion of the request void wait(); /** - * Explicitly cancel any asynchronous operation(s) and put the object into - * the FINISHED::CANCELLED state. This operation is very similar to the - * timeout-based request expiration, except it's requested explicitly. + * @brief Explicitly cancel any asynchronous operation(s) and put the object into + * the FINISHED::CANCELLED state. This operation is very similar to the + * timeout-based request expiration, except it's requested explicitly. */ void cancel(); /// @return The context string for debugging and diagnostic printouts. std::string context() const; - /** - * @return A dictionary of parameters and the corresponding values to - * be stored in a database for a request. - */ + /// @return A dictionary of parameters and the corresponding values to be stored + /// in a database for a request. virtual std::list> extendedPersistentState() const { return std::list>(); } protected: /** - * Construct the request with the pointer to the services provider. + * @brief Construct the request with the pointer to the services provider. * @param serviceProvider Is required to access configuration services. * @param type The type name of he request (used for debugging and error reporting). * @param worker The name of a worker. */ - QservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& type, + QservMgtRequest(std::shared_ptr const& serviceProvider, std::string const& type, std::string const& worker); /// @return A shared pointer of the desired subclass (no dynamic type checking). @@ -209,50 +179,80 @@ class QservMgtRequest : public std::enable_shared_from_this { return std::static_pointer_cast(shared_from_this()); } - /// @return The API for submitting requests to the remote services. - XrdSsiService* service() { return _service; } + /** + * @brief Create an HTTP request. + * + * The methods is required to be provided by subclasses for creating + * subclass-specific requests using the coresponding helper methods. + * + * @see QservMgtRequest::createHttpReq + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + */ + virtual void createHttpReqImpl(replica::Lock const& lock) = 0; /** - * This method is supposed to be provided by subclasses for additional - * subclass-specific actions to begin processing the request. - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. + * @brief Create an HTTP "GET" request, but do not start it yet. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + * @param service The REST service (w/o the query part) to be called. + * @param (optional) HTTP query for the request. + * @throw std::logic_error If the method is called while the curent state + * is not State::CREATED, or if the HTTP request was already created. */ - virtual void startImpl(replica::Lock const& lock) = 0; + void createHttpReq(replica::Lock const& lock, std::string const& service, + std::string const& query = std::string()); /** - * Request expiration timer's handler. The expiration interval (if any) - * is configured via the configuration service. When the request expires - * it finishes with completion status FINISHED::TIMEOUT_EXPIRED. - * @param ec A error code to be checked. + * @brief Create an HTTP request ("POST", "PUT" or "DELETE") that has the JSON body, + * but do not start it yet. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + * @param method An HTTP method ("POST", "PUT" or "DELETE") for the request, + * @param service The complete target (including the REST service and the query part) to be called. + * @param body A JSON object to be sent in the request's body. + * @throw std::logic_error If the method is called while the curent state + * is not State::CREATED, or if the HTTP request was already created. */ - void expired(boost::system::error_code const& ec); + void createHttpReq(replica::Lock const& lock, std::string const& method, std::string const& target, + nlohmann::json const& body); /** - * Finalize request processing (as reported by subclasses) + * @brief Notify a subclass that a data object was was succesfully retrieved + * from the worker. * - * This is supposed to be the last operation to be called by subclasses - * upon a completion of the request. + * This method allows subclasses to implement the optional result validation and processing, + * including a translation of the JSON object into the subclas-specific result type. * - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. - * @param extendedState The new extended state. - * @param serverError (optional) error message from a Qserv worker service. + * @note Any exceptions thrown by the method will result in setting the status + * ExtendedState::SERVER_BAD_RESPONSE to indicate a problem with interpreting the data. + * The method is also required to report its final verdican on the status of the object. + * Normally, it's going to be ExtendedState::SUCCESS. However, a subclass may set + * a different status, depending on its findings. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + * @param data The JSON result to be processed by a subclass. + * @return The final verdict made by the subclass on the completion status. */ - void finish(replica::Lock const& lock, ExtendedState extendedState, std::string const& serverError = ""); + virtual ExtendedState dataReady(replica::Lock const& lock, nlohmann::json const& data) { + return ExtendedState::SUCCESS; + } /** - * This method is supposed to be provided by subclasses - * to finalize request processing as required by the subclass. - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. + * @brief Finalize request processing (as reported by subclasses) + * @note This is supposed to be the last operation to be called by subclasses + * upon a completion of the request. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + * @param extendedState The new extended state. + * @param serverError (optional) error message from a Qserv worker service. */ - virtual void finishImpl(replica::Lock const& lock) = 0; + void finish(replica::Lock const& lock, ExtendedState extendedState, std::string const& serverError = ""); /** - * Start user-notification protocol (in case if user-defined notifiers - * were provided to a subclass). The callback is expected to be made - * asynchronously in a separate thread to avoid blocking the current thread. + * @brief Start user-notification protocol (in case if user-defined notifiers + * were provided to a subclass). The callback is expected to be made + * asynchronously in a separate thread to avoid blocking the current thread. * * This method has to be provided by subclasses to forward * notification on request completion to a client which initiated @@ -266,14 +266,13 @@ class QservMgtRequest : public std::enable_shared_from_this { * } * @code * @see QservMgtRequest::notifyDefaultImpl - * - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. */ virtual void notify(replica::Lock const& lock) = 0; /** - * The helper function which pushes up-stream notifications on behalf of + * @brief The helper function which pushes up-stream notifications on behalf of * subclasses. Upon a completion of this method the callback function * object will get reset to 'nullptr'. * @note This default implementation works for callback functions which @@ -281,8 +280,8 @@ class QservMgtRequest : public std::enable_shared_from_this { * the corresponding subclass. Subclasses with more complex signatures of * their callbacks should have their own implementations which may look * similarly to this one. - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. * @param onFinish A callback function (if set) to be called. */ template @@ -299,40 +298,15 @@ class QservMgtRequest : public std::enable_shared_from_this { } /** - * Ensure the object is in the desired internal state. Throw an - * exception otherwise. - * @note Normally this condition should never been seen unless there is a problem with - * the application implementation or the underlying run-time system. - * @param desiredState The desired state of the request. - * @param context A context from which the state test is requested. - * @throws std::logic_error - */ - void assertState(State desiredState, std::string const& context) const; - - /** - * Set the desired primary and extended state. - * - * The change of the state is done via a method to allow extra actions - * at this step, such as: - * - reporting change state in a debug stream - * - verifying the correctness of the state transition - * - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. - * @param state The primary state of the request. - * @param extendedState The extended state of the request. - */ - void setState(replica::Lock const& lock, State state, ExtendedState extendedState = ExtendedState::NONE); - - /** - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling this method. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. * @return A server error string (if any). */ std::string serverError(replica::Lock const& lock) const; /** - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling - * this method. + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. * @return The performance info. */ Performance performance(replica::Lock const& lock) const; @@ -341,42 +315,69 @@ class QservMgtRequest : public std::enable_shared_from_this { mutable replica::Mutex _mtx; private: + /// @return The callback function for tracking connection parameters of the worker. + http::AsyncReq::GetHostPort _getHostPortTracker() const; + + /// Extract and process data of the completed request. Notify a subclass in case of success. + void _processResponse(); + + /** + * @brief Ensure the request is in the desired state. + * @note The method doesn't require a lock on the mutex _mtx to be acqured before + * being called neither it acquires the lock by itself since the implementation + * of the method relies on checking a value of the atomic variable representing + * the primary state of the request. + * @param func A context from which the state test is requested (for tracing + * and error reporting). + * @param mustBeStarted 'true' if the request is expected to be in any + * state past State::CREATED, or 'false' if it's expected to be exactly + * in State::CREATED. + * @throws std::logic_error If the request was not found in the desired state. + */ + void _assertStarted(std::string const& func, bool mustBeStarted) const; + + // Shortcut methods based on the above defined one. + + void _assertStarted(std::string const& func) const { _assertStarted(func, true); } + void _assertNotStarted(std::string const& func) const { _assertStarted(func, false); } + + /** + * @brief Set the desired primary and extended state. + * + * The change of the state is done via a method to allow extra actions + * at this step, such as: 1) reporting change state in a debug stream, + * or 2) verifying the correctness of the state transition. + * + * @param lock A lock on QservMgtRequest::_mtx must be acquired before + * calling this method. + * @param state The primary state of the request. + * @param extendedState The extended state of the request. + */ + void _setState(replica::Lock const& lock, State state, ExtendedState extendedState = ExtendedState::NONE); + /// The global counter for the number of instances of any subclass static std::atomic _numClassInstances; // Input parameters - ServiceProvider::Ptr const _serviceProvider; + std::shared_ptr const _serviceProvider; std::string const _type; std::string const _id; std::string const _worker; // Two-level state of a request - - std::atomic _state; - std::atomic _extendedState; + std::atomic _state; ///< The primary state. + std::atomic _extendedState; ///< The sub-state. /// Error message (if any) reported by the remote service std::string _serverError; - /// Performance counters - Performance _performance; - - /// An identifier of the parent job which started the request - std::string _jobId; - - /// An API for submitting requests to the remote services - XrdSsiService* _service; + Performance _performance; ///< Performance counters. + std::string _jobId; ///< An identifier of the parent job which started the request. - /// This timer is used (if configured) to limit the total run time - /// of a request. The timer starts when the request is started. And it's - /// explicitly finished when a request finishes (successfully or not). - /// - /// If the time has a chance to expire then the request would finish - /// with status: FINISHED::TIMEOUT_EXPIRED. - unsigned int _requestExpirationIvalSec; - boost::asio::deadline_timer _requestExpirationTimer; + std::shared_ptr _httpRequest; ///< The actual request sent to the worker. + nlohmann::json _info; ///< The data object returned by the worker. // Synchronization primitives for implementing QservMgtRequest::wait() diff --git a/src/replica/QservMgtServices.cc b/src/replica/QservMgtServices.cc index 86f5f13316..4cc2618553 100644 --- a/src/replica/QservMgtServices.cc +++ b/src/replica/QservMgtServices.cc @@ -24,27 +24,10 @@ // System headers #include -#include - -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "http/MetaModule.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" -#include "util/BlockPost.h" -#include "util/TimeUtils.h" -#include "wbase/TaskState.h" // LSST headers #include "lsst/log/Log.h" -/// This C++ symbol is provided by the SSI shared library -extern XrdSsiProvider* XrdSsiProviderClient; - -using namespace lsst::qserv; using namespace std; namespace { @@ -55,99 +38,23 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.QservMgtServices"); namespace lsst::qserv::replica { -////////////////////////////////////////////////////////////////////////////////// -////////////////////////// QservMgtRequestWrapperImpl ////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Request-type specific wrappers - */ -template -struct QservMgtRequestWrapperImpl : QservMgtRequestWrapper { - /// The implementation of the virtual method defined in the base class - void notify() const final { - if (nullptr != _onFinish) { - // Clearing the stored callback after finishing the up-stream notification - // has two purposes: - // - // 1. it guaranties (exactly) one time notification - // 2. it breaks the up-stream dependency on a caller object if a shared - // pointer to the object was mentioned as the lambda-function's closure - - auto onFinish = move(_onFinish); - _onFinish = nullptr; - onFinish(_request); - } - } - - QservMgtRequestWrapperImpl(typename T::Ptr const& request, typename T::CallbackType const& onFinish) - : QservMgtRequestWrapper(), _request(request), _onFinish(onFinish) {} - - /// Destructor - ~QservMgtRequestWrapperImpl() = default; - - /// Implement a virtual method of the base class - shared_ptr request() const override { return _request; } - -private: - // The context of the operation - - typename T::Ptr _request; - mutable typename T::CallbackType _onFinish; -}; - -//////////////////////////////////////////////////////////////////////// -////////////////////////// QservMgtServices ////////////////////////// -//////////////////////////////////////////////////////////////////////// - -QservMgtServices::Ptr QservMgtServices::create(ServiceProvider::Ptr const& serviceProvider) { +QservMgtServices::Ptr QservMgtServices::create(shared_ptr const& serviceProvider) { return QservMgtServices::Ptr(new QservMgtServices(serviceProvider)); } -QservMgtServices::QservMgtServices(ServiceProvider::Ptr const& serviceProvider) +QservMgtServices::QservMgtServices(shared_ptr const& serviceProvider) : _serviceProvider(serviceProvider) {} AddReplicaQservMgtRequest::Ptr QservMgtServices::addReplica( unsigned int chunk, vector const& databases, string const& worker, AddReplicaQservMgtRequest::CallbackType const& onFinish, string const& jobId, unsigned int requestExpirationIvalSec) { - AddReplicaQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = AddReplicaQservMgtRequest::create( - serviceProvider(), worker, chunk, databases, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -AddReplicaQservHttpMgtRequest::Ptr QservMgtServices::addReplicaOverHttp( - unsigned int chunk, vector const& databases, string const& worker, - AddReplicaQservHttpMgtRequest::CallbackType const& onFinish, string const& jobId, - unsigned int requestExpirationIvalSec) { - auto request = - AddReplicaQservHttpMgtRequest::create(serviceProvider(), worker, chunk, databases, onFinish); + auto const request = AddReplicaQservMgtRequest::create( + serviceProvider(), worker, chunk, databases, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -156,43 +63,13 @@ RemoveReplicaQservMgtRequest::Ptr QservMgtServices::removeReplica( unsigned int chunk, vector const& databases, string const& worker, bool force, RemoveReplicaQservMgtRequest::CallbackType const& onFinish, string const& jobId, unsigned int requestExpirationIvalSec) { - RemoveReplicaQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); + auto const request = RemoveReplicaQservMgtRequest::create( + serviceProvider(), worker, chunk, databases, force, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); - request = RemoveReplicaQservMgtRequest::create( - serviceProvider(), worker, chunk, databases, force, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -RemoveReplicaQservHttpMgtRequest::Ptr QservMgtServices::removeReplicaOverHttp( - unsigned int chunk, vector const& databases, string const& worker, bool force, - RemoveReplicaQservHttpMgtRequest::CallbackType const& onFinish, string const& jobId, - unsigned int requestExpirationIvalSec) { - auto request = RemoveReplicaQservHttpMgtRequest::create(serviceProvider(), worker, chunk, databases, - force, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -200,42 +77,12 @@ RemoveReplicaQservHttpMgtRequest::Ptr QservMgtServices::removeReplicaOverHttp( GetReplicasQservMgtRequest::Ptr QservMgtServices::getReplicas( string const& databaseFamily, string const& worker, bool inUseOnly, string const& jobId, GetReplicasQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - GetReplicasQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = GetReplicasQservMgtRequest::create( - serviceProvider(), worker, databaseFamily, inUseOnly, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -GetReplicasQservHttpMgtRequest::Ptr QservMgtServices::getReplicasOverHttp( - string const& databaseFamily, string const& worker, bool inUseOnly, string const& jobId, - GetReplicasQservHttpMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - auto request = GetReplicasQservHttpMgtRequest::create(serviceProvider(), worker, databaseFamily, - inUseOnly, onFinish); + auto const request = GetReplicasQservMgtRequest::create( + serviceProvider(), worker, databaseFamily, inUseOnly, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -244,43 +91,12 @@ SetReplicasQservMgtRequest::Ptr QservMgtServices::setReplicas( string const& worker, QservReplicaCollection const& newReplicas, vector const& databases, bool force, string const& jobId, SetReplicasQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - SetReplicasQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = SetReplicasQservMgtRequest::create( - serviceProvider(), worker, newReplicas, databases, force, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -SetReplicasQservHttpMgtRequest::Ptr QservMgtServices::setReplicasOverHttp( - string const& worker, QservReplicaCollection const& newReplicas, vector const& databases, - bool force, string const& jobId, SetReplicasQservHttpMgtRequest::CallbackType const& onFinish, - unsigned int requestExpirationIvalSec) { - auto request = SetReplicasQservHttpMgtRequest::create(serviceProvider(), worker, newReplicas, databases, - force, onFinish); + auto const request = SetReplicasQservMgtRequest::create( + serviceProvider(), worker, newReplicas, databases, force, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -289,41 +105,12 @@ TestEchoQservMgtRequest::Ptr QservMgtServices::echo(string const& worker, string string const& jobId, TestEchoQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - TestEchoQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = TestEchoQservMgtRequest::create( - serviceProvider(), worker, data, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -TestEchoQservHttpMgtRequest::Ptr QservMgtServices::echoOverHttp( - string const& worker, string const& data, string const& jobId, - TestEchoQservHttpMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - auto request = TestEchoQservHttpMgtRequest::create(serviceProvider(), worker, data, onFinish); + auto const request = + TestEchoQservMgtRequest::create(serviceProvider(), worker, data, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -332,41 +119,12 @@ GetStatusQservMgtRequest::Ptr QservMgtServices::status(string const& worker, str wbase::TaskSelector const& taskSelector, GetStatusQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - GetStatusQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = GetStatusQservMgtRequest::create( - serviceProvider(), worker, taskSelector, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -GetStatusQservHttpMgtRequest::Ptr QservMgtServices::statusOverHttp( - string const& worker, string const& jobId, wbase::TaskSelector const& taskSelector, - GetStatusQservHttpMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - auto request = GetStatusQservHttpMgtRequest::create(serviceProvider(), worker, taskSelector, onFinish); + auto const request = GetStatusQservMgtRequest::create( + serviceProvider(), worker, taskSelector, + [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -374,41 +132,11 @@ GetStatusQservHttpMgtRequest::Ptr QservMgtServices::statusOverHttp( GetDbStatusQservMgtRequest::Ptr QservMgtServices::databaseStatus( string const& worker, string const& jobId, GetDbStatusQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - GetDbStatusQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = GetDbStatusQservMgtRequest::create( - serviceProvider(), worker, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - - return request; -} - -GetDbStatusQservHttpMgtRequest::Ptr QservMgtServices::databaseStatusOverHttp( - string const& worker, string const& jobId, - GetDbStatusQservHttpMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - auto request = GetDbStatusQservHttpMgtRequest::create(serviceProvider(), worker, onFinish); + auto const request = GetDbStatusQservMgtRequest::create( + serviceProvider(), worker, [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } @@ -416,117 +144,34 @@ GetDbStatusQservHttpMgtRequest::Ptr QservMgtServices::databaseStatusOverHttp( GetConfigQservMgtRequest::Ptr QservMgtServices::config(string const& worker, string const& jobId, GetConfigQservMgtRequest::CallbackType const& onFinish, unsigned int requestExpirationIvalSec) { - GetConfigQservMgtRequest::Ptr request; - - // Make sure the XROOTD/SSI service is available before attempting - // any operations on requests - XrdSsiService* service = _xrdSsiService(); - if (not service) { - return request; - } else { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - auto const manager = shared_from_this(); - - request = GetConfigQservMgtRequest::create( - serviceProvider(), worker, - [manager](QservMgtRequest::Ptr const& request) { manager->_finish(request->id()); }); - - // Register the request (along with its callback) by its unique - // identifier in the local registry. Once it's complete it'll - // be automatically removed from the Registry. - _registry[request->id()] = - make_shared>(request, onFinish); - } - - // Initiate the request in the lock-free zone to avoid blocking the service - // from initiating other requests which this one is starting. - request->start(service, jobId, requestExpirationIvalSec); - return request; -} - -GetConfigQservHttpMgtRequest::Ptr QservMgtServices::configOverHttp( - string const& worker, string const& jobId, GetConfigQservHttpMgtRequest::CallbackType const& onFinish, - unsigned int requestExpirationIvalSec) { - auto request = GetConfigQservHttpMgtRequest::create(serviceProvider(), worker, onFinish); + auto const request = GetConfigQservMgtRequest::create( + serviceProvider(), worker, [self = shared_from_this()](QservMgtRequest::Ptr const& request) { + self->_finish(request->id()); + }); + _register(__func__, request, onFinish); request->start(jobId, requestExpirationIvalSec); return request; } void QservMgtServices::_finish(string const& id) { - string const context = id + " QservMgtServices::" + string(__func__) + " "; - - LOGS(_log, LOG_LVL_DEBUG, context); - - // IMPORTANT: - // - // Make sure the notification is complete before removing - // the request from the registry. This has two reasons: - // - // - it will avoid a possibility of deadlocking in case if - // the callback function to be notified will be doing - // any API calls of the service manager. - // - // - it will reduce the controller API dead-time due to a prolonged - // execution time of of the callback function. - - QservMgtRequestWrapper::Ptr requestWrapper; + string const context = "QservMgtServices::" + string(__func__) + "[" + id + "] "; + LOGS(_log, LOG_LVL_TRACE, context); + + // IMPORTANT: Make sure the notification is complete before removing the request + // from the registry. This has two reasons: + // - it will avoid a possibility of deadlocking in case if the callback function + // to be notified will be doing any API calls of the service manager. + // - it will reduce the controller API dead-time due to a prolonged execution + // time of the callback function. + detail::QservMgtRequestWrapper::Ptr requestWrapper; { - replica::Lock lock(_mtx, context); + replica::Lock const lock(_mtx, context); auto&& itr = _registry.find(id); - if (itr == _registry.end()) { - throw logic_error("QservMgtServices::" + string(__func__) + " request identifier " + id + - " is no longer valid. Check the logic of the application."); - } + if (itr == _registry.end()) throw logic_error(context + "unklnown request."); requestWrapper = itr->second; _registry.erase(id); } requestWrapper->notify(); } -XrdSsiService* QservMgtServices::_xrdSsiService() { - replica::Lock lock(_mtx, "QservMgtServices::" + string(__func__)); - - if (_service != nullptr) return _service; - - string const serviceProviderLocation = - serviceProvider()->config()->get("xrootd", "host") + ":" + - to_string(serviceProvider()->config()->get("xrootd", "port")); - - XrdSsiErrInfo errInfo; - unsigned int const intervalBetweenReconnectsMs = 1000; - uint64_t const startedConnectionAttemptsSec = util::TimeUtils::now() / 1000; - unsigned int numAttempts = 0; - while (true) { - ++numAttempts; - _service = XrdSsiProviderClient->GetService(errInfo, serviceProviderLocation); - if (_service != nullptr) break; // success - - // Allow another try after waiting for the given reconnection interval if - // allowed and while the configuration-specified timeout has not been expired. - - uint64_t const timeSinceStartedSec = util::TimeUtils::now() / 1000 - startedConnectionAttemptsSec; - - if (serviceProvider()->config()->get("xrootd", "allow-reconnect") && - timeSinceStartedSec < - serviceProvider()->config()->get("xrootd", "reconnect-timeout")) { - LOGS(_log, LOG_LVL_WARN, - "QservMgtServices::" << __func__ << " failed to contact service provider at: " - << serviceProviderLocation << ", error: " << errInfo.Get() - << ", total of " << numAttempts << " failed connection attempts."); - - util::BlockPost::wait(intervalBetweenReconnectsMs); - continue; - } - string const errMsg = "QservMgtServices::" + string(__func__) + - " failed to contact service provider at: " + serviceProviderLocation + - ", error: " + - string(errInfo.Get() + ", aborting after " + to_string(numAttempts) + - " failed connection attempts."); - LOGS(_log, LOG_LVL_ERROR, errMsg); - throw QservMgtConnectionError(errMsg); - } - return _service; -} - } // namespace lsst::qserv::replica diff --git a/src/replica/QservMgtServices.h b/src/replica/QservMgtServices.h index c865e9be47..9366aeda1c 100644 --- a/src/replica/QservMgtServices.h +++ b/src/replica/QservMgtServices.h @@ -24,26 +24,16 @@ // System headers #include #include -#include #include // Qserv headers -#include "replica/AddReplicaQservHttpMgtRequest.h" #include "replica/AddReplicaQservMgtRequest.h" -#include "replica/GetReplicasQservHttpMgtRequest.h" #include "replica/GetReplicasQservMgtRequest.h" -#include "replica/GetDbStatusQservHttpMgtRequest.h" #include "replica/GetDbStatusQservMgtRequest.h" -#include "replica/GetConfigQservHttpMgtRequest.h" #include "replica/GetConfigQservMgtRequest.h" -#include "replica/GetStatusQservHttpMgtRequest.h" #include "replica/GetStatusQservMgtRequest.h" -#include "replica/RemoveReplicaQservHttpMgtRequest.h" #include "replica/RemoveReplicaQservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "replica/SetReplicasQservHttpMgtRequest.h" #include "replica/SetReplicasQservMgtRequest.h" -#include "replica/TestEchoQservHttpMgtRequest.h" #include "replica/TestEchoQservMgtRequest.h" #include "replica/Mutex.h" #include "wbase/TaskState.h" @@ -51,31 +41,33 @@ // Forward declarations class XrdSsiService; -namespace lsst::qserv::base { +namespace lsst::qserv::wbase { class TaskSelector; -} // namespace lsst::qserv::base +} // namespace lsst::qserv::wbase -// This header declarations namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica -/** - * For exceptions thrown on unrecoverable connection failures to XRootD/SSI services. - */ -class QservMgtConnectionError : public std::runtime_error { -public: - using std::runtime_error::runtime_error; -}; +// This header declarations +namespace lsst::qserv::replica { +namespace detail { /** - * Structure QservMgtRequestWrapper is an abstract base for implementing requests + * Class QservMgtRequestWrapper is an abstract base for implementing requests * registry as a polymorphic collection to store active requests. Pure virtual * methods of the class will be overridden by request-type-specific implementations * (see structure RequestWrappeImplr in the .cc file) capturing * type-dependent pointer and a callback function. */ -struct QservMgtRequestWrapper { +class QservMgtRequestWrapper { +public: typedef std::shared_ptr Ptr; + QservMgtRequestWrapper() = default; + QservMgtRequestWrapper(QservMgtRequestWrapper const&) = delete; + QservMgtRequestWrapper& operator=(QservMgtRequestWrapper const&) = delete; + virtual ~QservMgtRequestWrapper() = default; /** @@ -88,6 +80,44 @@ struct QservMgtRequestWrapper { virtual std::shared_ptr request() const = 0; }; +/** + * Class QservMgtRequestWrapperImpl represents request-type specific wrappers. + */ +template +class QservMgtRequestWrapperImpl : public QservMgtRequestWrapper { +public: + QservMgtRequestWrapperImpl() = delete; + QservMgtRequestWrapperImpl(QservMgtRequestWrapperImpl const&) = delete; + QservMgtRequestWrapperImpl& operator=(QservMgtRequestWrapperImpl const&) = delete; + + QservMgtRequestWrapperImpl(typename T::Ptr const& request, typename T::CallbackType const& onFinish) + : QservMgtRequestWrapper(), _request(request), _onFinish(onFinish) {} + + virtual ~QservMgtRequestWrapperImpl() final = default; + + /// The implementation of the virtual method defined in the base class + virtual void notify() const final { + if (nullptr != _onFinish) { + // Clearing the stored callback after finishing the up-stream notification + // has two purposes: + // 1. it guaranties (exactly) one time notification + // 2. it breaks the up-stream dependency on a caller object if a shared + // pointer to the object was mentioned as the lambda-function's closure + auto onFinish = std::move(_onFinish); + _onFinish = nullptr; + onFinish(_request); + } + } + + /// Implement a virtual method of the base class + virtual std::shared_ptr request() const final { return _request; } + +private: + typename T::Ptr _request; + mutable typename T::CallbackType _onFinish; +}; +} // namespace detail + /** * Class QservMgtServices is a high-level interface to the Qserv management * services used by the replication system. @@ -99,11 +129,10 @@ class QservMgtServices : public std::enable_shared_from_this { /** * The factory method for instantiating a proper service object based * on an application configuration. - * * @param serviceProvider Is required for accessing configuration parameters. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider); + static Ptr create(std::shared_ptr const& serviceProvider); QservMgtServices() = delete; QservMgtServices(QservMgtServices const&) = delete; @@ -112,11 +141,10 @@ class QservMgtServices : public std::enable_shared_from_this { ~QservMgtServices() = default; /// @return reference to the ServiceProvider object - ServiceProvider::Ptr const& serviceProvider() const { return _serviceProvider; } + std::shared_ptr const& serviceProvider() const { return _serviceProvider; } /** * Notify Qserv worker on availability of a new replica - * * @param chunk The chunk whose replica will be enabled on the Qserv worker. * @param databases The names of databases. * @param worker The name of a worker where the replica is residing. @@ -134,14 +162,8 @@ class QservMgtServices : public std::enable_shared_from_this { AddReplicaQservMgtRequest::CallbackType const& onFinish = nullptr, std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); - AddReplicaQservHttpMgtRequest::Ptr addReplicaOverHttp( - unsigned int chunk, std::vector const& databases, std::string const& worker, - AddReplicaQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); - /** * Notify Qserv worker on a removal of a replica - * * @param chunk The chunk whose replicas will be disabled at the Qserv worker. * @param databases The names of databases. * @param worker The name of a worker where the replica is residing. @@ -161,14 +183,8 @@ class QservMgtServices : public std::enable_shared_from_this { bool force, RemoveReplicaQservMgtRequest::CallbackType const& onFinish = nullptr, std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); - RemoveReplicaQservHttpMgtRequest::Ptr removeReplicaOverHttp( - unsigned int chunk, std::vector const& databases, std::string const& worker, - bool force, RemoveReplicaQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - std::string const& jobId = "", unsigned int requestExpirationIvalSec = 0); - /** * Fetch replicas known to a Qserv worker - * * @param databaseFamily The name of a database family. * @param worker The name of a worker. * @param inUseOnly A flag telling the method to return replicas which are @@ -187,15 +203,8 @@ class QservMgtServices : public std::enable_shared_from_this { std::string const& jobId = "", GetReplicasQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - GetReplicasQservHttpMgtRequest::Ptr getReplicasOverHttp( - std::string const& databaseFamily, std::string const& worker, bool inUseOnly = false, - std::string const& jobId = "", - GetReplicasQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - /** * Enable a collection of replicas at a Qserv worker - * * @param worker The name of a worker. * @param newReplicas A collection of new replicas (NOTE: useCount field is ignored). * @param databases The names of databases to be affected by the request, @@ -216,15 +225,8 @@ class QservMgtServices : public std::enable_shared_from_this { SetReplicasQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - SetReplicasQservHttpMgtRequest::Ptr setReplicasOverHttp( - std::string const& worker, QservReplicaCollection const& newReplicas, - std::vector const& databases, bool force = false, std::string const& jobId = "", - SetReplicasQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - /** * Send a data string to a Qserv worker and get the same string in response - * * @param worker The name of a worker. * @param data The data string to be sent to a worker. * @param onFinish A callback function to be called upon request completion. @@ -241,14 +243,8 @@ class QservMgtServices : public std::enable_shared_from_this { TestEchoQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - TestEchoQservHttpMgtRequest::Ptr echoOverHttp( - std::string const& worker, std::string const& data, std::string const& jobId = "", - TestEchoQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - /** * Request detailed status of a Qserv worker - * * @param worker The name of a worker. * @param jobId An optional identifier of a job specifying a context in which * a request will be executed. @@ -265,15 +261,8 @@ class QservMgtServices : public std::enable_shared_from_this { GetStatusQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - GetStatusQservHttpMgtRequest::Ptr statusOverHttp( - std::string const& worker, std::string const& jobId = "", - wbase::TaskSelector const& taskSelector = wbase::TaskSelector(), - GetStatusQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - /** * Request detailed status on the database service of a Qserv worker - * * @param worker The name of a worker. * @param jobId An optional identifier of a job specifying a context in which * a request will be executed. @@ -289,14 +278,8 @@ class QservMgtServices : public std::enable_shared_from_this { GetDbStatusQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - GetDbStatusQservHttpMgtRequest::Ptr databaseStatusOverHttp( - std::string const& worker, std::string const& jobId = "", - GetDbStatusQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - /** * Request configuration parameters of a Qserv worker - * * @param worker The name of a worker. * @param jobId An optional identifier of a job specifying a context in which * a request will be executed. @@ -311,46 +294,42 @@ class QservMgtServices : public std::enable_shared_from_this { GetConfigQservMgtRequest::CallbackType const& onFinish = nullptr, unsigned int requestExpirationIvalSec = 0); - GetConfigQservHttpMgtRequest::Ptr configOverHttp( - std::string const& worker, std::string const& jobId = "", - GetConfigQservHttpMgtRequest::CallbackType const& onFinish = nullptr, - unsigned int requestExpirationIvalSec = 0); - private: /** * @param serviceProvider Is required for accessing configuration parameters. */ - explicit QservMgtServices(ServiceProvider::Ptr const& serviceProvider); + explicit QservMgtServices(std::shared_ptr const& serviceProvider); /** - * Finalize the completion of the request. This method will notify - * a requester on the completion of the operation and it will also - * remove the request from the server's registry. - * - * @param id A unique identifier of a completed request. + * Register the request (along with its callback) by its unique id in the local registry. + * When the request will finish it'll be automatically removed from the registry. + * @param func The name of a calling context (for error reporting and logging). + * @param request A request to be registered. + * @param onFinish A client callback to be called upon completion of the reqeust. */ - void _finish(std::string const& id); + template + void _register(std::string const& func, std::shared_ptr const& request, + typename T::CallbackType const& onFinish) { + replica::Lock const lock(_mtx, "QservMgtServices::" + func); + _registry[request->id()] = std::make_shared>(request, onFinish); + } /** - * @return A pointer to the XROOTD/SSI API service for launching worker management - * requests. - * @throws QservMgtConnectionError If unable to establish a connection. + * Finalize the completion of the request. + * This method will notify a requester on the completion of the operation and it will + * also remove the request from the server's registry. + * @param id A unique identifier of a completed request. */ - XrdSsiService* _xrdSsiService(); + void _finish(std::string const& id); // Input parameters - ServiceProvider::Ptr const _serviceProvider; - - /// The cashed pointer to the XROOTD/SSI service gets initialized at a time - /// the first request is being made. - XrdSsiService* _service = nullptr; + std::shared_ptr const _serviceProvider; - /// The registry of the on-going requests. - std::map> _registry; + /// The registry for the on-going requests. + std::map> _registry; - /// The mutex for enforcing thread safety of the class's public API - /// and internal operations. + /// The mutex for enforcing thread safety of the class's public API and internal operations. mutable replica::Mutex _mtx; }; diff --git a/src/replica/RemoveReplicaQservHttpMgtRequest.cc b/src/replica/RemoveReplicaQservHttpMgtRequest.cc deleted file mode 100644 index 211f3650c4..0000000000 --- a/src/replica/RemoveReplicaQservHttpMgtRequest.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/RemoveReplicaQservHttpMgtRequest.h" - -// Qserv headers -#include "replica/Common.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.RemoveReplicaQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -RemoveReplicaQservHttpMgtRequest::Ptr RemoveReplicaQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, - vector const& databases, bool force, - RemoveReplicaQservHttpMgtRequest::CallbackType const& onFinish) { - return RemoveReplicaQservHttpMgtRequest::Ptr( - new RemoveReplicaQservHttpMgtRequest(serviceProvider, worker, chunk, databases, force, onFinish)); -} - -RemoveReplicaQservHttpMgtRequest::RemoveReplicaQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, - vector const& databases, bool force, - RemoveReplicaQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_REMOVE_REPLICA", worker), - _chunk(chunk), - _databases(databases), - _force(force), - _onFinish(onFinish) {} - -list> RemoveReplicaQservHttpMgtRequest::extendedPersistentState() const { - list> result; - for (auto&& database : databases()) { - result.emplace_back("database", database); - } - result.emplace_back("chunk", to_string(chunk())); - result.emplace_back("force", replica::bool2str(force())); - return result; -} - -void RemoveReplicaQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const method = "DELETE"; - string const target = "/replica"; - json const data = json::object({{"chunk", _chunk}, {"databases", _databases}, {"force", _force ? 1 : 0}}); - createHttpReq(lock, method, target, data); -} - -void RemoveReplicaQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/RemoveReplicaQservHttpMgtRequest.h b/src/replica/RemoveReplicaQservHttpMgtRequest.h deleted file mode 100644 index 3e064e287a..0000000000 --- a/src/replica/RemoveReplicaQservHttpMgtRequest.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_REMOVEREPLICAQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_REMOVEREPLICAQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include -#include - -// Third party headers -#include "nlohmann/json.hpp" - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class RemoveReplicaQservHttpMgtRequest implements a request notifying Qserv workers - * on new chunks added to the database. - */ -class RemoveReplicaQservHttpMgtRequest : public QservHttpMgtRequest { -public: - typedef std::shared_ptr Ptr; - - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; - - RemoveReplicaQservHttpMgtRequest() = delete; - RemoveReplicaQservHttpMgtRequest(RemoveReplicaQservHttpMgtRequest const&) = delete; - RemoveReplicaQservHttpMgtRequest& operator=(RemoveReplicaQservHttpMgtRequest const&) = delete; - - virtual ~RemoveReplicaQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param chunk The chunk whose replicas will be disabled at the Qserv worker. - * @param databases The names of databases. - * @param force Force the removal even if the chunk is in use. - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static Ptr create(std::shared_ptr const& serviceProvider, std::string const& worker, - unsigned int chunk, std::vector const& databases, bool force = false, - CallbackType const& onFinish = nullptr); - - /// @return number of a chunk - unsigned int chunk() const { return _chunk; } - - /// @return names of databases - std::vector const& databases() const { return _databases; } - - /// @return flag indicating of the chunk removal should be forced even if in use - bool force() const { return _force; } - - /// @see QservHttpMgtRequest::extendedPersistentState() - virtual std::list> extendedPersistentState() const final; - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::notify - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see RemoveReplicaQservHttpMgtRequest::create() - RemoveReplicaQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, unsigned int chunk, - std::vector const& databases, bool force, - CallbackType const& onFinish); - - // Input parameters - - unsigned int const _chunk; - std::vector const _databases; - bool const _force; - CallbackType _onFinish; ///< The callback is reset when the request finishes. -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_REMOVEREPLICAQSERVHTTPMGTREQUEST_H diff --git a/src/replica/RemoveReplicaQservMgtRequest.cc b/src/replica/RemoveReplicaQservMgtRequest.cc index d44e6a551c..7066dea1a1 100644 --- a/src/replica/RemoveReplicaQservMgtRequest.cc +++ b/src/replica/RemoveReplicaQservMgtRequest.cc @@ -22,19 +22,13 @@ // Class header #include "replica/RemoveReplicaQservMgtRequest.h" -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - // Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" +#include "replica/Common.h" // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; namespace { @@ -46,7 +40,7 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.RemoveReplicaQservMgtRequest"); namespace lsst::qserv::replica { RemoveReplicaQservMgtRequest::Ptr RemoveReplicaQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, unsigned int chunk, + shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, vector const& databases, bool force, RemoveReplicaQservMgtRequest::CallbackType const& onFinish) { return RemoveReplicaQservMgtRequest::Ptr( @@ -54,15 +48,14 @@ RemoveReplicaQservMgtRequest::Ptr RemoveReplicaQservMgtRequest::create( } RemoveReplicaQservMgtRequest::RemoveReplicaQservMgtRequest( - ServiceProvider::Ptr const& serviceProvider, string const& worker, unsigned int chunk, + shared_ptr const& serviceProvider, string const& worker, unsigned int chunk, vector const& databases, bool force, RemoveReplicaQservMgtRequest::CallbackType const& onFinish) : QservMgtRequest(serviceProvider, "QSERV_REMOVE_REPLICA", worker), _chunk(chunk), _databases(databases), _force(force), - _onFinish(onFinish), - _qservRequest(nullptr) {} + _onFinish(onFinish) {} list> RemoveReplicaQservMgtRequest::extendedPersistentState() const { list> result; @@ -70,56 +63,19 @@ list> RemoveReplicaQservMgtRequest::extendedPersistentState result.emplace_back("database", database); } result.emplace_back("chunk", to_string(chunk())); - result.emplace_back("force", bool2str(force())); + result.emplace_back("force", replica::bool2str(force())); return result; } -void RemoveReplicaQservMgtRequest::startImpl(replica::Lock const& lock) { - auto const request = shared_from_base(); - - _qservRequest = xrdreq::RemoveChunkGroupQservRequest::create( - chunk(), databases(), force(), - [request](proto::WorkerCommandStatus::Code code, string const& error) { - if (request->state() == State::FINISHED) return; - replica::Lock lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - break; - case proto::WorkerCommandStatus::INVALID: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD, error); - break; - case proto::WorkerCommandStatus::IN_USE: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_CHUNK_IN_USE, error); - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error( - "RemoveReplicaQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); -} - -void RemoveReplicaQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +void RemoveReplicaQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const method = "DELETE"; + string const target = "/replica"; + json const data = json::object({{"chunk", _chunk}, {"databases", _databases}, {"force", _force ? 1 : 0}}); + createHttpReq(lock, method, target, data); } void RemoveReplicaQservMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); + LOGS(_log, LOG_LVL_TRACE, context() << __func__); notifyDefaultImpl(lock, _onFinish); } diff --git a/src/replica/RemoveReplicaQservMgtRequest.h b/src/replica/RemoveReplicaQservMgtRequest.h index 77f4a379a4..b95359136a 100644 --- a/src/replica/RemoveReplicaQservMgtRequest.h +++ b/src/replica/RemoveReplicaQservMgtRequest.h @@ -22,14 +22,21 @@ #define LSST_QSERV_REPLICA_REMOVEREPLICAQSERVMGTREQUEST_H // System headers +#include #include #include #include +#include + +// Third party headers +#include "nlohmann/json.hpp" // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/ChunkGroupQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { @@ -49,7 +56,7 @@ class RemoveReplicaQservMgtRequest : public QservMgtRequest { RemoveReplicaQservMgtRequest(RemoveReplicaQservMgtRequest const&) = delete; RemoveReplicaQservMgtRequest& operator=(RemoveReplicaQservMgtRequest const&) = delete; - ~RemoveReplicaQservMgtRequest() final = default; + virtual ~RemoveReplicaQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -65,7 +72,7 @@ class RemoveReplicaQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, + static Ptr create(std::shared_ptr const& serviceProvider, std::string const& worker, unsigned int chunk, std::vector const& databases, bool force = false, CallbackType const& onFinish = nullptr); @@ -79,22 +86,20 @@ class RemoveReplicaQservMgtRequest : public QservMgtRequest { bool force() const { return _force; } /// @see QservMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const override; + virtual std::list> extendedPersistentState() const final; protected: - /// @see QservMgtRequest::startImpl - void startImpl(replica::Lock const& lock) final; - - /// @see QservMgtRequest::finishImpl - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl + virtual void createHttpReqImpl(replica::Lock const& lock) final; /// @see QservMgtRequest::notify - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see RemoveReplicaQservMgtRequest::create() - RemoveReplicaQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - unsigned int chunk, std::vector const& databases, bool force, + RemoveReplicaQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, unsigned int chunk, + std::vector const& databases, bool force, CallbackType const& onFinish); // Input parameters @@ -102,12 +107,7 @@ class RemoveReplicaQservMgtRequest : public QservMgtRequest { unsigned int const _chunk; std::vector const _databases; bool const _force; - - /// The callback function for sending a notification upon request completion - CallbackType _onFinish; - - /// A request to the remote services - xrdreq::RemoveChunkGroupQservRequest::Ptr _qservRequest; + CallbackType _onFinish; ///< The callback is reset when the request finishes. }; } // namespace lsst::qserv::replica diff --git a/src/replica/SetReplicasQservHttpMgtRequest.cc b/src/replica/SetReplicasQservHttpMgtRequest.cc deleted file mode 100644 index 6e6c6cc6a5..0000000000 --- a/src/replica/SetReplicasQservHttpMgtRequest.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/SetReplicasQservHttpMgtRequest.h" - -// System headers -#include -#include -#include - -// Qserv headers -#include "replica/Common.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" -#include "util/IterableFormatter.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.SetReplicasQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -SetReplicasQservHttpMgtRequest::Ptr SetReplicasQservHttpMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, - QservReplicaCollection const& newReplicas, vector const& databases, bool force, - SetReplicasQservHttpMgtRequest::CallbackType const& onFinish) { - return SetReplicasQservHttpMgtRequest::Ptr(new SetReplicasQservHttpMgtRequest( - serviceProvider, worker, newReplicas, databases, force, onFinish)); -} - -SetReplicasQservHttpMgtRequest::SetReplicasQservHttpMgtRequest( - ServiceProvider::Ptr const& serviceProvider, string const& worker, - QservReplicaCollection const& newReplicas, vector const& databases, bool force, - SetReplicasQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_SET_REPLICAS", worker), - _newReplicas(newReplicas), - _databases(databases), - _force(force), - _onFinish(onFinish) {} - -QservReplicaCollection const& SetReplicasQservHttpMgtRequest::replicas() const { - if (not((state() == State::FINISHED) and (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("SetReplicasQservHttpMgtRequest::" + string(__func__) + - " replicas aren't available in state: " + state2string(state(), extendedState())); - } - return _replicas; -} - -list> SetReplicasQservHttpMgtRequest::extendedPersistentState() const { - list> result; - result.emplace_back("num_replicas", to_string(newReplicas().size())); - ostringstream ss; - ss << util::printable(_databases, "", "", ","); - result.emplace_back("databases", ss.str()); - result.emplace_back("force", replica::bool2str(force())); - return result; -} - -void SetReplicasQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - // Leave replicas that belong to the requested databases only. - set databaseFilter; - for (string const& database : _databases) { - databaseFilter.insert(database); - } - json replicas = json::object(); - for (auto&& replica : _newReplicas) { - if (databaseFilter.contains(replica.database)) { - replicas[replica.database].push_back(replica.chunk); - } - } - string const method = "POST"; - string const target = "/replicas"; - json const data = - json::object({{"replicas", replicas}, {"force", _force ? 1 : 0}, {"databases", _databases}}); - createHttpReq(lock, method, target, data); -} -QservHttpMgtRequest::ExtendedState SetReplicasQservHttpMgtRequest::dataReady(replica::Lock const& lock, - json const& data) { - _replicas.clear(); - for (auto&& [database, chunks] : data.at("replicas").get().items()) { - for (auto&& chunkEntry : chunks) { - unsigned int const chunk = chunkEntry.at(0); - unsigned int const useCount = chunkEntry.at(1); - _replicas.emplace_back(QservReplica{chunk, database, useCount}); - } - } - return QservHttpMgtRequest::ExtendedState::SUCCESS; -} - -void SetReplicasQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/SetReplicasQservHttpMgtRequest.h b/src/replica/SetReplicasQservHttpMgtRequest.h deleted file mode 100644 index fdca9eade1..0000000000 --- a/src/replica/SetReplicasQservHttpMgtRequest.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_SETREPLICASQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_SETREPLICASQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include -#include - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" -#include "replica/ReplicaInfo.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class SetReplicasQservHttpMgtRequest implements a request for configuring chunk - * inventory=ies (both transient and persistent) at Qserv workers. - */ -class SetReplicasQservHttpMgtRequest : public QservHttpMgtRequest { -public: - typedef std::shared_ptr Ptr; - - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; - - SetReplicasQservHttpMgtRequest() = delete; - SetReplicasQservHttpMgtRequest(SetReplicasQservHttpMgtRequest const&) = delete; - SetReplicasQservHttpMgtRequest& operator=(SetReplicasQservHttpMgtRequest const&) = delete; - - virtual ~SetReplicasQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * @note A collection of replicas passed into the request will be sanitized - * to leave a subset of replicas belonging to databases specified in - * the parameter 'databases' before this request is sent to the worker. - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param newReplicas A collection of new replicas (NOTE: useCount field is ignored). - * @param databases A set of databases that defines a scope of a scope of the request. - * @param force Proceed with the operation even if some replicas affected by - * the operation are in use. - * @param onFinish A callback function to be called upon request completion. - */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - QservReplicaCollection const& newReplicas, std::vector const& databases, - bool force = false, CallbackType const& onFinish = nullptr); - - /// @return a collection of replicas passed into the request - QservReplicaCollection const& newReplicas() const { return _newReplicas; } - - /// @return a flag indicating (if set) the 'force' mode of the operation - bool force() const { return _force; } - - /** - * @return The previous collection of replicas that was configured at Qserv worker - * at a time when the request was executed. The collection will only include - * replicas belonging to databases mentioned in the parameter 'databases' - * of the request. - * @throw std::logic_error if called before the request finishes or if it's finished - * with any but SUCCESS status. - */ - QservReplicaCollection const& replicas() const; - - /// @see QservHttpMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const final; - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::dataReady() - virtual QservHttpMgtRequest::ExtendedState dataReady(replica::Lock const& lock, - nlohmann::json const& data) final; - - /// @see QservHttpMgtRequest::notify - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see SetReplicasQservHttpMgtRequest::create() - SetReplicasQservHttpMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - QservReplicaCollection const& newReplicas, - std::vector const& databases, bool force, - CallbackType const& onFinish); - - // Input parameters. - - QservReplicaCollection const _newReplicas; - std::vector const _databases; - bool const _force; - CallbackType _onFinish; ///< The callback function is reset when the request finishes. - - /// A collection of replicas reported by the Qserv worker. - QservReplicaCollection _replicas; -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_SETREPLICASQSERVHTTPMGTREQUEST_H diff --git a/src/replica/SetReplicasQservMgtRequest.cc b/src/replica/SetReplicasQservMgtRequest.cc index c594804300..96e6a41d4d 100644 --- a/src/replica/SetReplicasQservMgtRequest.cc +++ b/src/replica/SetReplicasQservMgtRequest.cc @@ -27,13 +27,8 @@ #include #include -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - // Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" +#include "replica/Common.h" #include "replica/Configuration.h" #include "replica/ServiceProvider.h" #include "util/IterableFormatter.h" @@ -41,6 +36,7 @@ // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; namespace { @@ -67,8 +63,7 @@ SetReplicasQservMgtRequest::SetReplicasQservMgtRequest( _newReplicas(newReplicas), _databases(databases), _force(force), - _onFinish(onFinish), - _qservRequest(nullptr) {} + _onFinish(onFinish) {} QservReplicaCollection const& SetReplicasQservMgtRequest::replicas() const { if (not((state() == State::FINISHED) and (extendedState() == ExtendedState::SUCCESS))) { @@ -81,75 +76,46 @@ QservReplicaCollection const& SetReplicasQservMgtRequest::replicas() const { list> SetReplicasQservMgtRequest::extendedPersistentState() const { list> result; result.emplace_back("num_replicas", to_string(newReplicas().size())); - ostringstream databasesStream; - databasesStream << util::printable(_databases, "", "", " "); - result.emplace_back("databases", databasesStream.str()); - result.emplace_back("force", bool2str(force())); + ostringstream ss; + ss << util::printable(_databases, "", "", ","); + result.emplace_back("databases", ss.str()); + result.emplace_back("force", replica::bool2str(force())); return result; } -void SetReplicasQservMgtRequest::_setReplicas( - replica::Lock const& lock, xrdreq::SetChunkListQservRequest::ChunkCollection const& collection) { - _replicas.clear(); - for (auto&& replica : collection) { - _replicas.push_back(QservReplica{replica.chunk, replica.database, replica.use_count}); +void SetReplicasQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + // Leave replicas that belong to the requested databases only. + set databaseFilter; + for (string const& database : _databases) { + databaseFilter.insert(database); } -} - -void SetReplicasQservMgtRequest::startImpl(replica::Lock const& lock) { - xrdreq::SetChunkListQservRequest::ChunkCollection chunks; - for (auto&& chunkEntry : newReplicas()) { - chunks.push_back(xrdreq::SetChunkListQservRequest::Chunk{ - chunkEntry.chunk, chunkEntry.database, 0 /* UNUSED: use_count */ - }); + json replicas = json::object(); + for (auto&& replica : _newReplicas) { + if (databaseFilter.contains(replica.database)) { + replicas[replica.database].push_back(replica.chunk); + } } - auto const request = shared_from_base(); - - _qservRequest = xrdreq::SetChunkListQservRequest::create( - chunks, _databases, force(), - [request](proto::WorkerCommandStatus::Code code, string const& error, - xrdreq::SetChunkListQservRequest::ChunkCollection const& collection) { - if (request->state() == State::FINISHED) return; - replica::Lock lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - request->_setReplicas(lock, collection); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - case proto::WorkerCommandStatus::INVALID: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_BAD, error); - break; - case proto::WorkerCommandStatus::IN_USE: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_CHUNK_IN_USE, error); - break; - default: - throw logic_error( - "SetReplicasQservMgtRequest:: " + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); + string const method = "POST"; + string const target = "/replicas"; + json const data = + json::object({{"replicas", replicas}, {"force", _force ? 1 : 0}, {"databases", _databases}}); + createHttpReq(lock, method, target, data); } - -void SetReplicasQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; +QservMgtRequest::ExtendedState SetReplicasQservMgtRequest::dataReady(replica::Lock const& lock, + json const& data) { + _replicas.clear(); + for (auto&& [database, chunks] : data.at("replicas").get().items()) { + for (auto&& chunkEntry : chunks) { + unsigned int const chunk = chunkEntry.at(0); + unsigned int const useCount = chunkEntry.at(1); + _replicas.emplace_back(QservReplica{chunk, database, useCount}); + } } + return QservMgtRequest::ExtendedState::SUCCESS; } void SetReplicasQservMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); + LOGS(_log, LOG_LVL_TRACE, context() << __func__); notifyDefaultImpl(lock, _onFinish); } diff --git a/src/replica/SetReplicasQservMgtRequest.h b/src/replica/SetReplicasQservMgtRequest.h index 4da0d1d595..8ee99083e9 100644 --- a/src/replica/SetReplicasQservMgtRequest.h +++ b/src/replica/SetReplicasQservMgtRequest.h @@ -22,22 +22,26 @@ #define LSST_QSERV_REPLICA_SETREPLICASQSERVMGTREQUEST_H // System headers +#include #include #include #include +#include // Qserv headers #include "replica/QservMgtRequest.h" #include "replica/ReplicaInfo.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/SetChunkListQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { /** - * Class SetReplicasQservMgtRequest implements a request for setting new - * collections Qserv workers. + * Class SetReplicasQservMgtRequest implements a request for configuring chunk + * inventory=ies (both transient and persistent) at Qserv workers. */ class SetReplicasQservMgtRequest : public QservMgtRequest { public: @@ -50,17 +54,20 @@ class SetReplicasQservMgtRequest : public QservMgtRequest { SetReplicasQservMgtRequest(SetReplicasQservMgtRequest const&) = delete; SetReplicasQservMgtRequest& operator=(SetReplicasQservMgtRequest const&) = delete; - ~SetReplicasQservMgtRequest() final = default; + virtual ~SetReplicasQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan * and memory management of instances created otherwise (as values or via * low-level pointers). + * @note A collection of replicas passed into the request will be sanitized + * to leave a subset of replicas belonging to databases specified in + * the parameter 'databases' before this request is sent to the worker. * @param serviceProvider A reference to a provider of services for accessing * Configuration, saving the request's persistent state to the database. * @param worker The name of a worker to send the request to. * @param newReplicas A collection of new replicas (NOTE: useCount field is ignored). - * @param databases Limit a scope of the operation to databases of this collection. + * @param databases A set of databases that defines a scope of a scope of the request. * @param force Proceed with the operation even if some replicas affected by * the operation are in use. * @param onFinish A callback function to be called upon request completion. @@ -69,17 +76,19 @@ class SetReplicasQservMgtRequest : public QservMgtRequest { QservReplicaCollection const& newReplicas, std::vector const& databases, bool force = false, CallbackType const& onFinish = nullptr); - /// @return collection of new replicas to be set at the Qserv worker + /// @return a collection of replicas passed into the request QservReplicaCollection const& newReplicas() const { return _newReplicas; } - /// @return flag indicating (if set) the 'force' mode of the operation + /// @return a flag indicating (if set) the 'force' mode of the operation bool force() const { return _force; } /** - * @return A previous collection of replicas which was set at the corresponding - * Qserv worker before the operation. - * @note The method will throw exception std::logic_error if called before - * the request finishes or if it's finished with any but SUCCESS status. + * @return The previous collection of replicas that was configured at Qserv worker + * at a time when the request was executed. The collection will only include + * replicas belonging to databases mentioned in the parameter 'databases' + * of the request. + * @throw std::logic_error if called before the request finishes or if it's finished + * with any but SUCCESS status. */ QservReplicaCollection const& replicas() const; @@ -87,14 +96,15 @@ class SetReplicasQservMgtRequest : public QservMgtRequest { std::list> extendedPersistentState() const final; protected: - /// @see QservMgtRequest::startImpl - void startImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; - /// @see QservMgtRequest::finishImpl - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::dataReady() + virtual QservMgtRequest::ExtendedState dataReady(replica::Lock const& lock, + nlohmann::json const& data) final; /// @see QservMgtRequest::notify - void notify(replica::Lock const& lock) final; + virtual void notify(replica::Lock const& lock) final; private: /// @see SetReplicasQservMgtRequest::create() @@ -103,24 +113,12 @@ class SetReplicasQservMgtRequest : public QservMgtRequest { std::vector const& databases, bool force, CallbackType const& onFinish); - /** - * Carry over results of the request into a local collection. - * @param lock A lock on QservMgtRequest::_mtx must be acquired before calling this method. - * @param collection The input collection of replicas. - */ - void _setReplicas(replica::Lock const& lock, - xrdreq::SetChunkListQservRequest::ChunkCollection const& collection); - // Input parameters. QservReplicaCollection const _newReplicas; std::vector const _databases; - bool const _force; - CallbackType _onFinish; - - /// A request to the remote services. - xrdreq::SetChunkListQservRequest::Ptr _qservRequest; + CallbackType _onFinish; ///< The callback function is reset when the request finishes. /// A collection of replicas reported by the Qserv worker. QservReplicaCollection _replicas; diff --git a/src/replica/TestEchoQservHttpMgtRequest.cc b/src/replica/TestEchoQservHttpMgtRequest.cc deleted file mode 100644 index 2b2593ae66..0000000000 --- a/src/replica/TestEchoQservHttpMgtRequest.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ - -// Class header -#include "replica/TestEchoQservHttpMgtRequest.h" - -// LSST headers -#include "lsst/log/Log.h" - -using namespace nlohmann; -using namespace std; - -namespace { - -LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.TestEchoQservHttpMgtRequest"); - -} // namespace - -namespace lsst::qserv::replica { - -shared_ptr TestEchoQservHttpMgtRequest::create( - shared_ptr const& serviceProvider, string const& worker, string const& data, - TestEchoQservHttpMgtRequest::CallbackType const& onFinish) { - return shared_ptr( - new TestEchoQservHttpMgtRequest(serviceProvider, worker, data, onFinish)); -} - -TestEchoQservHttpMgtRequest::TestEchoQservHttpMgtRequest( - shared_ptr const& serviceProvider, string const& worker, string const& data, - TestEchoQservHttpMgtRequest::CallbackType const& onFinish) - : QservHttpMgtRequest(serviceProvider, "QSERV_TEST_ECHO", worker), _data(data), _onFinish(onFinish) {} - -string const& TestEchoQservHttpMgtRequest::dataEcho() const { - if (not((state() == State::FINISHED) and (extendedState() == ExtendedState::SUCCESS))) { - throw logic_error("TestEchoQservHttpMgtRequest::" + string(__func__) + - " no data available in state: " + state2string(state(), extendedState())); - } - return _dataEcho; -} - -list> TestEchoQservHttpMgtRequest::extendedPersistentState() const { - list> result; - result.emplace_back("data_length_bytes", to_string(data().size())); - return result; -} - -void TestEchoQservHttpMgtRequest::createHttpReqImpl(replica::Lock const& lock) { - string const method = "POST"; - string const target = "/echo"; - json const data = json::object({{"data", _data}}); - createHttpReq(lock, method, target, data); -} - -QservHttpMgtRequest::ExtendedState TestEchoQservHttpMgtRequest::dataReady(replica::Lock const& lock, - json const& data) { - _dataEcho = data.at("data"); - return QservHttpMgtRequest::ExtendedState::SUCCESS; -} - -void TestEchoQservHttpMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_TRACE, context() << __func__); - notifyDefaultImpl(lock, _onFinish); -} - -} // namespace lsst::qserv::replica diff --git a/src/replica/TestEchoQservHttpMgtRequest.h b/src/replica/TestEchoQservHttpMgtRequest.h deleted file mode 100644 index 4cbb87819d..0000000000 --- a/src/replica/TestEchoQservHttpMgtRequest.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * LSST Data Management System - * - * This product includes software developed by the - * LSST Project (http://www.lsst.org/). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the LSST License Statement and - * the GNU General Public License along with this program. If not, - * see . - */ -#ifndef LSST_QSERV_REPLICA_TESTECHOQSERVHTTPMGTREQUEST_H -#define LSST_QSERV_REPLICA_TESTECHOQSERVHTTPMGTREQUEST_H - -// System headers -#include -#include -#include -#include - -// Third party headers -#include "nlohmann/json.hpp" - -// Qserv headers -#include "replica/QservHttpMgtRequest.h" - -namespace lsst::qserv::replica { -class ServiceProvider; -} // namespace lsst::qserv::replica - -// This header declarations -namespace lsst::qserv::replica { - -/** - * Class TestEchoQservHttpMgtRequest a special kind of requests - * for testing Qserv workers. - */ -class TestEchoQservHttpMgtRequest : public QservHttpMgtRequest { -public: - /// The function type for notifications on the completion of the request - typedef std::function const&)> CallbackType; - - TestEchoQservHttpMgtRequest() = delete; - TestEchoQservHttpMgtRequest(TestEchoQservHttpMgtRequest const&) = delete; - TestEchoQservHttpMgtRequest& operator=(TestEchoQservHttpMgtRequest const&) = delete; - - virtual ~TestEchoQservHttpMgtRequest() final = default; - - /** - * Static factory method is needed to prevent issues with the lifespan - * and memory management of instances created otherwise (as values or via - * low-level pointers). - * @param serviceProvider A reference to a provider of services for accessing - * Configuration, saving the request's persistent state to the database. - * @param worker The name of a worker to send the request to. - * @param data The data string to be echoed back by the worker (if successful). - * @param onFinish (optional) callback function to be called upon request completion. - * @return A pointer to the created object. - */ - static std::shared_ptr create( - std::shared_ptr const& serviceProvider, std::string const& worker, - std::string const& data, CallbackType const& onFinish = nullptr); - - /// @return input data string sent to the worker - std::string const& data() const { return _data; } - - /** - * @return The data string echoed back by the worker. - * @note The method will throw exception std::logic_error if called before - * the request finishes or if it's finished with any status but SUCCESS. - */ - std::string const& dataEcho() const; - - /// @see QservHttpMgtRequest::extendedPersistentState() - virtual std::list> extendedPersistentState() const final; - -protected: - /// @see QservHttpMgtRequest::createHttpReqImpl() - virtual void createHttpReqImpl(replica::Lock const& lock) final; - - /// @see QservHttpMgtRequest::dataReady() - virtual QservHttpMgtRequest::ExtendedState dataReady(replica::Lock const& lock, - nlohmann::json const& data) final; - - /// @see QservHttpMgtRequest::notify() - virtual void notify(replica::Lock const& lock) final; - -private: - /// @see TestEchoQservHttpMgtRequest::create() - TestEchoQservHttpMgtRequest(std::shared_ptr const& serviceProvider, - std::string const& worker, std::string const& data, - CallbackType const& onFinish); - - // Input parameters - - std::string const _data; - CallbackType _onFinish; ///< This callback is reset after finishing the request. - - /// The data string returned by the Qserv worker - std::string _dataEcho; -}; - -} // namespace lsst::qserv::replica - -#endif // LSST_QSERV_REPLICA_TESTECHOQSERVHTTPMGTREQUEST_H diff --git a/src/replica/TestEchoQservMgtRequest.cc b/src/replica/TestEchoQservMgtRequest.cc index d5460bdc61..d5d5835ca1 100644 --- a/src/replica/TestEchoQservMgtRequest.cc +++ b/src/replica/TestEchoQservMgtRequest.cc @@ -22,23 +22,10 @@ // Class header #include "replica/TestEchoQservMgtRequest.h" -// System headers -#include -#include - -// Third party headers -#include "XrdSsi/XrdSsiProvider.hh" -#include "XrdSsi/XrdSsiService.hh" - -// Qserv headers -#include "global/ResourceUnit.h" -#include "proto/worker.pb.h" -#include "replica/Configuration.h" -#include "replica/ServiceProvider.h" - // LSST headers #include "lsst/log/Log.h" +using namespace nlohmann; using namespace std; namespace { @@ -49,13 +36,14 @@ LOG_LOGGER _log = LOG_GET("lsst.qserv.replica.TestEchoQservMgtRequest"); namespace lsst::qserv::replica { -TestEchoQservMgtRequest::Ptr TestEchoQservMgtRequest::create( - ServiceProvider::Ptr const& serviceProvider, string const& worker, string const& data, +shared_ptr TestEchoQservMgtRequest::create( + shared_ptr const& serviceProvider, string const& worker, string const& data, TestEchoQservMgtRequest::CallbackType const& onFinish) { - return TestEchoQservMgtRequest::Ptr(new TestEchoQservMgtRequest(serviceProvider, worker, data, onFinish)); + return shared_ptr( + new TestEchoQservMgtRequest(serviceProvider, worker, data, onFinish)); } -TestEchoQservMgtRequest::TestEchoQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, +TestEchoQservMgtRequest::TestEchoQservMgtRequest(shared_ptr const& serviceProvider, string const& worker, string const& data, TestEchoQservMgtRequest::CallbackType const& onFinish) : QservMgtRequest(serviceProvider, "QSERV_TEST_ECHO", worker), _data(data), _onFinish(onFinish) {} @@ -74,52 +62,22 @@ list> TestEchoQservMgtRequest::extendedPersistentState() co return result; } -void TestEchoQservMgtRequest::startImpl(replica::Lock const& lock) { - // Submit the actual request - - auto const request = shared_from_base(); - - _qservRequest = xrdreq::TestEchoQservRequest::create( - data(), [request](proto::WorkerCommandStatus::Code code, string const& error, string const& data, - string const& dataEcho) { - if (request->state() == State::FINISHED) return; - replica::Lock lock(request->_mtx, request->context() + string(__func__) + "[callback]"); - if (request->state() == State::FINISHED) return; - - switch (code) { - case proto::WorkerCommandStatus::SUCCESS: - request->_setData(lock, dataEcho); - request->finish(lock, QservMgtRequest::ExtendedState::SUCCESS); - break; - case proto::WorkerCommandStatus::ERROR: - request->finish(lock, QservMgtRequest::ExtendedState::SERVER_ERROR, error); - break; - default: - throw logic_error( - "TestEchoQservMgtRequest::" + string(__func__) + - " unhandled server status: " + proto::WorkerCommandStatus_Code_Name(code)); - } - }); - XrdSsiResource resource(ResourceUnit::makeWorkerPath(worker())); - service()->ProcessRequest(*_qservRequest, resource); +void TestEchoQservMgtRequest::createHttpReqImpl(replica::Lock const& lock) { + string const method = "POST"; + string const target = "/echo"; + json const data = json::object({{"data", _data}}); + createHttpReq(lock, method, target, data); } -void TestEchoQservMgtRequest::finishImpl(replica::Lock const& lock) { - switch (extendedState()) { - case ExtendedState::CANCELLED: - case ExtendedState::TIMEOUT_EXPIRED: - if (_qservRequest) _qservRequest->cancel(); - break; - default: - break; - } +QservMgtRequest::ExtendedState TestEchoQservMgtRequest::dataReady(replica::Lock const& lock, + json const& data) { + _dataEcho = data.at("data"); + return QservMgtRequest::ExtendedState::SUCCESS; } void TestEchoQservMgtRequest::notify(replica::Lock const& lock) { - LOGS(_log, LOG_LVL_DEBUG, context() << __func__); + LOGS(_log, LOG_LVL_TRACE, context() << __func__); notifyDefaultImpl(lock, _onFinish); } -void TestEchoQservMgtRequest::_setData(replica::Lock const& lock, string const& data) { _dataEcho = data; } - } // namespace lsst::qserv::replica diff --git a/src/replica/TestEchoQservMgtRequest.h b/src/replica/TestEchoQservMgtRequest.h index ba0113bcce..41992020ea 100644 --- a/src/replica/TestEchoQservMgtRequest.h +++ b/src/replica/TestEchoQservMgtRequest.h @@ -22,34 +22,38 @@ #define LSST_QSERV_REPLICA_TESTECHOQSERVMGTREQUEST_H // System headers +#include #include #include -#include +#include + +// Third party headers +#include "nlohmann/json.hpp" // Qserv headers #include "replica/QservMgtRequest.h" -#include "replica/ServiceProvider.h" -#include "xrdreq/TestEchoQservRequest.h" + +namespace lsst::qserv::replica { +class ServiceProvider; +} // namespace lsst::qserv::replica // This header declarations namespace lsst::qserv::replica { /** - * Class TestEchoQservMgtRequest implements a special kind of requests + * Class TestEchoQservMgtRequest a special kind of requests * for testing Qserv workers. */ class TestEchoQservMgtRequest : public QservMgtRequest { public: - typedef std::shared_ptr Ptr; - /// The function type for notifications on the completion of the request - typedef std::function CallbackType; + typedef std::function const&)> CallbackType; TestEchoQservMgtRequest() = delete; TestEchoQservMgtRequest(TestEchoQservMgtRequest const&) = delete; TestEchoQservMgtRequest& operator=(TestEchoQservMgtRequest const&) = delete; - ~TestEchoQservMgtRequest() final = default; + virtual ~TestEchoQservMgtRequest() final = default; /** * Static factory method is needed to prevent issues with the lifespan @@ -62,8 +66,9 @@ class TestEchoQservMgtRequest : public QservMgtRequest { * @param onFinish (optional) callback function to be called upon request completion. * @return A pointer to the created object. */ - static Ptr create(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - std::string const& data, CallbackType const& onFinish = nullptr); + static std::shared_ptr create( + std::shared_ptr const& serviceProvider, std::string const& worker, + std::string const& data, CallbackType const& onFinish = nullptr); /// @return input data string sent to the worker std::string const& data() const { return _data; } @@ -76,38 +81,28 @@ class TestEchoQservMgtRequest : public QservMgtRequest { std::string const& dataEcho() const; /// @see QservMgtRequest::extendedPersistentState() - std::list> extendedPersistentState() const override; + virtual std::list> extendedPersistentState() const final; protected: - /// @see QservMgtRequest::startImpl - void startImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::createHttpReqImpl() + virtual void createHttpReqImpl(replica::Lock const& lock) final; - /// @see QservMgtRequest::finishImpl - void finishImpl(replica::Lock const& lock) final; + /// @see QservMgtRequest::dataReady() + virtual QservMgtRequest::ExtendedState dataReady(replica::Lock const& lock, + nlohmann::json const& data) final; - /// @see QservMgtRequest::notify - void notify(replica::Lock const& lock) final; + /// @see QservMgtRequest::notify() + virtual void notify(replica::Lock const& lock) final; private: /// @see TestEchoQservMgtRequest::create() - TestEchoQservMgtRequest(ServiceProvider::Ptr const& serviceProvider, std::string const& worker, - std::string const& data, CallbackType const& onFinish); - - /** - * Carry over results of the request into a local storage. - * @param lock A lock on QservMgtRequest::_mtx must be acquired by a caller - * of the method. - * @param data The data string returned by a worker. - */ - void _setData(replica::Lock const& lock, std::string const& data); + TestEchoQservMgtRequest(std::shared_ptr const& serviceProvider, + std::string const& worker, std::string const& data, CallbackType const& onFinish); // Input parameters std::string const _data; - CallbackType _onFinish; ///< @note this object is reset after finishing the request - - /// A request to the remote services - xrdreq::TestEchoQservRequest::Ptr _qservRequest; + CallbackType _onFinish; ///< This callback is reset after finishing the request. /// The data string returned by the Qserv worker std::string _dataEcho;