提交 52c98f5c 编写于 作者: J jonathan pickett

issue 126: fwrite() failure with buffers straddling page boundaries during background AOF save

上级 9613f9a2
......@@ -45,6 +45,7 @@ redis_WSACleanup WSACleanup = NULL;
redis_WSAGetOverlappedResult WSAGetOverlappedResult = NULL;
// other API forwards
redis_fwrite fdapi_fwrite = NULL;
redis_setmode fdapi_setmode = NULL;
redis_select select = NULL;
redis_ntohl ntohl = NULL;
......@@ -906,6 +907,10 @@ int redis_setmode_impl(int fd,int mode) {
return crtsetmode(fd,mode);
}
size_t redis_fwrite_impl(const void * _Str, size_t _Size, size_t _Count, FILE * _File) {
return crtfwrite(_Str, _Size, _Count, _File);
}
auto f_select = dllfunctor_stdcall<int, int, fd_set*, fd_set*, fd_set*, const struct timeval*>("ws2_32.dll", "select");
int redis_select_impl(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout) {
try {
......@@ -1053,6 +1058,7 @@ private:
inet_addr = redis_inet_addr_impl;
gethostbyname = redis_gethostbyname_impl;
inet_ntoa = redis_inet_ntoa_impl;
fdapi_fwrite = redis_fwrite_impl;
fdapi_setmode = redis_setmode_impl;
WSASetLastError = redis_WSASetLastError_impl;
WSAGetLastError = redis_WSAGetLastError_impl;
......
......@@ -40,6 +40,7 @@ typedef int ssize_t;
#define INCL_WINSOCK_API_PROTOTYPES 0 // Important! Do not include Winsock API definitions to avoid conflicts with API entry points defnied below.
#include <WinSock2.h>
#include <fcntl.h>
#include <stdio.h>
// the following are required to be defined before WS2tcpip is included.
typedef void (*redis_WSASetLastError)(int iError);
......@@ -149,6 +150,7 @@ typedef BOOL (*redis_WSAGetOverlappedResult)(int rfd,LPWSAOVERLAPPED lpOverlappe
// other API forwards
typedef int (*redis_setmode)(int fd,int mode);
typedef size_t (*redis_fwrite)(const void * _Str, size_t _Size, size_t _Count, FILE * _File);
// API prototypes must match the unix implementation
typedef int (*redis_socket)(int af,int type,int protocol);
......@@ -227,6 +229,7 @@ extern redis_getpeername getpeername;
extern redis_getsockname getsockname;
extern redis_ntohs ntohs;
extern redis_setmode fdapi_setmode;
extern redis_fwrite fdapi_fwrite;
extern redis_select select;
extern redis_ntohl ntohl;
......@@ -250,6 +253,7 @@ int FDAPI_UpdateAcceptContext( int fd );
#ifndef FDAPI_NOCRTREDEFS
#define close(fd) fdapi_close(fd)
#define setmode(fd,mode) fdapi_setmode(fd,mode)
#define fwrite(Str, Size, Count, File) fdapi_fwrite(Str,Size,Count,File)
#define _get_osfhandle(fd) fdapi_get_osfhandle(fd)
#define _INC_STAT_INL
......
......@@ -19,6 +19,7 @@
* 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_fdapi_crt.h"
#include <io.h>
#include <stdlib.h>
......@@ -47,6 +48,25 @@ int crtsetmode(int fd, int mode) {
return ::_setmode(fd, mode);
}
size_t crtfwrite(const void * _Str, 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);
}
}
return ::fwrite(_Str, _Size, _Count, _File);
}
int crt_isatty(int fd) {
return _isatty(fd);
}
......
......@@ -21,6 +21,7 @@
*/
#pragma once
#include <cstdint>
#include <stdio.h>
int crt_close(int fd);
int crt_read(int fd, void *buffer, unsigned int count);
......@@ -28,6 +29,7 @@ int crt_write(int fd, const void *buffer, unsigned int count);
int crt_open(const char *filename, int oflag, int pmode);
intptr_t crtget_osfhandle(int fd);
int crtsetmode(int fd, int mode);
size_t crtfwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File);
int crt_isatty(int fd);
int crt_access(const char *pathname, int mode);
__int64 crt_lseek64(int fd, __int64 offset, int origin);
\ No newline at end of file
......@@ -54,7 +54,7 @@
#include "rio.h"
#include "util.h"
#ifdef _WIN32
//#include "win32fixes.h"
#include "Win32_Interop\Win32_FDAPI.h"
#endif
#include "config.h"
#include "redis.h"
......@@ -86,7 +86,6 @@ static off_t rioBufferTell(rio *r) {
/* Returns 1 or 0 for success/failure. */
static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
size_t retval;
retval = fwrite(buf,len,1,r->io.file.fp);
r->io.file.buffered += (off_t)len;
......
......@@ -112,6 +112,10 @@
#include "endianconv.h"
#include "redisassert.h"
#ifdef _WIN32
#include "Win32_Interop\Win32_FDAPI.h"
#endif
#define ZIP_END 255
#define ZIP_BIGLEN 254
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册