You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-30 19:23:07 +03:00
324 lines
9.1 KiB
C++
324 lines
9.1 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include <time.h>
|
|
#include <string>
|
|
#include <sys/types.h>
|
|
#include <map>
|
|
#include "boost/filesystem/operations.hpp"
|
|
#include "boost/filesystem/path.hpp"
|
|
namespace fs = boost::filesystem;
|
|
|
|
using namespace std;
|
|
|
|
#include "unistd.h"
|
|
#include "stdint.h"
|
|
#include "sys/time.h"
|
|
#include "syslog.h"
|
|
#include "idbregistry.h"
|
|
#include "WinSysLog.h"
|
|
|
|
// WinSyslog class encapsulates what substitutes for the syslog in the
|
|
// InfiniDB Windows version.
|
|
|
|
// Singleton instance
|
|
WinSyslog* WinSyslog::fpSysLog = WinSyslog::instance();
|
|
// For archive coordination.
|
|
// We have two mutexes. Only one will be used. We want to use the inter-process
|
|
// mutex name fhMutex. If creation succeeds, we set fbGoodIPMutex so the code knows
|
|
// it's good. If we fail, fMutex (Only this processes threads) will be used - it's
|
|
// better than nothing.
|
|
boost::mutex WinSyslog::fMutex; // Failsafe Intra process mutex
|
|
HANDLE WinSyslog::fhMutex; // Interprocess named mutex
|
|
bool WinSyslog::fbGoodIPMutex = false;
|
|
#define WINSYSLOG_MUTEX_NAME "WinSysLogMutex" // For the Windows Named Mutex
|
|
|
|
// Constructor, wherein we initialize everything
|
|
WinSyslog::WinSyslog() : fLastArchiveTime(0), fLastArchiveDay(0), fLogLineheaderSize(0)
|
|
{
|
|
fLogDirName = IDBreadRegistry("") + "\\log";
|
|
fLogFileName = IDBreadRegistry("") + "\\log\\InfiniDBLog.txt";
|
|
fTimeFileName = IDBreadRegistry("") + "\\log\\InfiniDBLastArchive.dat";
|
|
|
|
// Set up a buffer with all the line header except the timestamp.
|
|
// Leave room in the front for the timestamp.
|
|
// This header will approximate the linux standard syslog log header.
|
|
memset(fLogLineHeader, 0, LOG_BUF_SIZE);
|
|
char* pEnd = fLogLineHeader + LOG_BUF_SIZE;
|
|
char* pHeader = fLogLineHeader + TIMESTAMP_SIZE;
|
|
char exePath[LOG_BUF_SIZE];
|
|
DWORD nameSize = (DWORD)(pEnd - pHeader);
|
|
GetComputerName(pHeader, &nameSize);
|
|
pHeader += nameSize;
|
|
*pHeader++ = ' ';
|
|
GetModuleFileName(0, exePath, LOG_BUF_SIZE);
|
|
_splitpath_s(exePath, NULL, 0, NULL, 0, pHeader, pEnd - pHeader, NULL, 0);
|
|
pHeader += strlen(pHeader);
|
|
;
|
|
*pHeader++ = '[';
|
|
int pid = GetCurrentProcessId();
|
|
snprintf(pHeader, pEnd - pHeader, "%d", pid);
|
|
pHeader += strlen(pHeader);
|
|
;
|
|
*pHeader++ = ']';
|
|
*pHeader++ = ':';
|
|
fLogLineheaderSize = (int)(pHeader - fLogLineHeader);
|
|
// Set up the date we compare against for archiving.
|
|
// This will either be today (if fTimeFileName doesn't exist)
|
|
// or the the date stored in fTimeFileName.
|
|
time_t now = time(0);
|
|
FILE* lf;
|
|
lf = fopen(fTimeFileName.c_str(), "r+b");
|
|
|
|
if (lf == NULL) // First time archiving.
|
|
{
|
|
fLastArchiveTime = now;
|
|
// Persist the timestamp of last archive.
|
|
lf = fopen(fTimeFileName.c_str(), "w+b");
|
|
|
|
if (lf != 0)
|
|
{
|
|
fwrite(&fLastArchiveTime, sizeof(time_t), 1, lf);
|
|
fclose(lf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fread(&fLastArchiveTime, sizeof(time_t), 1, lf);
|
|
fclose(lf);
|
|
}
|
|
|
|
struct tm lasttm;
|
|
|
|
localtime_s(&lasttm, &fLastArchiveTime);
|
|
|
|
fLastArchiveDay = lasttm.tm_yday;
|
|
|
|
// Create an interprocess mutex to coordinate the archiving function
|
|
fhMutex = CreateMutex(NULL, FALSE, WINSYSLOG_MUTEX_NAME);
|
|
|
|
if (fhMutex == NULL)
|
|
{
|
|
syslog(LOG_ERR, "WinSyslog CreateMutex error: %d\n", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
fbGoodIPMutex = true;
|
|
}
|
|
}
|
|
|
|
WinSyslog::~WinSyslog()
|
|
{
|
|
CloseHandle(fhMutex);
|
|
}
|
|
|
|
// Log() is called by ::syslog() to actually write stuff to the file
|
|
int WinSyslog::Log(int priority, const char* format, va_list& args)
|
|
{
|
|
struct tm nowtm;
|
|
FILE* f;
|
|
time_t now = time(0);
|
|
|
|
localtime_s(&nowtm, &now);
|
|
|
|
// If now isn't the same day as the last archive date, archve.
|
|
if (nowtm.tm_yday != fLastArchiveDay)
|
|
{
|
|
Archive(nowtm);
|
|
}
|
|
|
|
// Log the line.
|
|
strftime(fLogLineHeader, TIMESTAMP_SIZE, "%b %d %H:%M:%S", &nowtm);
|
|
fLogLineHeader[TIMESTAMP_SIZE - 1] = ' ';
|
|
f = fopen(fLogFileName.c_str(), "a+");
|
|
|
|
if (f == 0)
|
|
return -1;
|
|
|
|
fwrite(fLogLineHeader, 1, fLogLineheaderSize, f);
|
|
vfprintf(f, format, args);
|
|
fwrite("\n", 1, 1, f);
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
// Archive() is called by Log() when the date changes
|
|
// Here we rename our log file to an archive name and delete
|
|
// any old files.
|
|
void WinSyslog::Archive(const tm& nowtm)
|
|
{
|
|
struct tm yesterdaytm;
|
|
bool bArchive = true;
|
|
time_t writeTime;
|
|
char ctimebuf[TIME_BUF_SIZE] = {0};
|
|
DWORD dwWaitResult;
|
|
char* szError = "";
|
|
|
|
// Lock it so we don't have two threads archiving.
|
|
if (fbGoodIPMutex)
|
|
{
|
|
// We have a good interprocess mutex. Try for one second to
|
|
// lock it. Abandon trying after a second. Something's stuck.
|
|
dwWaitResult = WaitForSingleObject(fhMutex, 1000);
|
|
|
|
switch (dwWaitResult)
|
|
{
|
|
// The thread got ownership of the mutex. Continue on.
|
|
case WAIT_OBJECT_0: break;
|
|
|
|
// The thread got ownership of an abandoned mutex, most likely because
|
|
// some process crashed in the middle of archiving. Continue on.
|
|
case WAIT_ABANDONED: break;
|
|
|
|
// We timed out. Something's not right. Don't archive.
|
|
case WAIT_TIMEOUT:
|
|
szError = "WinSyslog::Archive WAIT_TIMEOUT";
|
|
bArchive = false;
|
|
break;
|
|
|
|
// Horrible failure. Don't archive
|
|
case WAIT_FAILED:
|
|
szError = "WinSyslog::Archive WAIT_FAILED";
|
|
bArchive = false;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
boost::mutex::scoped_lock lock(fMutex);
|
|
}
|
|
|
|
try
|
|
{
|
|
// Check to see if any other thread or process already archived.
|
|
// If the value in fTimeFileName is different than our saved value
|
|
// Then somebody else beat us to it. Don't do it again.
|
|
time_t storedLastArchiveTime;
|
|
FILE* lf;
|
|
lf = fopen(fTimeFileName.c_str(), "r+b");
|
|
|
|
if (lf != NULL)
|
|
{
|
|
fread(&storedLastArchiveTime, sizeof(time_t), 1, lf);
|
|
fclose(lf);
|
|
|
|
if (storedLastArchiveTime != fLastArchiveTime)
|
|
{
|
|
bArchive = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we had something go wrong earlier, and then failed to read the Time file,
|
|
// this should prevent retrying to archive every log line.
|
|
storedLastArchiveTime = fLastArchiveTime = time(NULL);
|
|
}
|
|
|
|
if (bArchive == false)
|
|
{
|
|
// Something's not right. Try to set the internals so we don't attempt
|
|
// archiving again.
|
|
fLastArchiveTime = storedLastArchiveTime;
|
|
fLastArchiveDay = nowtm.tm_yday;
|
|
|
|
if (szError)
|
|
{
|
|
syslog(LOG_ERR, szError);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Get last archive date (usually yesterday)
|
|
yesterdaytm = nowtm;
|
|
yesterdaytm.tm_mday -= 1; // May be 0. mktime() adjusts accordingly.
|
|
time_t yesterday = mktime(&yesterdaytm);
|
|
localtime_s(&yesterdaytm, &yesterday);
|
|
string archiveFileName = fLogFileName;
|
|
size_t tail = archiveFileName.find(".txt");
|
|
archiveFileName.erase(tail, 4);
|
|
strftime(ctimebuf, TIME_BUF_SIZE, "-%Y-%m-%d.txt", &yesterdaytm);
|
|
archiveFileName += ctimebuf;
|
|
rename(fLogFileName.c_str(), archiveFileName.c_str());
|
|
|
|
// Persist the timestamp of last archive. In case of reboot, we
|
|
// can still archive properly
|
|
lf = fopen(fTimeFileName.c_str(), "w+b");
|
|
|
|
if (lf != 0)
|
|
{
|
|
fLastArchiveTime = time(0);
|
|
fwrite(&fLastArchiveTime, sizeof(time_t), 1, lf);
|
|
fclose(lf);
|
|
}
|
|
|
|
fLastArchiveDay = nowtm.tm_yday;
|
|
|
|
// Get the dates of all archive files.
|
|
fs::path sourceDir(fLogDirName);
|
|
fs::directory_iterator iter(sourceDir);
|
|
fs::directory_iterator end_iter;
|
|
std::multimap<std::time_t, fs::path> fileSet; // Stays sorted
|
|
|
|
while (iter != end_iter)
|
|
{
|
|
fs::path archiveFile = *iter;
|
|
|
|
if (fs::is_regular_file(archiveFile))
|
|
{
|
|
if (archiveFile.extension() == ".txt")
|
|
{
|
|
writeTime = fs::last_write_time(archiveFile);
|
|
fileSet.insert(make_pair(writeTime, archiveFile));
|
|
}
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
|
|
// Delete anything past the first seven newest files
|
|
typedef std::multimap<std::time_t, fs::path>::iterator PATH_ITER;
|
|
PATH_ITER fileIter = fileSet.begin();
|
|
PATH_ITER fileIterEnd = fileSet.end();
|
|
std::reverse_iterator<PATH_ITER> revEnd(fileIter);
|
|
std::reverse_iterator<PATH_ITER> revIter(fileIterEnd);
|
|
int cnt = 0;
|
|
|
|
for (; revIter != revEnd; ++revIter)
|
|
{
|
|
if (cnt++ < 7)
|
|
continue;
|
|
|
|
_wunlink(revIter->second.c_str());
|
|
}
|
|
}
|
|
catch (exception& e)
|
|
{
|
|
syslog(LOG_ERR, "WinSyslog::Archive Exception %s", e.what());
|
|
}
|
|
catch (...)
|
|
{
|
|
syslog(LOG_ERR, "WinSyslog::Archive Exception ...");
|
|
}
|
|
|
|
if (fbGoodIPMutex)
|
|
{
|
|
if (!ReleaseMutex(fhMutex))
|
|
syslog(LOG_ERR, "WinSyslog::Archive ReleaseMutex failed %d", GetLastError());
|
|
}
|
|
}
|