#ifndef __AutoSecondaryData_h_ #define __AutoSecondaryData_h_ #include "../shared/ContainerThread.h" /* This is a convenient way to load data from the alerts_daily table and other * secondary data sources. * * There are multiple ways make this data available. This sits on top of * the IAlertsDaily and AlertsDailyData classes. You could, for example, * directly access AlertsDailyData or make your own subclass of IAlertsDaily. * AutoSecondaryData, however, is meant to be a centralized place where a lot * of different modules can all place their requests. Because IAlertsDaily * requires classes to register themselves, and because only one can be active * at a time, different modules could get in each other's way. * AutoSecondaryData uses reference counts so multiple modules can all request * and dismiss data at their leisure, without interfering with each other. * * Other modules can specifically ask for certain data to be loaded. From the * command line ("-i auto_alerts_daily=1") you can also ask for the current * days from alerts_daily to be loaded. This module starts a background * thread which will periodically grab the latest from the database. */ class AutoSecondaryData : private ForeverThreadUser { private: enum { mtRequestDataNow /* Normally we automatically reread all data based on * a timer. This is an external request which will * reset the timer. We will reread all data very soon * after receive this message. */ }; const bool _alwaysWatchToday; // A value of n+1 means that n people are current using the data. (Not n // people, as you might expect.) If you increment the value and get 1, // that means that you are the first person to request the data, so you // are responsible for bringing the data into the cache and incrementing // the value a second time. If you decrement the value and get 1, that // means that no one is using the data, but it's still in the cache. If // the value stays 1 for long enough, the thread will eventually remove // the data from the cache, and remove the key from this variable. typedef std::map< std::string, int > AlertsDailyCount; AlertsDailyCount _alertsDailyCount; // If this thread automatically loads today's data, we request the data in // the normal way (i.e. we bump the reference count). As time passes, // we eventually change our request. We do this by removing our old // requests, then making new requests. This is where we store our old // requests, so we can clean those up. std::vector< std::string > _todayAuto; time_t _nextRefreshTime; void addAlertsDailyImpl(std::string const &date); void removeAlertsDailyImpl(std::string const &date); void checkTimer(); ~AutoSecondaryData(); AutoSecondaryData(); public: // Override these from IContainerThreadUser. virtual void beforeSleep(IBeforeSleepCallbacks &callbacks); virtual void initializeInThread(); virtual void handleRequestInThread(Request *original); // Request data for this date. This function is thread safe and // asynchronous. This increments a reference count. void addAlertsDaily(std::string const &date); // We are no longer interested in data for this date. This function is // thread safe an asynchronous. This decrements a reference count. The // data will not be erased before the reference count goes to 0. void removeAlertsDaily(std::string const &date); // Request a callback when all data is ready. Note that this doesn't know // which data the caller cares about. It does the callback when all data // is ready. That includes alerts daily for all days that anyone has // requested. That also includes other tables, like sector names. This // does not wait for data to be deleted. New data will be added as quckly as // possible. Old data will be deleted at some convenient time, eventually, // without any notification. Data will also be refreshed from the database // periodically, without any notification. void notifyWhenReady(RequestListener *listener, int callbackId); // This offers the same functionality as the previous version of // notifyWhenReady() but it uses lambda expressions rather than a // RequestListener. Lambda expressions are generally preferred in // newer code. void notifyWhenReady(std::function< void() > callback); static AutoSecondaryData &instance(); static void init() { instance(); } }; #endif