From 5f4adbf1a3a40632d5d471e9acccd058220de0a5 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sat, 23 May 2015 00:38:17 +0300 Subject: [PATCH] dynamic_node_id_server::distributed::StateReport structure --- .../distributed/raft_core.hpp | 25 +++++--- .../distributed/server.hpp | 62 +++++++++++++++++++ .../node_discoverer.hpp | 6 ++ 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/raft_core.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/raft_core.hpp index b77dfadf9e..ab26635bbe 100644 --- a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/raft_core.hpp +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/raft_core.hpp @@ -74,6 +74,15 @@ public: */ class RaftCore : private TimerBase { +public: + enum ServerState + { + ServerStateFollower, + ServerStateCandidate, + ServerStateLeader + }; + +private: typedef MethodBinder&, ServiceResponseDataStructure&)> AppendEntriesCallback; @@ -88,13 +97,6 @@ class RaftCore : private TimerBase typedef MethodBinder&)> RequestVoteResponseCallback; - enum ServerState - { - ServerStateFollower, - ServerStateCandidate, - ServerStateLeader - }; - struct PendingAppendEntriesFields { Log::Index prev_log_index; @@ -895,6 +897,15 @@ public: // Remember that index zero contains a special-purpose entry that doesn't count as allocation return persistent_state_.getLog().getLastIndex(); } + + /** + * These accessors are needed for debugging, visualization and testing. + */ + const PersistentState& getPersistentState() const { return persistent_state_; } + const ClusterManager& getClusterManager() const { return cluster_; } + MonotonicTime getLastActivityTimestamp() const { return last_activity_timestamp_; } + bool isInActiveMode() const { return active_mode_; } + ServerState getServerState() const { return server_state_; } }; } diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp index 2fd6e2158a..940529e358 100644 --- a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp @@ -295,6 +295,68 @@ public: } Log::Index getNumAllocations() const { return raft_core_.getNumAllocations(); } + + /** + * These accessors are needed for debugging, visualization and testing. + */ + const RaftCore& getRaftCore() const { return raft_core_; } + const NodeDiscoverer& getNodeDiscoverer() const { return node_discoverer_; } +}; + +/** + * This structure represents immediate state of the server. + * It can be used for state visualization and debugging. + */ +struct StateReport +{ + uint8_t cluster_size; + + RaftCore::ServerState state; + bool is_active; + + Log::Index last_log_index; + Log::Index commit_index; + + Term last_log_term; + Term current_term; + + NodeID voted_for; + + MonotonicTime last_activity_timestamp; + + uint8_t num_unknown_nodes; + + struct FollowerState + { + NodeID node_id; + Log::Index next_index; + Log::Index match_index; + + FollowerState() + : next_index(0) + , match_index(0) + { } + } followers[ClusterManager::MaxClusterSize - 1]; + + StateReport(const Server& s) + : cluster_size (s.getRaftCore().getClusterManager().getClusterSize()) + , state (s.getRaftCore().getServerState()) + , is_active (s.getRaftCore().isInActiveMode()) + , last_log_index (s.getRaftCore().getPersistentState().getLog().getLastIndex()) + , commit_index (s.getRaftCore().getCommitIndex()) + , last_log_term (0) // See below + , current_term (s.getRaftCore().getPersistentState().getCurrentTerm()) + , voted_for (s.getRaftCore().getPersistentState().getVotedFor()) + , last_activity_timestamp(s.getRaftCore().getLastActivityTimestamp()) + , num_unknown_nodes (s.getNodeDiscoverer().getNumUnknownNodes()) + { + const Entry* const e = s.getRaftCore().getPersistentState().getLog().getEntryAtIndex(last_log_index); + UAVCAN_ASSERT(e != NULL); + if (e != NULL) + { + last_log_term = e->term; + } + } }; } diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp index 03b4145759..d8042074a2 100644 --- a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp @@ -361,6 +361,12 @@ public: * Returns true if there's at least one node with pending GetNodeInfo. */ bool hasUnknownNodes() const { return !node_map_.isEmpty(); } + + /** + * Returns number of nodes that are being queried at the moment. + * This method is needed for testing and state visualization. + */ + uint8_t getNumUnknownNodes() const { return static_cast(node_map_.getSize()); } }; }