[Fix] AOF rewrite not working.

Fix for issue https://github.com/MSOpenTech/redis/issues/275
An existing fix was not working in Release mode because the compiler
optimization was removing the code that forces the VEH to map the memory page.
This commit is contained in:
Enrico Giordani
2015-08-20 13:18:52 +02:00
parent f1d1162123
commit 1c26e8c63b
6 changed files with 92 additions and 17 deletions
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Win32_Common.h"
namespace Globals
{
size_t pageSize = 0;
}
/* This function is used to force the VEH on the entire size of the buffer length,
in the event that the buffer crosses the memory page boundaries */
void EnsureMemoryIsMapped(const void *buffer, size_t size) {
/* Use 'volatile' to make sure the compiler doesn't remove "c = *((char*) (p + offset));" */
volatile char c;
char* p = (char*) buffer;
char* pStart = p - ((size_t) p % Globals::pageSize);
char* pEnd = p + size;
if ((size_t) (pEnd - pStart) > Globals::pageSize) {
size_t offset = 0;
while (offset < size) {
if (size < offset) {
offset = size;
} else {
offset += Globals::pageSize;
}
c = *((char*) (p + offset));
}
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WIN32_COMMON_H
#define WIN32_COMMON_H
void EnsureMemoryIsMapped(const void *buffer, size_t size);
namespace Globals {
// forward declarations only
extern size_t pageSize;
}
#endif
+2
View File
@@ -22,6 +22,7 @@
<ClCompile Include="win32fixes.c" />
<ClCompile Include="Win32_ANSI.c" />
<ClCompile Include="Win32_CommandLine.cpp" />
<ClCompile Include="Win32_Common.cpp" />
<ClCompile Include="Win32_dlmalloc.c" />
<ClCompile Include="Win32_EventLog.cpp" />
<ClCompile Include="Win32_FDAPI.cpp" />
@@ -45,6 +46,7 @@
<ClInclude Include="Win32_EventLog.h" />
<ClInclude Include="Win32_FDAPI.h" />
<ClInclude Include="Win32_fdapi_crt.h" />
<ClInclude Include="Win32_Common.h" />
<ClInclude Include="Win32_QFork.h" />
<ClInclude Include="Win32_QFork_impl.h" />
<ClInclude Include="Win32_RedisLog.h" />
+3 -3
View File
@@ -22,6 +22,7 @@
#include "win32_types.h"
#include "Win32_FDAPI.h"
#include "Win32_Common.h"
#include <Windows.h>
#include <WinNT.h>
@@ -161,7 +162,6 @@ const SIZE_T cAllocationGranularity = 1 << 18; // 256KB per h
const int cMaxBlocks = 1 << 24; // 256KB * 16M heap blocks = 4TB. 4TB is the largest memory config Windows supports at present.
const char* cMapFileBaseName = "RedisQFork";
const int cDeadForkWait = 30000;
size_t pageSize = 0;
#ifndef _WIN64
size_t cDefaultmaxHeap32Bit = 1 << 29; // 512MB
@@ -693,7 +693,7 @@ StartupStatus QForkStartup(int argc, char** argv) {
::redisLog(REDIS_WARNING, "Failing startup.\n");
return StartupStatus::ssFAILED;
}
pageSize = perfinfo.PageSize;
Globals::pageSize = perfinfo.PageSize;
/*
Not specifying the maxmemory or maxheap flags will result in the default behavior of: new key generation not
@@ -740,7 +740,7 @@ StartupStatus QForkStartup(int argc, char** argv) {
maxheapBytes = cSentinelHeapSize;
} else {
#ifdef _WIN64
maxheapBytes = perfinfo.PhysicalTotal * pageSize;
maxheapBytes = perfinfo.PhysicalTotal * Globals::pageSize;
#else
maxheapBytes = cDefaultmaxHeap32Bit;
#endif
+5 -13
View File
@@ -21,6 +21,7 @@
*/
#include "Win32_fdapi_crt.h"
#include "Win32_Common.h"
#include <io.h>
#include <stdlib.h>
@@ -56,22 +57,14 @@ int crtsetmode(int fd, int mode) {
return ::_setmode(fd, mode);
}
size_t crt_fwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File) {
size_t crt_fwrite(const void *buffer, size_t size, size_t count, FILE *file) {
// fwrite() somehow locks its view of the buffer. If during a fork operation the buffer has not been loaded into the forkee's process space,
// the VEH will be called to load the missing pages. Although the page gets loaded, fwrite() will not see the loaded page. The result is
// that fwrite will fail with errno set to ERROR_INVALID_USER_BUFFER. The fix is to force the buffer into memory before fwrite(). This only
// impacts wirites that straddle page boundaries.
const intptr_t pageSize = 4096;
char* p = (char*)_Str;
char* pageStart = p - ((intptr_t)p % pageSize);
char* pEnd = p + _Size;
if ((intptr_t)(pEnd - pageStart) > pageSize) {
for (size_t n = 0; n < _Size; n++) {
char x = *((char*)_Str + n);
}
}
// impacts writes that straddle page boundaries.
EnsureMemoryIsMapped(buffer, size);
return ::fwrite(buffer, size, count, file);
return ::fwrite(_Str, _Size, _Count, _File);
}
int crt_fclose(FILE* file) {
@@ -93,4 +86,3 @@ int crt_access(const char *pathname, int mode) {
__int64 crt_lseek64(int fd, __int64 offset, int origin) {
return _lseeki64(fd, offset, origin);
}
+1 -1
View File
@@ -32,7 +32,7 @@ int crt_open(const char *filename, int oflag, int pmode);
int crt_open_osfhandle(intptr_t osfhandle, int flags);
intptr_t crtget_osfhandle(int fd);
int crtsetmode(int fd, int mode);
size_t crt_fwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File);
size_t crt_fwrite(const void *buffer, size_t size, size_t count, FILE *file);
int crt_fclose(FILE* file);
int crt_fileno(FILE* file);