You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			326 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			10 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());
 | 
						|
    }
 | 
						|
}
 |