Skip to content

Commit

Permalink
Merge pull request #86 from UAVCAN/nid_allocation_activity_monitoring
Browse files Browse the repository at this point in the history
Monitoring activity of dynamic node ID allocation servers
  • Loading branch information
pavel-kirienko committed Feb 20, 2016
2 parents 702f6f0 + 38f5591 commit 7ce96d6
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2015 Pavel Kirienko <[email protected]>
*/

#ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_SERVER_HPP_INCLUDED
#define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_SERVER_HPP_INCLUDED

#include <uavcan/build_config.hpp>
#include <uavcan/debug.hpp>
#include <uavcan/protocol/dynamic_node_id_server/allocation_request_manager.hpp>
#include <uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp>
#include <uavcan/protocol/dynamic_node_id_server/event.hpp>

namespace uavcan
{
namespace dynamic_node_id_server
{

class AbstractServer : protected IAllocationRequestHandler
, protected INodeDiscoveryHandler
{
UniqueID own_unique_id_;
MonotonicTime started_at_;

protected:
INode& node_;
IEventTracer& tracer_;
AllocationRequestManager allocation_request_manager_;
NodeDiscoverer node_discoverer_;

AbstractServer(INode& node,
IEventTracer& tracer) :
node_(node),
tracer_(tracer),
allocation_request_manager_(node, tracer, *this),
node_discoverer_(node, tracer, *this)
{ }

const UniqueID& getOwnUniqueID() const { return own_unique_id_; }

int init(const UniqueID& own_unique_id, const TransferPriority priority)
{
int res = 0;

own_unique_id_ = own_unique_id;

res = allocation_request_manager_.init(priority);
if (res < 0)
{
return res;
}

res = node_discoverer_.init(priority);
if (res < 0)
{
return res;
}

started_at_ = node_.getMonotonicTime();

return 0;
}

public:
/**
* This can be used to guess if there are any un-allocated dynamic nodes left in the network.
*/
bool guessIfAllDynamicNodesAreAllocated(
const MonotonicDuration& allocation_activity_timeout =
MonotonicDuration::fromMSec(Allocation::MAX_REQUEST_PERIOD_MS * 2),
const MonotonicDuration& min_uptime = MonotonicDuration::fromMSec(6000)) const
{
const MonotonicTime ts = node_.getMonotonicTime();

/*
* If uptime is not large enough, the allocator may be unaware about some nodes yet.
*/
const MonotonicDuration uptime = ts - started_at_;
if (uptime < max(allocation_activity_timeout, min_uptime))
{
return false;
}

/*
* If there are any undiscovered nodes, assume that allocation is still happening.
*/
if (node_discoverer_.hasUnknownNodes())
{
return false;
}

/*
* Lastly, check if there wasn't any allocation messages detected on the bus in the specified amount of time.
*/
const MonotonicDuration since_allocation_activity =
ts - allocation_request_manager_.getTimeOfLastAllocationActivity();
if (since_allocation_activity < allocation_activity_timeout)
{
return false;
}

return true;
}

/**
* This is useful for debugging/testing/monitoring.
*/
const NodeDiscoverer& getNodeDiscoverer() const { return node_discoverer_; }
};

}
}

#endif // Include guard
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class AllocationRequestManager
const MonotonicDuration stage_timeout_;

MonotonicTime last_message_timestamp_;
MonotonicTime last_activity_timestamp_;
Allocation::FieldTypes::unique_id current_unique_id_;

IAllocationRequestHandler& handler_;
Expand Down Expand Up @@ -127,6 +128,7 @@ class AllocationRequestManager
void handleAllocation(const ReceivedDataStructure<Allocation>& msg)
{
trace(TraceAllocationActivity, msg.getSrcNodeID().get());
last_activity_timestamp_ = msg.getMonotonicTimestamp();

if (!msg.isAnonymousTransfer())
{
Expand Down Expand Up @@ -266,9 +268,16 @@ class AllocationRequestManager
msg.node_id = allocated_node_id.get();

trace(TraceAllocationResponse, msg.node_id);
last_activity_timestamp_ = allocation_pub_.getNode().getMonotonicTime();

return allocation_pub_.broadcast(msg);
}

/**
* When the last allocation activity was registered.
* This value can be used to heuristically determine whether there are any unallocated nodes left in the network.
*/
MonotonicTime getTimeOfLastAllocationActivity() const { return last_activity_timestamp_; }
};

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

