diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index 25cc8f205246348dff171806e07c534c032544f1..a864eaa383e3b8e4eaedefd97f3cc905810870a3 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -90,20 +90,19 @@ public: /** Average requests per second */ double requestRate {0}; /** Node Info **/ - NodeInfo nodeInfo {}; + std::shared_ptr<NodeInfo> nodeInfo {}; std::string toString() const { std::ostringstream ss; ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl; ss << "Requests: " << requestRate << " per second." << std::endl; - auto& ni = nodeInfo; - auto& ipv4 = ni.ipv4; - if (ipv4.table_depth > 1) { - ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;; - } - auto& ipv6 = ni.ipv6; - if (ipv6.table_depth > 1) { - ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;; + if (nodeInfo) { + auto& ipv4 = nodeInfo->ipv4; + if (ipv4.table_depth > 1) + ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;; + auto& ipv6 = nodeInfo->ipv6; + if (ipv6.table_depth > 1) + ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;; } return ss.str(); } @@ -117,14 +116,15 @@ public: result["putCount"] = static_cast<Json::UInt64>(putCount); result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount); result["requestRate"] = requestRate; - result["nodeInfo"] = nodeInfo.toJson(); + if (nodeInfo) + result["nodeInfo"] = nodeInfo->toJson(); return result; } }; - ServerStats stats() const { return stats_; } + std::shared_ptr<ServerStats> stats() const { return stats_; } - void updateStats() const; + std::shared_ptr<ServerStats> updateStats(std::shared_ptr<NodeInfo> info) const; std::shared_ptr<DhtRunner> getNode() const { return dht_; } @@ -327,9 +327,8 @@ private: std::shared_ptr<dht::Logger> logger_; - mutable std::mutex statsMutex_; - mutable ServerStats stats_; - mutable NodeInfo nodeInfo_ {}; + mutable std::shared_ptr<ServerStats> stats_; + mutable std::shared_ptr<NodeInfo> nodeInfo_ {}; std::unique_ptr<asio::steady_timer> printStatsTimer_; // Thread-safe access to listeners map. diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 7a41d45b59365d18ad1630752cfcec4cefc81c23..25b5959167b44379ddab924ccc968a3087a0ee3e 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -36,6 +36,7 @@ #include <iostream> using namespace std::placeholders; +using namespace std::chrono_literals; #ifdef OPENDHT_PROXY_HTTP_PARSER_FORK namespace restinio { @@ -263,7 +264,7 @@ DhtProxyServer::DhtProxyServer( } dht->forwardAllMessages(true); - printStatsTimer_ = std::make_unique<asio::steady_timer>(io_context(), PRINT_STATS_PERIOD); + printStatsTimer_ = std::make_unique<asio::steady_timer>(io_context(), 0s); printStatsTimer_->async_wait(std::bind(&DhtProxyServer::handlePrintStats, this, std::placeholders::_1)); } @@ -344,20 +345,23 @@ DhtProxyServer::addServerSettings(ServerSettings& settings, const unsigned int m settings.connection_state_listener(connListener_); } -void -DhtProxyServer::updateStats() const +std::shared_ptr<DhtProxyServer::ServerStats> +DhtProxyServer::updateStats(std::shared_ptr<NodeInfo> info) const { auto now = clock::now(); auto last = lastStatsReset_.exchange(now); auto count = requestNum_.exchange(0); auto dt = std::chrono::duration<double>(now - last); - stats_.requestRate = count / dt.count(); + auto sstats = std::make_shared<ServerStats>(); + auto& stats = *sstats; + stats.requestRate = count / dt.count(); #ifdef OPENDHT_PUSH_NOTIFICATIONS - stats_.pushListenersCount = pushListeners_.size(); + stats.pushListenersCount = pushListeners_.size(); #endif - stats_.putCount = puts_.size(); - stats_.listenCount = listeners_.size(); - stats_.nodeInfo = nodeInfo_; + stats.putCount = puts_.size(); + stats.listenCount = listeners_.size(); + stats.nodeInfo = info; + return sstats; } void @@ -372,13 +376,12 @@ DhtProxyServer::handlePrintStats(const asio::error_code &ec) if (io_context().stopped()) return; - if (dht_){ - updateStats(); + if (auto dht = dht_) { // Refresh stats cache - auto newInfo = dht_->getNodeInfo(); - std::lock_guard<std::mutex> lck(statsMutex_); - nodeInfo_ = std::move(newInfo); - auto json = nodeInfo_.toJson(); + auto newInfo = std::make_shared<NodeInfo>(dht->getNodeInfo()); + stats_ = updateStats(newInfo); + nodeInfo_ = newInfo; + auto json = newInfo->toJson(); auto str = Json::writeString(jsonBuilder_, json); if (logger_) logger_->d("[proxy:server] [stats] %s", str.c_str()); @@ -477,12 +480,12 @@ DhtProxyServer::getNodeInfo(restinio::request_handle_t request, restinio::router::route_params_t /*params*/) const { Json::Value result; - std::lock_guard<std::mutex> lck(statsMutex_); - if (nodeInfo_.ipv4.good_nodes == 0 && - nodeInfo_.ipv6.good_nodes == 0){ - nodeInfo_ = dht_->getNodeInfo(); + auto nodeInfo = nodeInfo_; + if (not nodeInfo) { + nodeInfo = std::make_shared<NodeInfo>(dht_->getNodeInfo()); + nodeInfo_ = nodeInfo; } - result = nodeInfo_.toJson(); + result = nodeInfo->toJson(); // [ipv6:ipv4]:port or ipv4:port result["public_ip"] = request->remote_endpoint().address().to_string(); auto output = Json::writeString(jsonBuilder_, result) + "\n"; @@ -498,8 +501,8 @@ DhtProxyServer::getStats(restinio::request_handle_t request, { requestNum_++; try { - if (dht_){ - auto output = Json::writeString(jsonBuilder_, stats_.toJson()) + "\n"; + if (auto stats = stats_) { + auto output = Json::writeString(jsonBuilder_, stats->toJson()) + "\n"; auto response = initHttpResponse(request->create_response()); response.append_body(output); response.done(); diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index bb4cee6a5b7a4f146f660fff2b6aff91c9ccef8a..76632b9cfa78c613b31d01626effdfea4cea762a 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -152,8 +152,11 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params std::cout << nodeInfo.ipv6.toString() << std::endl; #ifdef OPENDHT_PROXY_SERVER for (const auto& proxy : proxies) { - std::cout << "Stats for proxy on port " << proxy.first << std::endl; - std::cout << " " << proxy.second->stats().toString() << std::endl; + std::cout << "Stats for proxy server on port " << proxy.first << std::endl; + if (auto stats = proxy.second->stats()) + std::cout << " " << stats->toString() << std::endl; + else + std::cout << " (stats not available yet)" << std::endl; } #endif continue;