#ifndef __RecordDispatcher_h_ #define __RecordDispatcher_h_ #include "../shared/Messages.h" #include "DataFormat.h" /* The each application has one dispatcher thread which gets the records first, * and distributes them to the other threads as needed. This interface * describes that thread. * * The system as a whole has one master application which gets the records * first, and passes them to the other applications. (The master application * is responsible for setting the alert id number, among other things.) The * master application always listens for new connections from both producers * and consumers of data. The other applications will have to initiate the * connection to the master. * * The consumers within the application don't care if this application is the * master or not. There might be different classes for these two cases, or * one class which can be configured different ways. There might be different * classes or objects for alerts vs top list, or maybe just one object that does * it all. Those are implementation details. * * If you call these functions before they are ready, the program will stop * and an appropriate message will be sent to the error log. (Something like * an assertion failure.) If the program is not configured to listen for * a particular type of data (i.e. alerts or top list) and you ask for that * data, nothing interesting will happen. */ class IRecordDispatcher { private: protected: static IRecordDispatcher *_alerts; static IRecordDispatcher *_topList; virtual ~IRecordDispatcher() { } public: // Is active means that we expect some data. You don't have to check this. // If it's not active, it's still safe to listen, but nothing interesting // will come of it. As an optimization you might check on this before // starting another thread or requesting other resources. This way only // one bit of code (RecordDispatcher.C) has to read from the config file // if we are watching one type of data or not. virtual bool isActive() const =0; // This means that we are the main server accumulating all of the alerts // or top list entries. This is just an FYI. People can read from here // regardless of this fact. However, some modules might only want to turn // themselves on if this server is the master. virtual bool isMaster() const =0; // "alerts" or "top_list". This is used as a prefix in a lot of config // items. virtual std::string const &getBaseName() const =0; // This will always start from the current record. The assumption is that // internal listeners will all start as soon as the program starts. External // listeners might have the ability to catch up after they are disconnected. // The listener will receive NewRecord requests. virtual void listenForRecords(RequestListener *listener, int callbackId) =0; virtual void listenForStatus(RequestListener *listener, int callbackId) =0; // This is used when one server asks for data from the next. This class // would do the asking, and FeedNextServer would do the supplying. They // will need to use the same command or they can't talk with each other! virtual std::string getListenCommand() const =0; // Same as above but for status messages, e.g. "becca:1301". virtual std::string getStatusCommand() const =0; // These will be NULL before init() is called. Afterwords they will not // be null. There isn't much reason to explicitly check. You could assert // that these are not null when you want them, but it's just as well to // wait for the core dump. static IRecordDispatcher *getAlerts() { return _alerts; } static IRecordDispatcher *getTopList() { return _topList; } static void init(); }; class NewRecord : public Request { public: const Record::Ref record; NewRecord(Record::Ref const &record) : Request(NULL), record(record) { } }; class ProviderStatus : public Request { public: const std::string name; ProviderStatus(std::string const &name) : Request(NULL), name(name) { } }; // This class compares the timestamp of each record to the current time, // and accumulates the results. This is designed to be given to // ThreadMonitor::find().add(). // // We use microseconds for the current time. The alerts only store the // time precise to the second. So when we measure the late time we expect // between 0 and 999999 microseconds to be added to each late time because // of round off error. class LateRecordCounter : public ThreadMonitor::Extra { private: int _noTimeCount; int _earlyCount; int _totalCount; int64_t _totalTime; int64_t _worstTime; public: void add(Record::Ref const &record); virtual std::string getInfoForThreadMonitor(); // For ThreadMonitor::Extra LateRecordCounter(); }; #endif