// datalogger.h : // #if !defined(AGD_DATALOGGER_H__21BAEB7B_E478_4ED1_B9F6_FDBCE620C55B__INCLUDED_) #define AGD_DATALOGGER_H__21BAEB7B_E478_4ED1_B9F6_FDBCE620C55B__INCLUDED_ #include #include #include #ifndef _LIBBUILD #include #include #else // _LIBBUILD #include "common/mysqlwrap.h" #include "common/logfile.h" #endif // _LIBBUILD ///////////////////////////////////////////////////////////////////////////// // datalogger.h - Declarations: #define _DL_DATABASE_ENGINE_INNODB 1 #define _DL_DATABASE_ENGINE_MYISAM 2 ///////////////////////////////////////////////////////////////////////////// #define _DL_USE_NEW_TABLES_LAYOUT 1 #define _DL_DATABSE_ENGINE _DL_DATABASE_ENGINE_INNODB ///////////////////////////////////////////////////////////////////////////// #if _DL_DATABSE_ENGINE == _DL_DATABASE_ENGINE_INNODB #define _DL_DATABSE_ENGINE_NAME "InnoDB" #define _DL_MAX_VARPATH_LENGTH 767 #elif _DL_DATABSE_ENGINE == _DL_DATABASE_ENGINE_MYISAM #define _DL_DATABSE_ENGINE_NAME "MyISAM" #define _DL_MAX_VARPATH_LENGTH 1000 #else // _DL_DATABSE_ENGINE #error Invalid database engine! #endif // _DL_DATABSE_ENGINE ///////////////////////////////////////////////////////////////////////////// #define _DL_NANOSECS_PER_SEC 1000000000 #define _DL_MAX_DB_NAME_LENGTH 64 #define _DL_MAX_DB_USER_LENGTH 64 #define _DL_MAX_DB_PASS_LENGTH 64 #define _DL_MAX_TABLE_NAME_LENGTH 64 #define _SECONDS_PER_DAY 86400 #define _MIDNIGHT_TIMESTAMP_UTC(t) ((t) / _SECONDS_PER_DAY * _SECONDS_PER_DAY) typedef enum _LogTypes { LT_NoLog, LT_IntervalConditional, LT_IntervalUnconditional, LT_ValueChangeConditional, LT_ValueChangeUnconditional, LT_IntervalConditionalRem, LT_IntervalUnconditionalRem, LT_ValueChangeConditionalRem, LT_ValueChangeUnconditionalRem }LogTypes, *LPLogTypes; #define _IS_VALID_LOGTYPE(lt) (((lt) > LT_NoLog) && ((lt) <= LT_ValueChangeUnconditionalRem)) #define _IS_VALUE_CHANGE_LOGTYPE(lt) (((lt) == LT_ValueChangeConditional) || ((lt) == LT_ValueChangeUnconditional) || ((lt) == LT_ValueChangeConditionalRem) || ((lt) == LT_ValueChangeUnconditionalRem)) #define _IS_INTERVAL_LOGTYPE(lt) (((lt) == LT_IntervalConditional) || ((lt) == LT_IntervalUnconditional) || ((lt) == LT_IntervalConditionalRem) || ((lt) == LT_IntervalUnconditionalRem)) #define _IS_CONDITIONAL_LOGTYPE(lt) (((lt) == LT_ValueChangeConditional) || ((lt) == LT_IntervalConditional) || ((lt) == LT_ValueChangeConditionalRem) || ((lt) == LT_IntervalConditionalRem)) #define _IS_UNCONDITIONAL_LOGTYPE(lt) (((lt) == LT_IntervalUnconditional) || ((lt) == LT_ValueChangeUnconditional) || ((lt) == LT_IntervalUnconditionalRem) || ((lt) == LT_ValueChangeUnconditionalRem)) #define _IS_DB_PERSISTENT_LOGTYPE(lt) (((lt) >= LT_IntervalConditionalRem) && ((lt) <= LT_ValueChangeUnconditionalRem)) typedef struct _DLPARAMS { char szDBName[_DL_MAX_DB_NAME_LENGTH]; char szDBUser[_DL_MAX_DB_USER_LENGTH]; char szDBPass[_DL_MAX_DB_PASS_LENGTH]; char szTagsTable[_DL_MAX_TABLE_NAME_LENGTH]; char szLogsTable[_DL_MAX_TABLE_NAME_LENGTH]; char szLogsTableBD[_DL_MAX_TABLE_NAME_LENGTH]; // bad date logs table const char *pszBaseDir; unsigned int nIntvSample; // sample interval unsigned int nIntvLog; // log interval unsigned int nIntvFlush; // flush interval unsigned int nMaxAge; // Max age of Logs entries in days unsigned long long nMaxSize; // max. Logs table size in Byte bool bMinMax; // log min max values as well? }DLPARAMS, *LPDLPARAMS; typedef const DLPARAMS *LPCDLPARAMS; typedef struct _DL_LOG_ENTRY { unsigned long nTagID; time_t nTimestamp; double fValue; double fMin; double fMax; int nIndex; LogTypes lt; bool bNull; }DL_LOG_ENTRY, *LPDL_LOG_ENTRY; typedef const DL_LOG_ENTRY *LPCDL_LOG_ENTRY; typedef struct _MYSQL_GLOBAL_VARS { bool bLogsTblIsInnoDB; bool bInnoDbFilePerTable; bool bInnoDbIsBarracuda; bool bInnoDbIsStrictMode; char szInnoDbFileFormat[64]; char szDataDir[PATH_MAX]; }MYSQL_GLOBAL_VARS, *LPMYSQL_GLOBAL_VARS; typedef const MYSQL_GLOBAL_VARS *LPCMYSQL_GLOBAL_VARS; ///////////////////////////////////////////////////////////////////////////// class CDataLogger { public: CDataLogger(LPCDLPARAMS pdlp, CLogfile &rlf); virtual ~CDataLogger(void); bool InitDatabase(bool bEnforceCreate = false); void Release(void); unsigned long GetTagID(const char *pszVarPath, int nDataType, int nLogType); bool Log(unsigned long nTagID, double fValue, double fMin, double fMax, time_t nTimestamp, int nIndex, LogTypes lt, bool bNull = false, bool bNoBadDateCheck = false); bool Flush(time_t nTimestamp); bool TableFileExists(const char *pszTableName); int64_t TableFileSize(const char *pszTableName); void SizeGuardTrigger(time_t ts); time_t LastLogTimestamp(void){ return m_nLastLogTimestamp;} bool SizeGuardDayWorkDone(time_t ts){ return m_nSGLastPassUTC == (unsigned long long)_MIDNIGHT_TIMESTAMP_UTC(ts);} bool Lock(void){ return !::pthread_mutex_lock(&m_mtx);} bool TryLock(void){ return !::pthread_mutex_trylock(&m_mtx);} bool Unlock(void){ return !::pthread_mutex_unlock(&m_mtx);} private: bool CreateDatabase(CMySqlDB &rdb, bool bEnforceCreate = false); bool CreateTagsTable(CMySqlDB &rdb); bool AlterTagsTable(CMySqlDB &rdb); bool CreateLogsTable(CMySqlDB &rdb); bool CreateLogsBDTable(CMySqlDB &rdb); bool CheckTable(CMySqlDB &rdb, const char *pszTableName, bool &bExists, bool &bUseResortTable, bool &bIsInnoDB); // bool QueryTableSizes(CMySqlDB &rdb, const char *pszTableName); bool DoSizeGuard(void); bool ReadGlobalOptions(CMySqlDB &rdb); bool QueryServerVariable(CMySqlDB &rdb, const char *pszVarname, CMySqlVar &val); // bool QueryStatusVariable(CMySqlDB &rdb, const char *pszVarname, CMySqlVar &val); static void* SizeGuardWorker(void* pParam); unsigned long long SizeGuardLastPassRead(void); void SizeGuardLastPassWrite(unsigned long long ts); static size_t Timestamp2String(time_t t, char *pszBuffer, size_t nCbBuffer); static const char* Ns2String(unsigned long long nNs, char *pszBuffer, size_t nCbBuffer); static const char* Ms2String(double fMs, char *pszBuffer, size_t nCbBuffer); time_t GetLastLogTimestamp(CMySqlDB &rdb); private: CLogfile &m_lf; DLPARAMS m_dlp; MYSQL_GLOBAL_VARS m_gv; char m_szAppDir[PATH_MAX]; std::vector m_logs; std::vector m_logsBD; pthread_t m_tidSGThread; bool m_bSGHasSizeLimitPrerequisites; bool m_bSGInProgress; bool m_bSGConfigured; unsigned long long m_nSGCurPassUTC; unsigned long long m_nSGLastPassUTC; pthread_mutex_t m_mtx; pthread_mutexattr_t m_mutexAttr; pthread_mutex_t m_condmtx1; pthread_cond_t m_cond1; time_t m_nLastLogTimestamp; bool m_bBadDateLogsDetected; }; ///////////////////////////////////////////////////////////////////////////// class CDataLoggerClock { public: CDataLoggerClock(unsigned long long nSampleTimeNs); virtual ~CDataLoggerClock(void); static unsigned long long GetNanoTick(struct timespec *pts = NULL); inline static unsigned long long GetMicroTick(struct timespec *pts = NULL){ return GetNanoTick(pts) / 1000;} inline static unsigned long long GetMilliTick(struct timespec *pts = NULL){ return GetNanoTick(pts) / 1000000;} inline static unsigned long long Timespec2NanoSec(const struct timespec *pts){ return (unsigned long long)pts->tv_sec * _DL_NANOSECS_PER_SEC + (unsigned long long)pts-> tv_nsec;} inline static void NanoSec2Timespec(unsigned long long n, struct timespec *pts){ if(pts){ pts->tv_sec = n / _DL_NANOSECS_PER_SEC; pts->tv_nsec = n % _DL_NANOSECS_PER_SEC; }} inline static long long CompareTimespec(const struct timespec *pts1, const struct timespec *pts2){ unsigned long long n1 = Timespec2NanoSec(pts1); unsigned long long n2 = Timespec2NanoSec(pts2); return (long long)(n1 - n2);} bool Sleep(bool &bTimerUnderrun, bool fAvoidCatchUpRaceOnTimerUnderrun); private: inline unsigned long long IncTime(struct timespec *pts, long long ns) const { unsigned long long n = Timespec2NanoSec(pts); n += ns; NanoSec2Timespec(n, pts); return n;} private: struct timespec m_tsDueTime; bool m_fSleepStarted; const long long m_nSampleTimeNs; }; ///////////////////////////////////////////////////////////////////////////// #endif // !defined(AGD_DATALOGGER_H__21BAEB7B_E478_4ED1_B9F6_FDBCE620C55B__INCLUDED_)