提交 2959371b 编写于 作者: J Jonathan Pickett

adding --maxheapgb flag to startup to control size of memory mapped file created

上级 2277ed0e
......@@ -122,7 +122,9 @@ const int cMaxBlocks = 1 << 16; // 64KB*64K sec
const SIZE_T cSystemReserve = 3 * 1024i64 * 1024i64 * 1024i64; // Reserve left for Windows to operate on when we are heavily loaded.
const wchar_t* cMapFileBaseName = L"RedisQFork";
const char* qforkFlag = "--QFork";
const char* maxheapgbFlag = "--maxheapgb";
const int cDeadForkWait = 30000;
const SIZE_T cBytesInGB = (SIZE_T)1024 * (SIZE_T)1024 * (SIZE_T)1024;
typedef enum BlockState {
bsINVALID = 0,
......@@ -248,167 +250,189 @@ BOOL QForkSlaveInit(HANDLE QForkConrolMemoryMapHandle, DWORD ParentProcessID) {
}
BOOL QForkMasterInit() {
// allocate file map for qfork control so it can be passed to the forked process
g_hQForkControlFileMap = CreateFileMappingW(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0, sizeof(QForkControl),
NULL);
if (g_hQForkControlFileMap == NULL) {
printf( "Problem with CreateFileMapping\n");
errno = EBADF;
goto err;
}
g_pQForkControl = (QForkControl*)MapViewOfFile(
g_hQForkControlFileMap,
FILE_MAP_ALL_ACCESS,
0, 0,
0);
if (g_pQForkControl == NULL) {
printf( "Problem with MapViewOfFile\n");
errno = ENOMEM;
goto err;
}
// This must be called only once per process! Calling it more times than that will not recreate existing
// section, and dlmalloc will ultimately fail with an access violation. Once is good.
if (dlmallopt(M_GRANULARITY, cAllocationGranularity) == 0) {
printf( "DLMalloc failed initializing allocation granularity.\n");
errno = ENOMEM;
goto err;
}
g_pQForkControl->heapBlockSize = cAllocationGranularity;
// determine the number of blocks we can allocate
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&ms);
SIZE_T maxPhysicalMapping = ms.ullTotalPhys - cSystemReserve;
g_pQForkControl->availableBlocksInHeap = (int)(maxPhysicalMapping / cAllocationGranularity);
if (g_pQForkControl->availableBlocksInHeap <= 0) {
printf( "Not enough physical memory to initialize Redis. Physical memory must be greater than 3GB.\n");
errno = ENOMEM;
goto err;
}
wchar_t heapMemoryMapPath[MAX_PATH];
swprintf_s(
heapMemoryMapPath,
MAX_PATH,
L"%s_%d.dat",
cMapFileBaseName,
GetCurrentProcessId());
g_pQForkControl->heapMemoryMapFile =
CreateFileW(
heapMemoryMapPath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL| FILE_FLAG_DELETE_ON_CLOSE,
NULL );
if (g_pQForkControl->heapMemoryMapFile == INVALID_HANDLE_VALUE) {
printf( "Problem creating memory mapped file.\n");
errno = EBADF;
goto err;
}
SIZE_T mmSize = g_pQForkControl->availableBlocksInHeap * cAllocationGranularity;
g_pQForkControl->heapMemoryMap =
CreateFileMappingW(
g_pQForkControl->heapMemoryMapFile,
BOOL QForkMasterInit( int maxHeapGB ) {
try {
// allocate file map for qfork control so it can be passed to the forked process
g_hQForkControlFileMap = CreateFileMappingW(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
HIDWORD(mmSize),
LODWORD(mmSize),
0, sizeof(QForkControl),
NULL);
if (g_pQForkControl->heapMemoryMap == NULL) {
printf( "Problem mapping heap.\n");
errno = EBADF;
goto err;
}
// Find a place in the virtual memory space where we can reserve space for our allocations that is likely
// to be available in the forked process. (If this ever fails in the forked process, we will have to launch
// the forked process and negotiate for a shared memory address here.)
LPVOID pHigh = VirtualAllocEx(
GetCurrentProcess(),
NULL,
mmSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_READWRITE);
if (pHigh == NULL) {
printf( "Viirtual memory reservation failed.\n");
DWORD err = GetLastError();
errno = ENOMEM;
goto err;
}
if (VirtualFree(pHigh, 0, MEM_RELEASE) == FALSE) {
DWORD err = GetLastError();
errno = ENOMEM;
goto err;
}
if (g_hQForkControlFileMap == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateFileMapping failed");
}
g_pQForkControl->heapStart =
MapViewOfFileEx(
g_pQForkControl->heapMemoryMap,
g_pQForkControl = (QForkControl*)MapViewOfFile(
g_hQForkControlFileMap,
FILE_MAP_ALL_ACCESS,
0,0,
0,
pHigh);
if (g_pQForkControl->heapStart == NULL) {
printf( "Mapping view of heap failed.\n");
DWORD err = GetLastError();
errno = ENOMEM;
goto err;
}
0, 0,
0);
if (g_pQForkControl == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: MapViewOfFile failed");
}
for (int n = 0; n < cMaxBlocks; n++) {
g_pQForkControl->heapBlockMap[n] =
((n < g_pQForkControl->availableBlocksInHeap) ?
BlockState::bsUNMAPPED : BlockState::bsINVALID);
}
// This must be called only once per process! Calling it more times than that will not recreate existing
// section, and dlmalloc will ultimately fail with an access violation. Once is good.
if (dlmallopt(M_GRANULARITY, cAllocationGranularity) == 0) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: DLMalloc failed initializing allocation granularity.");
}
g_pQForkControl->heapBlockSize = cAllocationGranularity;
// determine the number of blocks we can allocate
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&ms);
SIZE_T maxPhysicalMapping = ms.ullTotalPhys - cSystemReserve;
if (maxHeapGB != -1) {
SIZE_T maxHeap = (SIZE_T)maxHeapGB * cBytesInGB;
maxPhysicalMapping = min(maxPhysicalMapping,maxHeap);
}
g_pQForkControl->availableBlocksInHeap = (int)(maxPhysicalMapping / cAllocationGranularity);
if (g_pQForkControl->availableBlocksInHeap <= 0) {
throw std::runtime_error(
"QForkMasterInit: Not enough physical memory to initialize Redis. Physical memory must be greater than 3GB.");
}
g_pQForkControl->typeOfOperation = OperationType::otINVALID;
g_pQForkControl->forkedProcessReady = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->forkedProcessReady == NULL) {
errno = EBADF;
goto err;
}
g_pQForkControl->startOperation = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->startOperation == NULL) {
errno = EBADF;
goto err;
}
g_pQForkControl->operationComplete = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->operationComplete == NULL) {
errno = EBADF;
goto err;
wchar_t heapMemoryMapPath[MAX_PATH];
swprintf_s(
heapMemoryMapPath,
MAX_PATH,
L"%s_%d.dat",
cMapFileBaseName,
GetCurrentProcessId());
g_pQForkControl->heapMemoryMapFile =
CreateFileW(
heapMemoryMapPath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL| FILE_FLAG_DELETE_ON_CLOSE,
NULL );
if (g_pQForkControl->heapMemoryMapFile == INVALID_HANDLE_VALUE) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateFileW failed.");
}
SIZE_T mmSize = g_pQForkControl->availableBlocksInHeap * cAllocationGranularity;
g_pQForkControl->heapMemoryMap =
CreateFileMappingW(
g_pQForkControl->heapMemoryMapFile,
NULL,
PAGE_READWRITE,
HIDWORD(mmSize),
LODWORD(mmSize),
NULL);
if (g_pQForkControl->heapMemoryMap == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateFileMapping failed.");
}
// Find a place in the virtual memory space where we can reserve space for our allocations that is likely
// to be available in the forked process. (If this ever fails in the forked process, we will have to launch
// the forked process and negotiate for a shared memory address here.)
LPVOID pHigh = VirtualAllocEx(
GetCurrentProcess(),
NULL,
mmSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_READWRITE);
if (pHigh == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: VirtualAllocEx failed.");
}
if (VirtualFree(pHigh, 0, MEM_RELEASE) == FALSE) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: VirtualFree failed.");
}
g_pQForkControl->heapStart =
MapViewOfFileEx(
g_pQForkControl->heapMemoryMap,
FILE_MAP_ALL_ACCESS,
0,0,
0,
pHigh);
if (g_pQForkControl->heapStart == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: MapViewOfFileEx failed.");
}
for (int n = 0; n < cMaxBlocks; n++) {
g_pQForkControl->heapBlockMap[n] =
((n < g_pQForkControl->availableBlocksInHeap) ?
BlockState::bsUNMAPPED : BlockState::bsINVALID);
}
g_pQForkControl->typeOfOperation = OperationType::otINVALID;
g_pQForkControl->forkedProcessReady = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->forkedProcessReady == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateEvent failed.");
}
g_pQForkControl->startOperation = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->startOperation == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateEvent failed.");
}
g_pQForkControl->operationComplete = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->operationComplete == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateEvent failed.");
}
g_pQForkControl->operationFailed = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->operationFailed == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateEvent failed.");
}
g_pQForkControl->terminateForkedProcess = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->terminateForkedProcess == NULL) {
throw std::system_error(
GetLastError(),
system_category(),
"QForkMasterInit: CreateEvent failed.");
}
return TRUE;
}
g_pQForkControl->operationFailed = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->operationFailed == NULL) {
errno = EBADF;
goto err;
catch(std::system_error syserr) {
printf("QForkMasterInit: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
}
g_pQForkControl->terminateForkedProcess = CreateEvent(NULL,TRUE,FALSE,NULL);
if (g_pQForkControl->terminateForkedProcess == NULL) {
errno = EBADF;
goto err;
catch(std::runtime_error runerr) {
printf("QForkMasterInit: runtime error caught. message=%s\n", runerr.what());
}
return TRUE;
err:
printf( "Error ocurred initializing Redis.");
if( GetLastError() != 0 ) {
printf( " GetLastError() returns 0x%08x", GetLastError());
catch(...) {
printf("QForkMasterInit: other exception caught.\n");
}
printf( "\n");
return FALSE;
}
......@@ -418,6 +442,7 @@ StartupStatus QForkStartup(int argc, char** argv) {
bool foundSlaveFlag = false;
HANDLE QForkConrolMemoryMapHandle = NULL;
DWORD PPID = 0;
int maxHeapGB = -1;
if ((argc == 3) && (strcmp(argv[0], qforkFlag) == 0)) {
// slave command line looks like: --QFork [QForkConrolMemoryMap handle] [parent process id]
foundSlaveFlag = true;
......@@ -425,12 +450,28 @@ StartupStatus QForkStartup(int argc, char** argv) {
QForkConrolMemoryMapHandle = (HANDLE)strtoul(argv[1],&endPtr,10);
char* end = NULL;
PPID = strtoul(argv[2], &end, 10);
} else {
for (int n = 0; n < argc - 1; n++) {
if (_stricmp(argv[n],maxheapgbFlag) == 0) {
maxHeapGB = atoi(argv[n+1]);
if (maxHeapGB == 0) {
printf (
"%s specified. Unable to convert %s to the maximum number of gigabytes to use for the heap.\n",
maxheapgbFlag,
argv[n+1] );
printf( "Failing startup.\n");
return StartupStatus::ssFAILED;
} else {
break;
}
}
}
}
if (foundSlaveFlag) {
return QForkSlaveInit( QForkConrolMemoryMapHandle, PPID ) ? StartupStatus::ssSLAVE_EXIT : StartupStatus::ssFAILED;
} else {
return QForkMasterInit() ? StartupStatus::ssCONTINUE_AS_MASTER : StartupStatus::ssFAILED;
return QForkMasterInit(maxHeapGB) ? StartupStatus::ssCONTINUE_AS_MASTER : StartupStatus::ssFAILED;
}
}
......@@ -599,8 +640,8 @@ BOOL BeginForkOperation(OperationType type, char* fileName, LPVOID globalData, i
catch(std::system_error syserr) {
printf("BeginForkOperation: system error caught. error code=0x%08x, message=%s\n", syserr.code().value(), syserr.what());
}
catch(std::runtime_error syserr) {
printf("BeginForkOperation: runtime error caught. message=%s\n", syserr.what());
catch(std::runtime_error runerr) {
printf("BeginForkOperation: runtime error caught. message=%s\n", runerr.what());
}
catch(...) {
printf("BeginForkOperation: other exception caught.\n");
......
......@@ -491,6 +491,10 @@ void loadServerConfigFromString(char *config) {
err = sentinelHandleConfiguration(argv+1,argc-1);
if (err) goto loaderr;
}
#ifdef _WIN32
} else if (!strcasecmp(argv[0],"maxheapgb")) {
// this flag is for QFork infrastructure and has already been handled
#endif
} else {
err = "Bad directive or wrong number of arguments"; goto loaderr;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册