#include <uavcan/build_config.hpp>
#include <uavcan/debug.hpp>
#include <uavcan/protocol/dynamic_node_id_server/allocation_request_manager.hpp>
#include <uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp>
#include <uavcan/protocol/dynamic_node_id_server/abstract_server.hpp>
#include <uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp>
#include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp>
#include <uavcan/protocol/dynamic_node_id_server/centralized/storage.hpp>
Expand All @@ -26,15 +25,8 @@ namespace centralized
*
* This version is suitable only for simple non-critical systems.
*/
class Server : IAllocationRequestHandler
, INodeDiscoveryHandler
class Server : public AbstractServer
{
UniqueID own_unique_id_;

INode& node_;
IEventTracer& tracer_;
AllocationRequestManager allocation_request_manager_;
NodeDiscoverer node_discoverer_;
Storage storage_;

/*
Expand Down Expand Up @@ -128,10 +120,7 @@ class Server : IAllocationRequestHandler
Server(INode& node,
IStorageBackend& storage,
IEventTracer& tracer)
: node_(node)
, tracer_(tracer)
, allocation_request_manager_(node, tracer, *this)
, node_discoverer_(node, tracer, *this)
: AbstractServer(node, tracer)
, storage_(storage)
{ }

Expand All @@ -148,12 +137,19 @@ class Server : IAllocationRequestHandler
}

/*
* Making sure that the server is started with the same node ID
* Common logic
*/
own_unique_id_ = own_unique_id;
res = AbstractServer::init(own_unique_id, priority);
if (res < 0)
{
return res;
}

/*
* Making sure that the server is started with the same node ID
*/
{
const NodeID stored_own_node_id = storage_.getNodeIDForUniqueID(own_unique_id_);
const NodeID stored_own_node_id = storage_.getNodeIDForUniqueID(getOwnUniqueID());
if (stored_own_node_id.isValid())
{
if (stored_own_node_id != node_.getNodeID())
Expand All @@ -163,29 +159,14 @@ class Server : IAllocationRequestHandler
}
else
{
res = storage_.add(node_.getNodeID(), own_unique_id_);
res = storage_.add(node_.getNodeID(), getOwnUniqueID());
if (res < 0)
{
return res;
}
}
}

/*
* Misc
*/
res = allocation_request_manager_.init(priority);
if (res < 0)
{
return res;
}

res = node_discoverer_.init(priority);
if (res < 0)
{
return res;
}

return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
#include <uavcan/debug.hpp>
#include <uavcan/protocol/dynamic_node_id_server/distributed/types.hpp>
#include <uavcan/protocol/dynamic_node_id_server/distributed/raft_core.hpp>
#include <uavcan/protocol/dynamic_node_id_server/allocation_request_manager.hpp>
#include <uavcan/protocol/dynamic_node_id_server/abstract_server.hpp>
#include <uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp>
#include <uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp>
#include <uavcan/protocol/dynamic_node_id_server/event.hpp>

namespace uavcan
Expand All @@ -23,8 +22,7 @@ namespace distributed
/**
* This class implements the top-level allocation logic and server API.
*/
class UAVCAN_EXPORT Server : IAllocationRequestHandler
, INodeDiscoveryHandler
class UAVCAN_EXPORT Server : public AbstractServer
, IRaftLeaderMonitor
{
struct UniqueIDLogPredicate
Expand Down Expand Up @@ -55,19 +53,10 @@ class UAVCAN_EXPORT Server : IAllocationRequestHandler
}
};

/*
* Constants
*/
UniqueID own_unique_id_;

/*
* States
*/
INode& node_;
IEventTracer& tracer_;
RaftCore raft_core_;
AllocationRequestManager allocation_request_manager_;
NodeDiscoverer node_discoverer_;

/*
* Methods of IAllocationRequestHandler
Expand Down Expand Up @@ -196,7 +185,7 @@ class UAVCAN_EXPORT Server : IAllocationRequestHandler

if (!result.isConstructed())
{
raft_core_.appendLog(own_unique_id_, node_.getNodeID());
raft_core_.appendLog(getOwnUniqueID(), node_.getNodeID());
}
}

Expand Down Expand Up @@ -239,11 +228,8 @@ class UAVCAN_EXPORT Server : IAllocationRequestHandler
Server(INode& node,
IStorageBackend& storage,
IEventTracer& tracer)
: node_(node)
, tracer_(tracer)
: AbstractServer(node, tracer)
, raft_core_(node, storage, tracer, *this)
, allocation_request_manager_(node, tracer, *this)
, node_discoverer_(node, tracer, *this)
{ }

int init(const UniqueID& own_unique_id,
Expand All @@ -260,36 +246,28 @@ class UAVCAN_EXPORT Server : IAllocationRequestHandler
}

/*
* Making sure that the server is started with the same node ID
* Common logic
*/
own_unique_id_ = own_unique_id;
res = AbstractServer::init(own_unique_id, priority);
if (res < 0)
{
return res;
}

/*
* Making sure that the server is started with the same node ID
*/
const LazyConstructor<RaftCore::LogEntryInfo> own_log_entry =
raft_core_.traverseLogFromEndUntil(NodeIDLogPredicate(node_.getNodeID()));

if (own_log_entry.isConstructed())
{
if (own_log_entry->entry.unique_id != own_unique_id_)
if (own_log_entry->entry.unique_id != getOwnUniqueID())
{
return -ErrInvalidConfiguration;
}
}

/*
* Misc
*/
res = allocation_request_manager_.init(priority);
if (res < 0)
{
return res;
}

res = node_discoverer_.init(priority);
if (res < 0)
{
return res;
}

return 0;
}

Expand All @@ -299,7 +277,6 @@ class UAVCAN_EXPORT Server : IAllocationRequestHandler
* These accessors are needed for debugging, visualization and testing.
*/
const RaftCore& getRaftCore() const { return raft_core_; }
const NodeDiscoverer& getNodeDiscoverer() const { return node_discoverer_; }
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void redraw(const uavcan_linux::NodePtr& node,
/*
* Constants that are permanent for the designed UI layout
*/
constexpr unsigned NumRelevantEvents = 16;
constexpr unsigned NumRelevantEvents = 17;
constexpr unsigned NumRowsWithoutEvents = 3;

/*
Expand Down Expand Up @@ -390,6 +390,11 @@ void redraw(const uavcan_linux::NodePtr& node,
node->getInternalFailureCount(),
colorize_if(node->getInternalFailureCount() != 0, CLIColor::Magenta));

const bool all_allocated = server.guessIfAllDynamicNodesAreAllocated();
render_top_str("All allocated",
all_allocated ? "Yes": "No",
colorize_if(!all_allocated, CLIColor::Magenta));

// Empty line before the next block
std::printf(" ");
render_next_event_counter();
Expand Down

0 comments on commit 7ce96d6

Please sign in to comment.