Enable new callback API

- OnData() channel data handler.
 - ConditionalRun() for devices without incoming data.
 - Header file with common main(), to be extended with getDevice/addCustomOptions.
 - Update examples (MQ/Tutorial3) to use the new API and config.
 - NewSimpleMessage() for simpler creation of small messages (additional copy).
 - Replace SetProperty/GetProperty with fConfig access.
 - Runtime configurable channel names for common devices.
 - Configurable logging interval per channel.
 - FairMQMultiplier for distributing same data to multiple outputs.
 - Cleanup state machine messages.
 - Cmd option to toggle signal handling.
 - Simpler API for send/receive timeouts.
 - Enable --log-to-file.
 - Fix coverity issues, warnings.
 - Various code cleanup and minor tweaks.
This commit is contained in:
Alexey Rybalchenko
2016-08-10 09:47:53 +02:00
parent e0a03242ac
commit 16fd63cd5b
54 changed files with 1730 additions and 1665 deletions

View File

@@ -20,6 +20,7 @@
#include <string>
#include <iostream>
#include <unordered_map>
#include <functional>
#include <mutex>
#include <condition_variable>
@@ -33,8 +34,19 @@
#include "FairMQMessage.h"
#include "FairMQParts.h"
typedef std::unordered_map<std::string, std::vector<FairMQChannel>> FairMQChannelMap;
typedef std::function<bool(std::unique_ptr<FairMQMessage>&, int)> InputMsgCallback;
typedef std::function<bool(FairMQParts&, int)> InputMultipartCallback;
class FairMQProgOptions;
template<typename T>
void FairMQSimpleMsgCleanup(void* /*data*/, void* hint)
{
delete static_cast<T*>(hint);
}
class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
{
friend class FairMQChannel;
@@ -94,9 +106,9 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// @param i channel index
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
/// In case of errors, returns -1.
inline int Send(const std::unique_ptr<FairMQMessage>& msg, const std::string& chan, const int i = 0) const
inline int Send(const std::unique_ptr<FairMQMessage>& msg, const std::string& chan, const int i = 0, int sndTimeoutInMs = -1) const
{
return fChannels.at(chan).at(i).Send(msg);
return fChannels.at(chan).at(i).Send(msg, sndTimeoutInMs);
}
/// Shorthand method to send `msg` on `chan` at index `i` without blocking
@@ -116,9 +128,9 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// @param i channel index
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
/// In case of errors, returns -1.
inline int64_t Send(const FairMQParts& parts, const std::string& chan, const int i = 0) const
inline int64_t Send(const FairMQParts& parts, const std::string& chan, const int i = 0, int sndTimeoutInMs = -1) const
{
return fChannels.at(chan).at(i).Send(parts.fParts);
return fChannels.at(chan).at(i).Send(parts.fParts, sndTimeoutInMs);
}
/// Shorthand method to send FairMQParts on `chan` at index `i` without blocking
@@ -138,9 +150,9 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// @param i channel index
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
/// In case of errors, returns -1.
inline int Receive(const std::unique_ptr<FairMQMessage>& msg, const std::string& chan, const int i = 0) const
inline int Receive(const std::unique_ptr<FairMQMessage>& msg, const std::string& chan, const int i = 0, int rcvTimeoutInMs = -1) const
{
return fChannels.at(chan).at(i).Receive(msg);
return fChannels.at(chan).at(i).Receive(msg, rcvTimeoutInMs);
}
/// Shorthand method to receive `msg` on `chan` at index `i` without blocking
@@ -160,9 +172,9 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// @param i channel index
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
/// In case of errors, returns -1.
inline int64_t Receive(FairMQParts& parts, const std::string& chan, const int i = 0) const
inline int64_t Receive(FairMQParts& parts, const std::string& chan, const int i = 0, int rcvTimeoutInMs = -1) const
{
return fChannels.at(chan).at(i).Receive(parts.fParts);
return fChannels.at(chan).at(i).Receive(parts.fParts, rcvTimeoutInMs);
}
/// Shorthand method to receive FairMQParts on `chan` at index `i` without blocking
@@ -176,6 +188,13 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
return fChannels.at(chan).at(i).ReceiveAsync(parts.fParts);
}
/// @brief Create FairMQPoller
/// @return pointer to FairMQPoller
inline FairMQPoller* NewPoller(const std::initializer_list<std::string> channelList) const
{
return fTransportFactory->CreatePoller(fChannels, channelList);
}
/// @brief Create empty FairMQMessage
/// @return pointer to FairMQMessage
inline FairMQMessage* NewMessage() const
@@ -202,6 +221,26 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
return fTransportFactory->CreateMessage(data, size, ffn, hint);
}
template<typename T>
inline FairMQMessage* NewSimpleMessage(const T& data) const
{
T* dataCopy = new T(data);
return fTransportFactory->CreateMessage(dataCopy, sizeof(T), FairMQSimpleMsgCleanup<T>, dataCopy);
}
template<std::size_t N>
inline FairMQMessage* NewSimpleMessage(const char(&data)[N]) const
{
std::string* msgStr = new std::string(data);
return fTransportFactory->CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
}
inline FairMQMessage* NewSimpleMessage(const std::string& str) const
{
std::string* msgStr = new std::string(str);
return fTransportFactory->CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
}
/// Waits for the first initialization run to finish
void WaitForInitialValidation();
@@ -255,8 +294,32 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// @param rhs Left hand side value for comparison
static bool SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs);
// TODO: make this const?
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
FairMQProgOptions* fConfig; ///< Program options configuration
template<class T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(std::unique_ptr<FairMQMessage>& msg, int index))
{
fDataCallbacks = true;
fMsgInputs.insert(std::make_pair(channelName, [this, memberFunction](std::unique_ptr<FairMQMessage>& msg, int index)
{
return (static_cast<T*>(this)->*memberFunction)(msg, index);
}));
}
void OnData(const std::string& channelName, InputMsgCallback);
template<class T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
{
fDataCallbacks = true;
fMultipartInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQParts& parts, int index)
{
return (static_cast<T*>(this)->*memberFunction)(parts, index);
}));
}
void OnData(const std::string& channelName, InputMultipartCallback);
protected:
std::string fId; ///< Device ID
@@ -274,7 +337,6 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
FairMQSocket* fCmdSocket; ///< Socket used for the internal unblocking mechanism
FairMQTransportFactory* fTransportFactory; ///< Transport factory
FairMQProgOptions* fConfig; ///< Program options configuration
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
virtual void Init();
@@ -285,6 +347,15 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// Runs the device (to be overloaded in child classes)
virtual void Run();
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
virtual void PreRun();
/// Called during RUNNING state repeatedly until it returns false or device state changes
virtual bool ConditionalRun();
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
virtual void PostRun();
/// Handles the PAUSE state
virtual void Pause();
@@ -330,9 +401,13 @@ class FairMQDevice : public FairMQStateMachine, public FairMQConfigurable
/// Signal handler
void SignalHandler(int signal);
bool fCatchingSignals;
bool fTerminated;
bool fTerminationRequested;
// Interactive state loop helper
std::atomic<bool> fRunning;
std::atomic<bool> fInteractiveRunning;
bool fDataCallbacks;
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
};
#endif /* FAIRMQDEVICE_H_ */