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
587 lines
13 KiB
C++
587 lines
13 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. */
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOMINMAX
|
|
#include <windows.h>
|
|
#include <conio.h>
|
|
#include <malloc.h>
|
|
#include <unistd.h>
|
|
#include <io.h>
|
|
#include <direct.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <psapi.h>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
//#define NDEBUG
|
|
#include <cassert>
|
|
#include <unistd.h>
|
|
using namespace std;
|
|
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
namespace ba = boost::algorithm;
|
|
|
|
#include "idbregistry.h"
|
|
#include "syslog.h"
|
|
|
|
namespace
|
|
{
|
|
bool vFlg;
|
|
bool useSCMAPI;
|
|
|
|
SERVICE_STATUS_HANDLE svcStatusHandle;
|
|
SERVICE_STATUS svcStatus;
|
|
HANDLE svcStopEvent;
|
|
|
|
struct ProcInfo
|
|
{
|
|
ProcInfo()
|
|
{
|
|
}
|
|
ProcInfo(const string& name) : pName(name)
|
|
{
|
|
}
|
|
string pName;
|
|
string pCmdLine;
|
|
};
|
|
|
|
typedef vector<ProcInfo> ProcInfoVec;
|
|
|
|
const int interProcessSleepTime = 2;
|
|
const size_t cmdLineLen = 128;
|
|
|
|
string installDir;
|
|
|
|
bool shuttingDown = false;
|
|
|
|
int runIt(const string& pName)
|
|
{
|
|
int rc = 0;
|
|
char* cmdLine = (char*)alloca(cmdLineLen);
|
|
strncpy_s(cmdLine, cmdLineLen, pName.c_str(), pName.size());
|
|
PROCESS_INFORMATION pInfo;
|
|
ZeroMemory(&pInfo, sizeof(pInfo));
|
|
STARTUPINFO sInfo;
|
|
ZeroMemory(&sInfo, sizeof(sInfo));
|
|
|
|
try
|
|
{
|
|
if (CreateProcess(0, cmdLine, 0, 0, false, 0, 0, 0, &sInfo, &pInfo) == 0)
|
|
return -1;
|
|
}
|
|
catch (exception& e)
|
|
{
|
|
cout << e.what() << endl;
|
|
}
|
|
|
|
if (WaitForSingleObject(pInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
|
|
{
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
|
|
DWORD exitCode;
|
|
|
|
if (GetExitCodeProcess(pInfo.hProcess, &exitCode) == 0)
|
|
{
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (exitCode != 0)
|
|
rc = -1;
|
|
|
|
out:
|
|
CloseHandle(pInfo.hProcess);
|
|
return rc;
|
|
}
|
|
|
|
int loadBRM()
|
|
{
|
|
// if no save file just return
|
|
string saveFile = installDir + "\\dbrm\\BRM_saves_current";
|
|
|
|
if (GetFileAttributes(saveFile.c_str()) == INVALID_FILE_ATTRIBUTES)
|
|
return 0;
|
|
|
|
// read contents of save file
|
|
ifstream ifs(saveFile.c_str());
|
|
|
|
if (!ifs)
|
|
return -1;
|
|
|
|
string saveFilePfx;
|
|
getline(ifs, saveFilePfx);
|
|
|
|
if (saveFilePfx.empty())
|
|
return 0;
|
|
|
|
// run load_brm and wait for it to finish
|
|
string brmCmd = "load_brm \"" + saveFilePfx + "\"";
|
|
|
|
if (runIt(brmCmd))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ReportSvcStatus(DWORD currentState, DWORD win32ExitCode, DWORD waitHint)
|
|
{
|
|
static DWORD checkPoint = 1;
|
|
|
|
svcStatus.dwCurrentState = currentState;
|
|
svcStatus.dwWin32ExitCode = win32ExitCode;
|
|
svcStatus.dwWaitHint = waitHint;
|
|
|
|
if (currentState == SERVICE_START_PENDING)
|
|
svcStatus.dwControlsAccepted = 0;
|
|
else
|
|
svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
|
|
|
if (currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED)
|
|
svcStatus.dwCheckPoint = 0;
|
|
else
|
|
svcStatus.dwCheckPoint = checkPoint++;
|
|
|
|
SetServiceStatus(svcStatusHandle, &svcStatus);
|
|
}
|
|
|
|
extern "C" DWORD WINAPI procRunner(LPVOID);
|
|
|
|
int startUp()
|
|
{
|
|
int rc;
|
|
|
|
syslog(LOG_INFO, "System is starting");
|
|
|
|
if (runIt("clearShm"))
|
|
return -1;
|
|
|
|
rc = loadBRM();
|
|
|
|
if (rc)
|
|
return rc;
|
|
|
|
ProcInfoVec procInfo;
|
|
procInfo.push_back(ProcInfo("workernode DBRM_Worker1 fg"));
|
|
procInfo.push_back(ProcInfo("controllernode fg"));
|
|
procInfo.push_back(ProcInfo("DecomSvr"));
|
|
procInfo.push_back(ProcInfo("PrimProc"));
|
|
procInfo.push_back(ProcInfo("WriteEngineServer"));
|
|
procInfo.push_back(ProcInfo("ExeMgr"));
|
|
procInfo.push_back(ProcInfo("DDLProc"));
|
|
procInfo.push_back(ProcInfo("DMLProc"));
|
|
string mysqldCmd = "mysqld --defaults-file=" + installDir + "\\my.ini";
|
|
procInfo.push_back(ProcInfo(mysqldCmd));
|
|
|
|
const ProcInfoVec::size_type numProcs = procInfo.size();
|
|
|
|
for (unsigned pidx = 0; pidx < numProcs; pidx++)
|
|
{
|
|
cout << "Starting " << procInfo[pidx].pName << "...";
|
|
|
|
HANDLE thd;
|
|
DWORD tid;
|
|
thd = CreateThread(0, 0, procRunner, &procInfo[pidx], 0, &tid);
|
|
|
|
if (thd == NULL)
|
|
{
|
|
LPTSTR lpBuffer;
|
|
LPTSTR* lppBuffer = &lpBuffer;
|
|
DWORD fmRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0,
|
|
GetLastError(), 0, (LPSTR)lppBuffer, 0, 0);
|
|
|
|
cerr << endl;
|
|
ostringstream ostr;
|
|
ostr << "Failed to start process runner thread for " << procInfo[pidx].pName << ": ";
|
|
|
|
if (fmRes > 0)
|
|
ostr << lpBuffer;
|
|
else
|
|
ostr << "Unknown error";
|
|
|
|
cerr << ostr.str() << endl;
|
|
syslog(LOG_ERR, ostr.str().c_str());
|
|
return -1;
|
|
}
|
|
|
|
Sleep(interProcessSleepTime * 1000);
|
|
cout << endl;
|
|
|
|
if (useSCMAPI)
|
|
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR,
|
|
interProcessSleepTime * (static_cast<DWORD>(numProcs) - pidx - 1) * 1000);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD WINAPI procRunner(LPVOID parms)
|
|
{
|
|
ProcInfo* pip = reinterpret_cast<ProcInfo*>(parms);
|
|
ProcInfo pi = *pip;
|
|
char* cmdLine = (char*)alloca(cmdLineLen);
|
|
strncpy_s(cmdLine, cmdLineLen, pi.pName.c_str(), pi.pName.size());
|
|
BOOL cpRc;
|
|
PROCESS_INFORMATION pInfo;
|
|
STARTUPINFO sInfo;
|
|
|
|
for (;;)
|
|
{
|
|
ZeroMemory(&sInfo, sizeof(sInfo));
|
|
ZeroMemory(&pInfo, sizeof(pInfo));
|
|
cpRc = CreateProcess(0, cmdLine, 0, 0, false, 0, 0, 0, &sInfo, &pInfo);
|
|
|
|
if (cpRc == 0)
|
|
{
|
|
LPTSTR lpBuffer;
|
|
LPTSTR* lppBuffer = &lpBuffer;
|
|
DWORD fmRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0,
|
|
GetLastError(), 0, (LPSTR)lppBuffer, 0, 0);
|
|
ostringstream ostr;
|
|
cerr << endl;
|
|
ostr << "Failed to start process " << pi.pName << ": ";
|
|
|
|
if (fmRes > 0)
|
|
ostr << lpBuffer;
|
|
else
|
|
ostr << "Unknown error";
|
|
|
|
cerr << ostr.str() << endl;
|
|
syslog(LOG_ERR, ostr.str().c_str());
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
ostringstream ostr;
|
|
ostr << pi.pName << " started ";
|
|
cerr << ostr.str() << endl;
|
|
syslog(LOG_INFO, ostr.str().c_str());
|
|
}
|
|
|
|
WaitForSingleObject(pInfo.hProcess, INFINITE);
|
|
ostringstream ostr;
|
|
ostr << pi.pName;
|
|
|
|
if (shuttingDown)
|
|
{
|
|
ostr << " shut down";
|
|
syslog(LOG_INFO, ostr.str().c_str());
|
|
}
|
|
else
|
|
{
|
|
ostr << " has died unexpectedly";
|
|
syslog(LOG_ERR, ostr.str().c_str());
|
|
}
|
|
|
|
cerr << ostr.str() << endl;
|
|
CloseHandle(pInfo.hProcess);
|
|
|
|
if (shuttingDown)
|
|
return 0;
|
|
|
|
Sleep(10 * 1000);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int killProcByPid(DWORD pid)
|
|
{
|
|
int rc = -1;
|
|
HANDLE hProc;
|
|
hProc = OpenProcess(PROCESS_TERMINATE, false, pid);
|
|
|
|
if (hProc != NULL)
|
|
{
|
|
if (TerminateProcess(hProc, 0) != 0)
|
|
rc = 0;
|
|
|
|
CloseHandle(hProc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD maxPids = 64;
|
|
DWORD* pids = 0;
|
|
|
|
int killProcByName(const string& pname)
|
|
{
|
|
if (!pids)
|
|
pids = (DWORD*)malloc(maxPids * sizeof(DWORD));
|
|
|
|
DWORD needed = 0;
|
|
|
|
if (EnumProcesses(pids, maxPids * sizeof(DWORD), &needed) == 0)
|
|
return -1;
|
|
|
|
while (needed == maxPids * sizeof(DWORD))
|
|
{
|
|
maxPids *= 2;
|
|
pids = (DWORD*)realloc(pids, maxPids * sizeof(DWORD));
|
|
|
|
if (EnumProcesses(pids, maxPids * sizeof(DWORD), &needed) == 0)
|
|
return -1;
|
|
}
|
|
|
|
int rc = -1;
|
|
DWORD numPids = needed / sizeof(DWORD);
|
|
DWORD i;
|
|
|
|
for (i = 0; i < numPids; i++)
|
|
{
|
|
bool found = false;
|
|
|
|
if (pids[i] != 0)
|
|
{
|
|
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
|
|
|
|
// Get a handle to the process.
|
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pids[i]);
|
|
|
|
// Get the process name.
|
|
if (NULL != hProcess)
|
|
{
|
|
HMODULE hMod;
|
|
DWORD cbNeeded;
|
|
|
|
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
|
|
{
|
|
GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
|
|
}
|
|
}
|
|
|
|
if (pname == szProcessName)
|
|
found = true;
|
|
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
rc = killProcByPid(pids[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int shutDown()
|
|
{
|
|
shuttingDown = true;
|
|
syslog(LOG_INFO, "System is shutting down");
|
|
|
|
vector<string> pList;
|
|
|
|
pList.push_back("mysqld.exe");
|
|
pList.push_back("DMLProc.exe");
|
|
pList.push_back("DDLProc.exe");
|
|
pList.push_back("ExeMgr.exe");
|
|
pList.push_back("WriteEngineServer.exe");
|
|
pList.push_back("PrimProc.exe");
|
|
pList.push_back("DecomSvr.exe");
|
|
pList.push_back("controllernode.exe");
|
|
pList.push_back("workernode.exe");
|
|
|
|
vector<string>::iterator iter = pList.begin();
|
|
vector<string>::iterator end = pList.end();
|
|
vector<string>::size_type i = pList.size();
|
|
|
|
while (iter != end)
|
|
{
|
|
if (killProcByName(*iter) == 0)
|
|
Sleep(interProcessSleepTime * 1000);
|
|
|
|
if (useSCMAPI)
|
|
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, static_cast<DWORD>(--i) * interProcessSleepTime * 1000);
|
|
|
|
++iter;
|
|
}
|
|
|
|
if (runIt("save_brm") == 0)
|
|
runIt("clearShm");
|
|
|
|
if (useSCMAPI)
|
|
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void svcStop()
|
|
{
|
|
useSCMAPI = true;
|
|
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 20 * 1000);
|
|
SetEvent(svcStopEvent);
|
|
}
|
|
|
|
extern "C" VOID WINAPI svcMain(DWORD, LPSTR*);
|
|
|
|
// The SCM has asked us to start as a service
|
|
int svcStart()
|
|
{
|
|
SERVICE_TABLE_ENTRY st[] = {
|
|
{"InfiniDB", svcMain},
|
|
{0, 0},
|
|
};
|
|
|
|
// This call returns when the service has stopped
|
|
StartServiceCtrlDispatcher(st);
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern "C" VOID WINAPI svcCtrlHandler(DWORD);
|
|
|
|
VOID WINAPI svcMain(DWORD dwArgc, LPSTR* lpszArgv)
|
|
{
|
|
useSCMAPI = true;
|
|
|
|
svcStatusHandle = RegisterServiceCtrlHandler("InfiniDB", svcCtrlHandler);
|
|
|
|
svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
svcStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, interProcessSleepTime * 7 * 1000);
|
|
|
|
svcStopEvent = CreateEvent(0, 1, 0, 0);
|
|
|
|
if (startUp() != 0)
|
|
{
|
|
ReportSvcStatus(SERVICE_STOPPED, 1, 0);
|
|
return;
|
|
}
|
|
|
|
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
|
|
|
WaitForSingleObject(svcStopEvent, INFINITE);
|
|
|
|
shutDown();
|
|
|
|
CloseHandle(svcStopEvent);
|
|
|
|
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
|
|
}
|
|
|
|
VOID WINAPI svcCtrlHandler(DWORD dwCtrl)
|
|
{
|
|
// Handle the requested control code.
|
|
|
|
switch (dwCtrl)
|
|
{
|
|
case SERVICE_CONTROL_STOP: // Notifies a service that it should stop
|
|
case SERVICE_CONTROL_SHUTDOWN: // Notifies a service that the system is shutting down so the service can
|
|
// perform cleanup tasks
|
|
svcStop();
|
|
break;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE: // Notifies a service that it should report its current status
|
|
// information to the service control manager
|
|
break;
|
|
|
|
case SERVICE_CONTROL_CONTINUE: // Notifies a paused service that it should resume
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PARAMCHANGE: // Notifies a service that its startup parameters have changed. The
|
|
// service should reread its startup parameters
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PAUSE: // Notifies a service that it should pause
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
opterr = 0;
|
|
vFlg = false;
|
|
int c;
|
|
int rc;
|
|
useSCMAPI = false;
|
|
|
|
while ((c = getopt(argc, argv, "v")) != EOF)
|
|
switch (c)
|
|
{
|
|
case 'v': vFlg = true; break;
|
|
|
|
case '?':
|
|
default: break;
|
|
}
|
|
|
|
if (!vFlg)
|
|
{
|
|
_close(0);
|
|
_close(1);
|
|
_close(2);
|
|
int fd = -1;
|
|
_sopen_s(&fd, "NUL", _O_TEXT | _O_RDONLY, _SH_DENYNO, _S_IREAD);
|
|
assert(fd == 0);
|
|
fd = -1;
|
|
_sopen_s(&fd, "NUL", _O_TEXT | _O_APPEND | _O_WRONLY, _SH_DENYNO, _S_IWRITE);
|
|
assert(fd == 1);
|
|
fd = -1;
|
|
_sopen_s(&fd, "NUL", _O_TEXT | _O_APPEND | _O_WRONLY, _SH_DENYNO, _S_IWRITE);
|
|
assert(fd == 2);
|
|
}
|
|
|
|
int (*cmdFp)();
|
|
|
|
string command;
|
|
|
|
if (argc - optind < 1)
|
|
command = "svcstart";
|
|
else
|
|
command = argv[optind];
|
|
|
|
if (ba::istarts_with(command, "sta"))
|
|
{
|
|
cmdFp = startUp;
|
|
}
|
|
else if (ba::istarts_with(command, "sto") || ba::istarts_with(command, "sh"))
|
|
{
|
|
cmdFp = shutDown;
|
|
}
|
|
else if (ba::istarts_with(command, "sv"))
|
|
{
|
|
cmdFp = svcStart;
|
|
}
|
|
else
|
|
{
|
|
cerr << "Unknown command " << command << " (try 'start' or 'shutdown')" << endl;
|
|
return 1;
|
|
}
|
|
|
|
installDir = IDBreadRegistry("", true);
|
|
|
|
string newDir = installDir + "\\bin";
|
|
rc = _chdir(newDir.c_str());
|
|
|
|
rc = cmdFp();
|
|
|
|
return (rc ? 1 : 0);
|
|
}
|