#include "cluster/ClioNode.hpp" #include "data/LedgerCacheLoadingState.hpp" #include "etl/WriterState.hpp" #include "util/TimeUtils.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace cluster { namespace { struct JsonFields { static constexpr std::string_view const kUpdateTime = "update_time"; static constexpr std::string_view const kDbRole = "db_role"; static constexpr std::string_view const kEtlStarted = "etl_started"; static constexpr std::string_view const kCacheIsFull = "cache_is_full"; static constexpr std::string_view const kCacheIsCurrentlyLoading = "cache_is_currently_loading"; }; } // namespace ClioNode ClioNode::from( ClioNode::Uuid uuid, etl::WriterStateInterface const& writerState, data::LedgerCacheLoadingStateInterface const& cacheLoadingState ) { auto const dbRole = [&writerState]() { if (writerState.isReadOnly()) { return ClioNode::DbRole::ReadOnly; } if (writerState.isFallback()) { return ClioNode::DbRole::Fallback; } if (writerState.isFallbackRecovery()) { return ClioNode::DbRole::FallbackRecovery; } return writerState.isWriting() ? ClioNode::DbRole::Writer : ClioNode::DbRole::NotWriter; }(); return ClioNode{ .uuid = std::move(uuid), .updateTime = std::chrono::system_clock::now(), .dbRole = dbRole, .etlStarted = writerState.isEtlStarted(), .cacheIsFull = writerState.isCacheFull(), .cacheIsCurrentlyLoading = cacheLoadingState.isCurrentlyLoading() }; } void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, ClioNode const& node) { jv = { {JsonFields::kUpdateTime, util::systemTpToUtcStr(node.updateTime, ClioNode::kTimeFormat)}, {JsonFields::kDbRole, static_cast(node.dbRole)}, {JsonFields::kEtlStarted, node.etlStarted}, {JsonFields::kCacheIsFull, node.cacheIsFull}, {JsonFields::kCacheIsCurrentlyLoading, node.cacheIsCurrentlyLoading} }; } ClioNode tag_invoke(boost::json::value_to_tag, boost::json::value const& jv) { auto const& obj = jv.as_object(); auto const& updateTimeStr = obj.at(JsonFields::kUpdateTime).as_string(); auto const updateTime = util::systemTpFromUtcStr(std::string(updateTimeStr), ClioNode::kTimeFormat); if (!updateTime.has_value()) { throw std::runtime_error("Failed to parse update time"); } // Each field has a default value for backward compatibility auto dbRole = ClioNode::DbRole::Fallback; if (auto const* v = obj.if_contains(JsonFields::kDbRole)) { auto const dbRoleValue = v->as_int64(); if (dbRoleValue > static_cast(ClioNode::DbRole::Max)) throw std::runtime_error("Invalid db_role value"); dbRole = static_cast(dbRoleValue); } auto const etlStarted = obj.contains(JsonFields::kEtlStarted) ? obj.at(JsonFields::kEtlStarted).as_bool() : true; auto const cacheIsFull = obj.contains(JsonFields::kCacheIsFull) ? obj.at(JsonFields::kCacheIsFull).as_bool() : true; auto const cacheIsCurrentlyLoading = obj.contains(JsonFields::kCacheIsCurrentlyLoading) ? obj.at(JsonFields::kCacheIsCurrentlyLoading).as_bool() : false; return ClioNode{ // Json data doesn't contain uuid so leaving it empty here. It will be filled outside of // this parsing .uuid = std::make_shared(), .updateTime = *updateTime, .dbRole = dbRole, .etlStarted = etlStarted, .cacheIsFull = cacheIsFull, .cacheIsCurrentlyLoading = cacheIsCurrentlyLoading }; } } // namespace cluster