windows sockets with IOCP

This commit is contained in:
Henry Rawas
2012-02-09 16:27:08 -08:00
committed by Igor Zinkovsky
parent 734dabb6b7
commit ac1cdea778
64 changed files with 4498 additions and 241 deletions
+20
View File
@@ -17,3 +17,23 @@ release.h
src/transfer.sh
src/configs
src/redis-server.dSYM
*.user
*.exe
*.sdf
*.suo
deps/pthreads-win32/
msvs/Debug/
msvs/Release/
msvs/RedisBenchmark/Debug/
msvs/RedisBenchmark/Release/
msvs/RedisCheckAof/Debug/
msvs/RedisCheckAof/Release/
msvs/RedisCheckDump/Debug/
msvs/RedisCheckDump/Release/
msvs/RedisCli/Debug/
msvs/RedisCli/Release/
msvs/hiredis/Debug/
msvs/hiredis/Release/
msvs/ipch
msvs/RedisServer.opensdf
+9 -2
View File
@@ -30,7 +30,9 @@
*/
#include <string.h>
#include <strings.h>
#ifndef _WIN32
#include <strings.h>
#endif
#include <assert.h>
#include <ctype.h>
#include "async.h"
@@ -38,6 +40,11 @@
#include "sds.h"
#include "util.h"
#ifdef _WIN32
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
/* Forward declaration of function in hiredis.c */
void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
@@ -47,8 +54,8 @@ static unsigned int callbackHash(const void *key) {
}
static void *callbackValDup(void *privdata, const void *src) {
((void) privdata);
redisCallback *dup = malloc(sizeof(*dup));
((void) privdata);
memcpy(dup,src,sizeof(*dup));
return dup;
}
+65
View File
@@ -42,7 +42,11 @@
/* -------------------------- private prototypes ---------------------------- */
static int _dictExpandIfNeeded(dict *ht);
#ifdef _WIN32
static size_t _dictNextPower(size_t size);
#else
static unsigned long _dictNextPower(unsigned long size);
#endif
static int _dictKeyIndex(dict *ht, const void *key);
static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
@@ -85,6 +89,53 @@ static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
}
/* Expand or create the hashtable */
#ifdef _WIN32
static int dictExpand(dict *ht, size_t size) {
dict n; /* the new hashtable */
size_t realsize = _dictNextPower(size), i;
/* the size is invalid if it is smaller than the number of
* elements already inside the hashtable */
if (ht->used > size)
return DICT_ERR;
_dictInit(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize-1;
n.table = calloc(realsize,sizeof(dictEntry*));
/* Copy all the elements from the old to the new table:
* note that if the old hash table is empty ht->size is zero,
* so dictExpand just creates an hash table. */
n.used = ht->used;
for (i = 0; i < ht->size && ht->used > 0; i++) {
dictEntry *he, *nextHe;
if (ht->table[i] == NULL) continue;
/* For each hash entry on this slot... */
he = ht->table[i];
while(he) {
unsigned int h;
nextHe = he->next;
/* Get the new element index */
h = dictHashKey(ht, he->key) & n.sizemask;
he->next = n.table[h];
n.table[h] = he;
ht->used--;
/* Pass to the next element */
he = nextHe;
}
}
assert(ht->used == 0);
free(ht->table);
/* Remap the new hashtable in the old */
*ht = n;
return DICT_OK;
}
#else
static int dictExpand(dict *ht, unsigned long size) {
dict n; /* the new hashtable */
unsigned long realsize = _dictNextPower(size), i;
@@ -130,6 +181,7 @@ static int dictExpand(dict *ht, unsigned long size) {
*ht = n;
return DICT_OK;
}
#endif
/* Add an element to the target hash table */
static int dictAdd(dict *ht, void *key, void *val) {
@@ -303,6 +355,18 @@ static int _dictExpandIfNeeded(dict *ht) {
}
/* Our hash table capability is a power of two */
#ifdef _WIN32
static size_t _dictNextPower(size_t size) {
size_t i = DICT_HT_INITIAL_SIZE;
if (size >= LONG_MAX) return LONG_MAX;
while(1) {
if (i >= size)
return i;
i *= 2;
}
}
#else
static unsigned long _dictNextPower(unsigned long size) {
unsigned long i = DICT_HT_INITIAL_SIZE;
@@ -313,6 +377,7 @@ static unsigned long _dictNextPower(unsigned long size) {
i *= 2;
}
}
#endif
/* Returns the index of a free slot that can be populated with
* an hash entry for the given 'key'.
+10
View File
@@ -60,9 +60,15 @@ typedef struct dictType {
typedef struct dict {
dictEntry **table;
dictType *type;
#ifdef _WIN32
size_t size;
size_t sizemask;
size_t used;
#else
unsigned long size;
unsigned long sizemask;
unsigned long used;
#endif
void *privdata;
} dict;
@@ -113,7 +119,11 @@ typedef struct dictIterator {
/* API */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
static dict *dictCreate(dictType *type, void *privDataPtr);
#ifdef _WIN32
static int dictExpand(dict *ht, size_t size);
#else
static int dictExpand(dict *ht, unsigned long size);
#endif
static int dictAdd(dict *ht, void *key, void *val);
static int dictReplace(dict *ht, void *key, void *val);
static int dictDelete(dict *ht, const void *key);
+83 -7
View File
@@ -31,7 +31,9 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <assert.h>
#include <errno.h>
#include <ctype.h>
@@ -296,7 +298,11 @@ static int processBulkItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj = NULL;
char *p, *s;
#ifdef _WIN32
long long len;
#else
long len;
#endif
unsigned long bytelen;
int success = 0;
@@ -316,10 +322,10 @@ static int processBulkItem(redisReader *r) {
success = 1;
} else {
/* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */
bytelen += (unsigned long)len+2; /* include \r\n */
if (r->pos+bytelen <= r->len) {
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,s+2,len);
obj = r->fn->createString(cur,s+2,(size_t)len);
else
obj = (void*)REDIS_REPLY_STRING;
success = 1;
@@ -343,7 +349,11 @@ static int processMultiBulkItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
#ifdef _WIN32
long long elements;
#else
long elements;
#endif
int root = 0;
/* Set error for nested multi bulks with depth > 1 */
@@ -365,13 +375,13 @@ static int processMultiBulkItem(redisReader *r) {
moveToNextTask(r);
} else {
if (r->fn && r->fn->createArray)
obj = r->fn->createArray(cur,elements);
obj = r->fn->createArray(cur,(int)elements);
else
obj = (void*)REDIS_REPLY_ARRAY;
/* Modify task stack when there are more than 0 elements. */
if (elements > 0) {
cur->elements = elements;
cur->elements = (int)elements;
cur->obj = obj;
r->ridx++;
r->rstack[r->ridx].type = -1;
@@ -596,7 +606,7 @@ static int intlen(int i) {
/* Helper function for redisvFormatCommand(). */
static void addArgument(sds a, char ***argv, int *argc, int *totlen) {
(*argc)++;
if ((*argv = realloc(*argv, sizeof(char*)*(*argc))) == NULL) redisOOM();
if ((*argv = (char **)realloc(*argv, sizeof(char*)*(*argc))) == NULL) redisOOM();
if (totlen) *totlen = *totlen+1+intlen(sdslen(a))+2+sdslen(a)+2;
(*argv)[(*argc)-1] = a;
}
@@ -697,7 +707,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
}
/* Consume and discard vararg */
#ifdef _WIN32
va_arg(ap,void *);
#else
va_arg(ap,void);
#endif
}
}
touched = 1;
@@ -717,11 +731,15 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
totlen += 1+intlen(argc)+2;
/* Build the command at protocol level */
cmd = malloc(totlen+1);
cmd = (char *)malloc(totlen+1);
if (!cmd) redisOOM();
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
#ifdef _WIN32
pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)sdslen(argv[j]));
#else
pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(argv[j]));
#endif
memcpy(cmd+pos,argv[j],sdslen(argv[j]));
pos += sdslen(argv[j]);
sdsfree(argv[j]);
@@ -780,7 +798,11 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]);
#ifdef _WIN32
pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)len);
#else
pos += sprintf(cmd+pos,"$%zu\r\n",len);
#endif
memcpy(cmd+pos,argv[j],len);
pos += len;
cmd[pos++] = '\r';
@@ -815,7 +837,11 @@ static redisContext *redisContextInit(void) {
void redisFree(redisContext *c) {
if (c->fd > 0)
#ifdef _WIN32
closesocket(c->fd);
#else
close(c->fd);
#endif
if (c->errstr != NULL)
sdsfree(c->errstr);
if (c->obuf != NULL)
@@ -870,6 +896,21 @@ redisContext *redisConnectUnixNonBlock(const char *path) {
return c;
}
/* initializers if caller handles connection */
redisContext *redisConnected() {
redisContext *c = redisContextInit();
c->fd = -1;
c->flags |= REDIS_BLOCK;
return c;
}
redisContext *redisConnectedNonBlock() {
redisContext *c = redisContextInit();
c->fd = -1;
c->flags &= ~REDIS_BLOCK;
return c;
}
/* Set read/write timeout on a blocking socket. */
int redisSetTimeout(redisContext *c, struct timeval tv) {
if (c->flags & REDIS_BLOCK)
@@ -902,7 +943,16 @@ static void __redisCreateReplyReader(redisContext *c) {
* see if there is a reply available. */
int redisBufferRead(redisContext *c) {
char buf[2048];
#ifdef _WIN32
int nread = recv((SOCKET)c->fd,buf,sizeof(buf),0);
if (nread == -1) {
errno = WSAGetLastError();
if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK))
errno = EAGAIN;
}
#else
int nread = read(c->fd,buf,sizeof(buf));
#endif
if (nread == -1) {
if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
/* Try again later */
@@ -921,6 +971,23 @@ int redisBufferRead(redisContext *c) {
return REDIS_OK;
}
/* Use this function if the caller has already read the data. It will
* feed bytes to the reply parser.
*
* After this function is called, you may use redisContextReadReply to
* see if there is a reply available. */
int redisBufferReadDone(redisContext *c, char *buf, int nread) {
if (nread == 0) {
__redisSetError(c,REDIS_ERR_EOF,
sdsnew("Server closed the connection"));
return REDIS_ERR;
} else {
__redisCreateReplyReader(c);
redisReplyReaderFeed(c->reader,buf,nread);
}
return REDIS_OK;
}
/* Write the output buffer to the socket.
*
* Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
@@ -933,7 +1000,16 @@ int redisBufferRead(redisContext *c) {
int redisBufferWrite(redisContext *c, int *done) {
int nwritten;
if (sdslen(c->obuf) > 0) {
#ifdef _WIN32
nwritten = send((SOCKET)c->fd,c->obuf,sdslen(c->obuf),0);
if (nwritten == -1) {
errno = WSAGetLastError();
if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK))
errno = EAGAIN;
}
#else
nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
#endif
if (nwritten == -1) {
if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
/* Try again later */
+20
View File
@@ -33,7 +33,20 @@
#define __HIREDIS_H
#include <stdio.h> /* for size_t */
#include <stdarg.h> /* for va_list */
#ifndef _WIN32
#include <sys/time.h> /* for struct timeval */
#endif
#ifdef _WIN32
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include <winsock2.h>
#include <windows.h>
#ifndef va_copy
#define va_copy(d,s) d = (s)
#endif
#endif
#define HIREDIS_MAJOR 0
#define HIREDIS_MINOR 9
@@ -117,7 +130,11 @@ struct redisContext; /* need forward declaration of redisContext */
/* Context for a connection to Redis */
typedef struct redisContext {
#ifdef _WIN32
SOCKET fd;
#else
int fd;
#endif
int flags;
char *obuf; /* Write buffer */
int err; /* Error flags, 0 when there is no error */
@@ -149,11 +166,14 @@ redisContext *redisConnectNonBlock(const char *ip, int port);
redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
redisContext *redisConnected();
redisContext *redisConnectedNonBlock();
int redisSetTimeout(redisContext *c, struct timeval tv);
int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn);
void redisFree(redisContext *c);
int redisBufferRead(redisContext *c);
int redisBufferWrite(redisContext *c, int *done);
int redisBufferReadDone(redisContext *c, char *buf, int nread);
/* In a blocking context, this function first checks if there are unconsumed
* replies to return and returns one if so. Otherwise, it flushes the output
+179 -1
View File
@@ -32,6 +32,14 @@
#include "fmacros.h"
#include <sys/types.h>
#ifdef _WIN32
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include "winsock2.h"
#include "windows.h"
#define socklen_t int
#else
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
@@ -39,9 +47,11 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
@@ -52,6 +62,31 @@
/* Forward declaration */
void __redisSetError(redisContext *c, int type, sds err);
#ifdef _WIN32
static int redisCreateSocket(redisContext *c, int type) {
SOCKET s;
int on=1;
s = socket(type, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
__redisSetError(c,REDIS_ERR_IO,sdscatprintf(sdsempty(), "socket error: %d\n", WSAGetLastError()));
return REDIS_ERR;
}
if (type == AF_INET) {
LINGER l;
l.l_onoff = 1;
l.l_linger = 2;
setsockopt(s, SOL_SOCKET, SO_LINGER, (const char *) &l, sizeof(l));
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) == -1) {
__redisSetError(c,REDIS_ERR_IO,NULL);
closesocket(s);
return REDIS_ERR;
}
}
return (int)s;
}
#else
static int redisCreateSocket(redisContext *c, int type) {
int s, on = 1;
if ((s = socket(type, SOCK_STREAM, 0)) == -1) {
@@ -67,7 +102,31 @@ static int redisCreateSocket(redisContext *c, int type) {
}
return s;
}
#endif
#ifdef _WIN32
static int redisSetBlocking(redisContext *c, int fd, int blocking) {
/* If iMode = 0, blocking is enabled; */
/* If iMode != 0, non-blocking mode is enabled. */
u_long flags;
if (blocking)
flags = (u_long)0;
else
flags = (u_long)1;
if (ioctlsocket((SOCKET)fd, FIONBIO, &flags) == SOCKET_ERROR) {
errno = WSAGetLastError();
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "ioctlsocket(FIONBIO): %d\n", errno));
closesocket(fd);
return REDIS_ERR;
};
return REDIS_OK;
}
#else
static int redisSetBlocking(redisContext *c, int fd, int blocking) {
int flags;
@@ -94,7 +153,20 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
}
return REDIS_OK;
}
#endif
#ifdef _WIN32
static int redisSetTcpNoDelay(redisContext *c, int fd) {
int yes = 1;
if (setsockopt((SOCKET)fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&yes, sizeof(yes)) == -1) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "setsockopt(TCP_NODELAY): %d", (int)GetLastError()));
closesocket(fd);
return REDIS_ERR;
}
return REDIS_OK;
}
#else
static int redisSetTcpNoDelay(redisContext *c, int fd) {
int yes = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
@@ -105,6 +177,7 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
}
return REDIS_OK;
}
#endif
static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) {
struct timeval to;
@@ -121,35 +194,62 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
if (errno == EINPROGRESS) {
FD_ZERO(&wfd);
#ifdef _WIN32
FD_SET((SOCKET)fd, &wfd);
#else
FD_SET(fd, &wfd);
#endif
if (select(FD_SETSIZE, NULL, &wfd, NULL, toptr) == -1) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "select(2): %s", strerror(errno)));
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
return REDIS_ERR;
}
if (!FD_ISSET(fd, &wfd)) {
#ifdef _WIN32
errno = WSAGetLastError();
__redisSetError(c,REDIS_ERR_IO,NULL);
closesocket(fd);
#else
errno = ETIMEDOUT;
__redisSetError(c,REDIS_ERR_IO,NULL);
close(fd);
#endif
return REDIS_ERR;
}
err = 0;
errlen = sizeof(err);
#ifdef _WIN32
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen) == SOCKET_ERROR) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "getsockopt(SO_ERROR): %d", WSAGetLastError()));
closesocket(fd);
return REDIS_ERR;
}
#else
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "getsockopt(SO_ERROR): %s", strerror(errno)));
close(fd);
return REDIS_ERR;
}
#endif
if (err) {
errno = err;
__redisSetError(c,REDIS_ERR_IO,NULL);
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
return REDIS_ERR;
}
@@ -157,10 +257,29 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
}
__redisSetError(c,REDIS_ERR_IO,NULL);
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
return REDIS_ERR;
}
#ifdef _WIN32
int redisContextSetTimeout(redisContext *c, struct timeval tv) {
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,(const char *)&tv,sizeof(tv)) == SOCKET_ERROR ) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "setsockopt(SO_RCVTIMEO): %d", WSAGetLastError()));
return REDIS_ERR;
}
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,(const char *)&tv,sizeof(tv)) == SOCKET_ERROR ) {
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(), "setsockopt(SO_SNDTIMEO): %d", WSAGetLastError()));
return REDIS_ERR;
}
return REDIS_OK;
}
#else
int redisContextSetTimeout(redisContext *c, struct timeval tv) {
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
__redisSetError(c,REDIS_ERR_IO,
@@ -174,7 +293,57 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
}
return REDIS_OK;
}
#endif
#ifdef _WIN32
int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout) {
int s;
int blocking = (c->flags & REDIS_BLOCK);
struct sockaddr_in sa;
unsigned long inAddress;
if ((s = redisCreateSocket(c,AF_INET)) < 0)
return REDIS_ERR;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (redisSetTcpNoDelay(c,s) != REDIS_OK)
return REDIS_ERR;
inAddress = inet_addr(addr);
if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) {
struct hostent *he;
he = gethostbyname(addr);
if (he == NULL) {
__redisSetError(c,REDIS_ERR_OTHER,
sdscatprintf(sdsempty(),"can't resolve: %s\n", addr));
closesocket(s);
return REDIS_ERR;;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
else {
sa.sin_addr.s_addr = inAddress;
}
if (connect((SOCKET)s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
errno = WSAGetLastError();
if ((errno == WSAEINVAL) || (errno == WSAEWOULDBLOCK))
errno = EINPROGRESS;
if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
if (redisContextWaitReady(c,s,timeout) != REDIS_OK)
return REDIS_ERR;
}
}
c->fd = s;
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
}
#else
int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout) {
int s;
int blocking = (c->flags & REDIS_BLOCK);
@@ -220,8 +389,16 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
}
#endif
int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout) {
#ifdef _WIN32
(void) timeout;
__redisSetError(c,REDIS_ERR_IO,
sdscatprintf(sdsempty(),"Unix sockets are not suported on Windows platform. (%s)\n", path));
return REDIS_ERR;
#else
int s;
int blocking = (c->flags & REDIS_BLOCK);
struct sockaddr_un sa;
@@ -249,4 +426,5 @@ int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *t
c->fd = s;
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
#endif
}
+7 -2
View File
@@ -34,6 +34,11 @@
#include <sys/types.h>
#include <stdarg.h>
#ifdef _WIN32
#define inline __inline
#define va_copy(d,s) d = (s)
#endif
typedef char *sds;
struct sdshdr {
@@ -43,12 +48,12 @@ struct sdshdr {
};
static inline size_t sdslen(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
struct sdshdr *sh = (struct sdshdr *)(s-(sizeof(struct sdshdr)));
return sh->len;
}
static inline size_t sdsavail(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
struct sdshdr *sh = (struct sdshdr *)(s-(sizeof(struct sdshdr)));
return sh->free;
}
+244 -2
View File
@@ -82,24 +82,31 @@
*
*/
#ifndef _WIN32
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "linenoise.h"
#ifdef _WIN32
#include "../../src/win32fixes.h"
#define REDIS_NOTUSED(V) ((void) V)
#endif
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096
static char *unsupported_term[] = {"dumb","cons25",NULL};
static linenoiseCompletionCallback *completionCallback = NULL;
#ifndef _WIN32
static struct termios orig_termios; /* in order to restore at exit */
#endif
static int rawmode = 0; /* for atexit() function to check if restore is needed*/
static int atexit_registered = 0; /* register atexit just 1 time */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
@@ -109,13 +116,141 @@ char **history = NULL;
static void linenoiseAtExit(void);
int linenoiseHistoryAdd(const char *line);
#ifdef _WIN32
#ifndef STDIN_FILENO
#define STDIN_FILENO (_fileno(stdin))
#endif
HANDLE hOut;
HANDLE hIn;
DWORD consolemode;
static int win32read(char *c) {
DWORD foo;
INPUT_RECORD b;
KEY_EVENT_RECORD e;
while (1) {
if (!ReadConsoleInput(hIn, &b, 1, &foo)) return 0;
if (!foo) return 0;
if (b.EventType == KEY_EVENT && b.Event.KeyEvent.bKeyDown) {
e = b.Event.KeyEvent;
*c = b.Event.KeyEvent.uChar.AsciiChar;
//if (e.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
/* Alt+key ignored */
//} else
if (e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
/* Ctrl+Key */
switch (*c) {
case 'D':
*c = 4;
return 1;
case 'C':
*c = 3;
return 1;
case 'H':
*c = 8;
return 1;
case 'T':
*c = 20;
return 1;
case 'B': /* ctrl-b, left_arrow */
*c = 2;
return 1;
case 'F': /* ctrl-f right_arrow*/
*c = 6;
return 1;
case 'P': /* ctrl-p up_arrow*/
*c = 16;
return 1;
case 'N': /* ctrl-n down_arrow*/
*c = 14;
return 1;
case 'U': /* Ctrl+u, delete the whole line. */
*c = 21;
return 1;
case 'K': /* Ctrl+k, delete from current to end of line. */
*c = 11;
return 1;
case 'A': /* Ctrl+a, go to the start of the line */
*c = 1;
return 1;
case 'E': /* ctrl+e, go to the end of the line */
*c = 5;
return 1;
}
/* Other Ctrl+KEYs ignored */
} else {
switch (e.wVirtualKeyCode) {
case VK_ESCAPE: /* ignore - send ctrl-c, will return -1 */
*c = 3;
return 1;
case VK_RETURN: /* enter */
*c = 13;
return 1;
case VK_LEFT: /* left */
*c = 2;
return 1;
case VK_RIGHT: /* right */
*c = 6;
return 1;
case VK_UP: /* up */
*c = 16;
return 1;
case VK_DOWN: /* down */
*c = 14;
return 1;
case VK_HOME:
*c = 1;
return 1;
case VK_END:
*c = 5;
return 1;
case VK_BACK:
*c = 8;
return 1;
case VK_DELETE:
*c = 127;
return 1;
default:
if (*c) return 1;
}
}
}
}
return -1; /* Makes compiler happy */
}
#ifdef __STRICT_ANSI__
char *strdup(const char *s) {
size_t l = strlen(s)+1;
char *p = malloc(l);
memcpy(p,s,l);
return p;
}
#endif /* __STRICT_ANSI__ */
#endif /* _WIN32 */
static int isUnsupportedTerm(void) {
#ifndef _WIN32
char *term = getenv("TERM");
int j;
if (term == NULL) return 0;
for (j = 0; unsupported_term[j]; j++)
if (!strcasecmp(term,unsupported_term[j])) return 1;
#endif
return 0;
}
@@ -130,6 +265,7 @@ static void freeHistory(void) {
}
static int enableRawMode(int fd) {
#ifndef _WIN32
struct termios raw;
if (!isatty(STDIN_FILENO)) goto fatal;
@@ -157,6 +293,37 @@ static int enableRawMode(int fd) {
/* put terminal in raw mode after flushing */
if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
rawmode = 1;
#else
REDIS_NOTUSED(fd);
if (!atexit_registered) {
/* Init windows console handles only once */
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut==INVALID_HANDLE_VALUE) goto fatal;
if (!GetConsoleMode(hOut, &consolemode)) {
CloseHandle(hOut);
errno = ENOTTY;
return -1;
};
hIn = GetStdHandle(STD_INPUT_HANDLE);
if (hIn == INVALID_HANDLE_VALUE) {
CloseHandle(hOut);
errno = ENOTTY;
return -1;
}
GetConsoleMode(hIn, &consolemode);
SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT);
/* Cleanup them at exit */
atexit(linenoiseAtExit);
atexit_registered = 1;
}
rawmode = 1;
#endif
return 0;
fatal:
@@ -165,26 +332,49 @@ fatal:
}
static void disableRawMode(int fd) {
#ifdef _WIN32
REDIS_NOTUSED(fd);
rawmode = 0;
#else
/* Don't even check the return value as it's too late. */
if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
rawmode = 0;
#endif
}
/* At exit we'll try to fix the terminal to the initial conditions. */
static void linenoiseAtExit(void) {
#ifdef _WIN32
SetConsoleMode(hIn, consolemode);
CloseHandle(hOut);
CloseHandle(hIn);
#else
disableRawMode(STDIN_FILENO);
#endif
freeHistory();
}
static int getColumns(void) {
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO b;
if (!GetConsoleScreenBufferInfo(hOut, &b)) return 80;
return b.srWindow.Right - b.srWindow.Left;
#else
struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80;
return ws.ws_col;
#endif
}
static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) {
char seq[64];
#ifdef _WIN32
DWORD pl, bl, w;
CONSOLE_SCREEN_BUFFER_INFO b;
COORD coord;
#endif
size_t plen = strlen(prompt);
while((plen+pos) >= cols) {
@@ -196,6 +386,7 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
len--;
}
#ifndef _WIN32
/* Cursor to left edge */
snprintf(seq,64,"\x1b[0G");
if (write(fd,seq,strlen(seq)) == -1) return;
@@ -208,6 +399,27 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
/* Move cursor to original position. */
snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
if (write(fd,seq,strlen(seq)) == -1) return;
#else
REDIS_NOTUSED(seq);
REDIS_NOTUSED(fd);
/* Get buffer console info */
if (!GetConsoleScreenBufferInfo(hOut, &b)) return;
/* Erase Line */
coord.X = 0;
coord.Y = b.dwCursorPosition.Y;
FillConsoleOutputCharacterA(hOut, ' ', b.dwSize.X, coord, &w);
/* Cursor to the left edge */
SetConsoleCursorPosition(hOut, coord);
/* Write the prompt and the current buffer content */
WriteConsole(hOut, prompt, plen, &pl, NULL);
WriteConsole(hOut, buf, len, &bl, NULL);
/* Move cursor to original position. */
coord.X = (int)(pos+plen);
coord.Y = b.dwCursorPosition.Y;
SetConsoleCursorPosition(hOut, coord);
#endif
}
static void beep() {
@@ -290,6 +502,9 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
size_t len = 0;
size_t cols = getColumns();
int history_index = 0;
#ifdef _WIN32
DWORD foo;
#endif
buf[0] = '\0';
buflen--; /* Make sure there is always space for the nulterm */
@@ -298,13 +513,21 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
* initially is just an empty string. */
linenoiseHistoryAdd("");
#ifdef _WIN32
if (!WriteConsole(hOut, prompt, plen, &foo, NULL)) return -1;
#else
if (write(fd,prompt,plen) == -1) return -1;
#endif
while(1) {
char c;
int nread;
char seq[2], seq2[2];
#ifdef _WIN32
nread = win32read(&c);
#else
nread = read(fd,&c,1);
#endif
if (nread <= 0) return len;
/* Only autocomplete when the callback is set. It returns < 0 when
@@ -327,6 +550,17 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
errno = EAGAIN;
return -1;
case 127: /* backspace */
#ifdef _WIN32
/* delete in _WIN32*/
/* win32read() will send 127 for DEL and 8 for BS and Ctrl-H */
if (pos < len && len > 0) {
memmove(buf+pos,buf+pos+1,len-pos);
len--;
buf[len] = '\0';
refreshLine(fd,prompt,buf,len,pos,cols);
}
break;
#endif
case 8: /* ctrl-h */
if (pos > 0 && len > 0) {
memmove(buf+pos-1,buf+pos,len-pos);
@@ -430,7 +664,11 @@ up_down_arrow:
if (plen+len < cols) {
/* Avoid a full update of the line in the
* trivial case. */
#ifdef _WIN32
if (!WriteConsole(hOut, &c, 1, &foo, NULL)) return -1;
#else
if (write(fd,&c,1) == -1) return -1;
#endif
} else {
refreshLine(fd,prompt,buf,len,pos,cols);
}
@@ -575,7 +813,11 @@ int linenoiseHistorySetMaxLen(int len) {
/* Save the history in the specified file. On success 0 is returned
* otherwise -1 is returned. */
int linenoiseHistorySave(char *filename) {
#ifdef _WIN32
FILE *fp = fopen(filename,"wb");
#else
FILE *fp = fopen(filename,"w");
#endif
int j;
if (fp == NULL) return -1;
+101
View File
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B00D4BB5-44DE-405E-839C-D16F547006CF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>RedisBenchmark</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<TargetName>redis-benchmark</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>redis-benchmark</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WIN32IOCP;WIN32;PTW32_STATIC_LIB;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;$(SolutionDir)..\deps\libuv\include;$(SolutionDir)..\deps\hiredis;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;uuid.lib;ws2_32.lib;hiredis.lib;pthread.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_WIN32IOCP;WIN32;PTW32_STATIC_LIB;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;$(SolutionDir)..\deps\libuv\include;$(SolutionDir)..\deps\hiredis;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;uuid.lib;ws2_32.lib;hiredis.lib;pthread.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\adlist.c" />
<ClCompile Include="..\..\src\ae.c" />
<ClCompile Include="..\..\src\anet.c" />
<ClCompile Include="..\..\src\redis-benchmark.c" />
<ClCompile Include="..\..\src\sds.c" />
<ClCompile Include="..\..\src\win32fixes.c" />
<ClCompile Include="..\..\src\win32_wsiocp.c" />
<ClCompile Include="..\..\src\zmalloc.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+82
View File
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}</ProjectGuid>
<RootNamespace>RedisCheckAof</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>redis-check-aof</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>redis-check-aof</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PTW32_STATIC_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_CONSOLE;PTW32_STATIC_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)redis-check-aof$(TargetExt)</OutputFile>
<AdditionalDependencies>ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\redis-check-aof.c" />
<ClCompile Include="..\..\src\win32fixes.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{52193A97-D010-41D6-BF2B-33E8E764E308}</ProjectGuid>
<RootNamespace>RedisCheckDump</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>redis-check-dump</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>redis-check-dump</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)redis-check-dump$(TargetExt)</OutputFile>
<AdditionalDependencies>ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)redis-check-dump$(TargetExt)</OutputFile>
<AdditionalDependencies>ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\lzf_c.c" />
<ClCompile Include="..\..\src\lzf_d.c" />
<ClCompile Include="..\..\src\redis-check-dump.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+95
View File
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{392BBB91-3934-4A56-AF42-65C5728311E8}</ProjectGuid>
<RootNamespace>RedisCli</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>redis-cli</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>redis-cli</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;$(SolutionDir)..\deps\hiredis;$(SolutionDir)..\deps\linenoise</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PTW32_STATIC_LIB;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)redis-cli$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>hiredis.lib;ws2_32.lib;pthread.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;$(SolutionDir)..\deps\hiredis;$(SolutionDir)..\deps\linenoise</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PTW32_STATIC_LIB;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)redis-cli$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>hiredis.lib;ws2_32.lib;pthread.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\deps\linenoise\linenoise.c" />
<ClCompile Include="..\..\src\adlist.c" />
<ClCompile Include="..\..\src\anet.c" />
<ClCompile Include="..\..\src\redis-cli.c" />
<ClCompile Include="..\..\src\release.c" />
<ClCompile Include="..\..\src\sds.c" />
<ClCompile Include="..\..\src\win32fixes.c" />
<ClCompile Include="..\..\src\win32_wsiocp.c" />
<ClCompile Include="..\..\src\zmalloc.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+56
View File
@@ -0,0 +1,56 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisServer", "RedisServer.vcxproj", "{51866E6A-BD89-D909-159B-3B68B27D4DF4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hiredis", "hiredis\hiredis.vcxproj", "{13E85053-54B3-487B-8DDB-3430B1C1B3BF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisBenchmark", "RedisBenchmark\RedisBenchmark.vcxproj", "{B00D4BB5-44DE-405E-839C-D16F547006CF}"
ProjectSection(ProjectDependencies) = postProject
{13E85053-54B3-487B-8DDB-3430B1C1B3BF} = {13E85053-54B3-487B-8DDB-3430B1C1B3BF}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisCheckAof", "RedisCheckAof\RedisCheckAof.vcxproj", "{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisCheckDump", "RedisCheckDump\RedisCheckDump.vcxproj", "{52193A97-D010-41D6-BF2B-33E8E764E308}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RedisCli", "RedisCli\RedisCli.vcxproj", "{392BBB91-3934-4A56-AF42-65C5728311E8}"
ProjectSection(ProjectDependencies) = postProject
{13E85053-54B3-487B-8DDB-3430B1C1B3BF} = {13E85053-54B3-487B-8DDB-3430B1C1B3BF}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{51866E6A-BD89-D909-159B-3B68B27D4DF4}.Debug|Win32.ActiveCfg = Debug|Win32
{51866E6A-BD89-D909-159B-3B68B27D4DF4}.Debug|Win32.Build.0 = Debug|Win32
{51866E6A-BD89-D909-159B-3B68B27D4DF4}.Release|Win32.ActiveCfg = Release|Win32
{51866E6A-BD89-D909-159B-3B68B27D4DF4}.Release|Win32.Build.0 = Release|Win32
{13E85053-54B3-487B-8DDB-3430B1C1B3BF}.Debug|Win32.ActiveCfg = Debug|Win32
{13E85053-54B3-487B-8DDB-3430B1C1B3BF}.Debug|Win32.Build.0 = Debug|Win32
{13E85053-54B3-487B-8DDB-3430B1C1B3BF}.Release|Win32.ActiveCfg = Release|Win32
{13E85053-54B3-487B-8DDB-3430B1C1B3BF}.Release|Win32.Build.0 = Release|Win32
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Debug|Win32.ActiveCfg = Debug|Win32
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Debug|Win32.Build.0 = Debug|Win32
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Release|Win32.ActiveCfg = Release|Win32
{B00D4BB5-44DE-405E-839C-D16F547006CF}.Release|Win32.Build.0 = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Win32.ActiveCfg = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Debug|Win32.Build.0 = Debug|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Win32.ActiveCfg = Release|Win32
{A65C2CD6-72A3-441A-AEA3-D754BEA9A86A}.Release|Win32.Build.0 = Release|Win32
{52193A97-D010-41D6-BF2B-33E8E764E308}.Debug|Win32.ActiveCfg = Debug|Win32
{52193A97-D010-41D6-BF2B-33E8E764E308}.Debug|Win32.Build.0 = Debug|Win32
{52193A97-D010-41D6-BF2B-33E8E764E308}.Release|Win32.ActiveCfg = Release|Win32
{52193A97-D010-41D6-BF2B-33E8E764E308}.Release|Win32.Build.0 = Release|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Debug|Win32.ActiveCfg = Debug|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Debug|Win32.Build.0 = Debug|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Release|Win32.ActiveCfg = Release|Win32
{392BBB91-3934-4A56-AF42-65C5728311E8}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+152
View File
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<TargetName>redis-server</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>redis-server</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>_WIN32IOCP;WIN32;_DEBUG;_CONSOLE;PTW32_STATIC_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<DisableSpecificWarnings>4996;4146</DisableSpecificWarnings>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>pthread.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;advapi32.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>_WIN32IOCP;WIN32;NDEBUG;_CONSOLE;PTW32_STATIC_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\deps\pthreads-win32\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4996;4146</DisableSpecificWarnings>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);$(SolutionDir)../deps/pthreads-win32/lib/$(Configuration);$(OutDir)lib</AdditionalLibraryDirectories>
<AdditionalDependencies>pthread.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;advapi32.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\src\adlist.c" />
<ClCompile Include="..\src\ae.c" />
<ClCompile Include="..\src\anet.c" />
<ClCompile Include="..\src\aof.c" />
<ClCompile Include="..\src\bio.c" />
<ClCompile Include="..\src\config.c" />
<ClCompile Include="..\src\db.c" />
<ClCompile Include="..\src\debug.c" />
<ClCompile Include="..\src\dict.c" />
<ClCompile Include="..\src\endian.c" />
<ClCompile Include="..\src\intset.c" />
<ClCompile Include="..\src\lzf_c.c" />
<ClCompile Include="..\src\lzf_d.c" />
<ClCompile Include="..\src\multi.c" />
<ClCompile Include="..\src\networking.c" />
<ClCompile Include="..\src\object.c" />
<ClCompile Include="..\src\pqsort.c" />
<ClCompile Include="..\src\pubsub.c" />
<ClCompile Include="..\src\rdb.c" />
<ClCompile Include="..\src\redis.c" />
<ClCompile Include="..\src\release.c" />
<ClCompile Include="..\src\replication.c" />
<ClCompile Include="..\src\sds.c" />
<ClCompile Include="..\src\sha1.c" />
<ClCompile Include="..\src\slowlog.c" />
<ClCompile Include="..\src\sort.c" />
<ClCompile Include="..\src\syncio.c" />
<ClCompile Include="..\src\t_hash.c" />
<ClCompile Include="..\src\t_list.c" />
<ClCompile Include="..\src\t_set.c" />
<ClCompile Include="..\src\t_string.c" />
<ClCompile Include="..\src\t_zset.c" />
<ClCompile Include="..\src\util.c" />
<ClCompile Include="..\src\win32fixes.c" />
<ClCompile Include="..\src\win32_wsiocp.c" />
<ClCompile Include="..\src\ziplist.c" />
<ClCompile Include="..\src\zipmap.c" />
<ClCompile Include="..\src\zmalloc.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\adlist.h" />
<ClInclude Include="..\src\ae.h" />
<ClInclude Include="..\src\anet.h" />
<ClInclude Include="..\src\bio.h" />
<ClInclude Include="..\src\config.h" />
<ClInclude Include="..\src\dict.h" />
<ClInclude Include="..\src\endian.h" />
<ClInclude Include="..\src\fmacros.h" />
<ClInclude Include="..\src\help.h" />
<ClInclude Include="..\src\intset.h" />
<ClInclude Include="..\src\lzf.h" />
<ClInclude Include="..\src\lzfP.h" />
<ClInclude Include="..\src\pqsort.h" />
<ClInclude Include="..\src\redis.h" />
<ClInclude Include="..\src\release.h" />
<ClInclude Include="..\src\sds.h" />
<ClInclude Include="..\src\sha1.h" />
<ClInclude Include="..\src\slowlog.h" />
<ClInclude Include="..\src\solarisfixes.h" />
<ClInclude Include="..\src\testhelp.h" />
<ClInclude Include="..\src\util.h" />
<ClInclude Include="..\src\version.h" />
<ClInclude Include="..\src\win32fixes.h" />
<ClInclude Include="..\src\win32_wsiocp.h" />
<ClInclude Include="..\src\ziplist.h" />
<ClInclude Include="..\src\zipmap.h" />
<ClInclude Include="..\src\zmalloc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+100
View File
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{13E85053-54B3-487B-8DDB-3430B1C1B3BF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>hiredis</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>hiredis</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>hiredis</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\deps\hiredis\async.c" />
<ClCompile Include="..\..\deps\hiredis\dict.c" />
<ClCompile Include="..\..\deps\hiredis\hiredis.c" />
<ClCompile Include="..\..\deps\hiredis\net.c" />
<ClCompile Include="..\..\deps\hiredis\sds.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\deps\hiredis\async.h" />
<ClInclude Include="..\..\deps\hiredis\dict.h" />
<ClInclude Include="..\..\deps\hiredis\fmacros.h" />
<ClInclude Include="..\..\deps\hiredis\hiredis.h" />
<ClInclude Include="..\..\deps\hiredis\net.h" />
<ClInclude Include="..\..\deps\hiredis\sds.h" />
<ClInclude Include="..\..\deps\hiredis\util.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+20 -7
View File
@@ -31,9 +31,11 @@
*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
#include <stdlib.h>
#include "ae.h"
@@ -48,7 +50,11 @@
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#ifdef _WIN32
#include "ae_wsiocp.c"
#else
#include "ae_select.c"
#endif
#endif
#endif
@@ -86,8 +92,9 @@ void aeStop(aeEventLoop *eventLoop) {
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData)
{
aeFileEvent *fe;
if (fd >= AE_SETSIZE) return AE_ERR;
aeFileEvent *fe = &eventLoop->events[fd];
fe = &eventLoop->events[fd];
if (aeApiAddEvent(eventLoop, fd, mask) == -1)
return AE_ERR;
@@ -102,8 +109,9 @@ int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
{
aeFileEvent *fe;
if (fd >= AE_SETSIZE) return;
aeFileEvent *fe = &eventLoop->events[fd];
fe = &eventLoop->events[fd];
if (fe->mask == AE_NONE) return;
fe->mask = fe->mask & (~mask);
@@ -119,8 +127,9 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
}
int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
aeFileEvent *fe;
if (fd >= AE_SETSIZE) return 0;
aeFileEvent *fe = &eventLoop->events[fd];
fe = &eventLoop->events[fd];
return fe->mask;
}
@@ -138,7 +147,7 @@ static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms)
long cur_sec, cur_ms, when_sec, when_ms;
aeGetTime(&cur_sec, &cur_ms);
when_sec = cur_sec + milliseconds/1000;
when_sec = (long)(cur_sec + milliseconds/1000);
when_ms = cur_ms + milliseconds%1000;
if (when_ms >= 1000) {
when_sec ++;
@@ -235,7 +244,11 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
if (now_sec > te->when_sec ||
(now_sec == te->when_sec && now_ms >= te->when_ms))
{
#ifdef _WIN32
long long retval;
#else
int retval;
#endif
id = te->id;
retval = te->timeProc(eventLoop, id, te->clientData);
@@ -362,7 +375,7 @@ int aeWait(int fd, int mask, long long milliseconds) {
fd_set rfds, wfds, efds;
int retmask = 0, retval;
tv.tv_sec = milliseconds/1000;
tv.tv_sec = (long)(milliseconds/1000);
tv.tv_usec = (milliseconds%1000)*1000;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
+224
View File
@@ -0,0 +1,224 @@
/* Copyright (c) 2012, Microsoft Corporation
* 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.
*/
/* IOCP-based ae.c module */
#include <string.h>
#include "ae.h"
#include "win32fixes.h"
#include "zmalloc.h"
#include "win32_wsiocp.h"
#include <mswsock.h>
#include <Guiddef.h>
#define MAX_COMPLETE_PER_POLL 100
/* structure that keeps state of sockets and Completion port handle */
typedef struct aeApiState {
HANDLE iocp;
int setsize;
OVERLAPPED_ENTRY entries[MAX_COMPLETE_PER_POLL];
aeSockState *sockstate;
} aeApiState;
/* utility to validate that socket / fd is being monitored */
aeSockState *aeGetSockState(void *apistate, int fd) {
if (apistate == NULL) return NULL;
if (fd >= ((aeApiState *)apistate)->setsize) {
return NULL;
}
return &((aeApiState *)apistate)->sockstate[fd];
}
/* Called by ae to initialize state */
static int aeApiCreate(aeEventLoop *eventLoop) {
aeApiState *state = (aeApiState *)zmalloc(sizeof(aeApiState));
if (!state) return -1;
memset(state, 0, sizeof(aeApiState));
state->sockstate = (aeSockState *)zmalloc(sizeof(aeSockState) * AE_SETSIZE);
if (state->sockstate == NULL) {
zfree(state);
return -1;
}
/* create a single IOCP to be shared by all sockets */
state->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
NULL,
0,
1);
state->setsize = AE_SETSIZE;
eventLoop->apidata = state;
/* initialize the IOCP socket code with state reference */
aeWinInit(state, state->iocp, aeGetSockState);
return 0;
}
/* termination */
static void aeApiFree(aeEventLoop *eventLoop) {
aeApiState *state = (aeApiState *)eventLoop->apidata;
CloseHandle(state->iocp);
zfree(state->sockstate);
zfree(state);
aeWinCleanup();
}
/* monitor state changes for a socket */
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = (aeApiState *)eventLoop->apidata;
aeSockState *sockstate = aeGetSockState(state, fd);
if (sockstate == NULL) {
errno = WSAEINVAL;
return -1;
}
if (mask & AE_READABLE) {
sockstate->masks |= AE_READABLE;
if (sockstate->masks & LISTEN_SOCK) {
/* actually a listen. Do not treat as read */
} else {
if ((sockstate->masks & READ_QUEUED) == 0) {
// queue up a 0 byte read
aeWinReceiveDone(fd);
}
}
}
if (mask & AE_WRITABLE) {
sockstate->masks |= AE_WRITABLE;
// if no write active, then need to queue write ready
if (sockstate->wreqs == 0) {
asendreq *areq = (asendreq *)zmalloc(sizeof(asendreq));
memset(areq, 0, sizeof(asendreq));
if (PostQueuedCompletionStatus(state->iocp,
0,
fd,
&areq->ov) == 0) {
errno = GetLastError();
zfree(areq);
return -1;
}
sockstate->wreqs++;
}
}
return 0;
}
/* stop monitoring state changes for a socket */
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = (aeApiState *)eventLoop->apidata;
aeSockState *sockstate = aeGetSockState(state, fd);
if (sockstate == NULL) {
errno = WSAEINVAL;
return;
}
if (mask & AE_READABLE) sockstate->masks &= ~AE_READABLE;
if (mask & AE_WRITABLE) sockstate->masks &= ~AE_WRITABLE;
}
/* return array of sockets that are ready for read or write
depending on the mask for each socket */
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = (aeApiState *)eventLoop->apidata;
aeSockState *sockstate;
ULONG j;
int numevents = 0;
ULONG numComplete = 0;
int rc;
int mswait = (tvp->tv_sec * 1000) + (tvp->tv_usec / 1000);
/* first get an array of completion notifications */
rc = GetQueuedCompletionStatusEx(state->iocp,
state->entries,
MAX_COMPLETE_PER_POLL,
&numComplete,
mswait,
FALSE);
if (rc && numComplete > 0) {
LPOVERLAPPED_ENTRY entry = state->entries;
for (j = 0; j < numComplete && numevents < AE_SETSIZE; j++, entry++) {
/* the competion key is the socket */
SOCKET sock = (SOCKET)entry->lpCompletionKey;
sockstate = aeGetSockState(state, sock);
if (sockstate == NULL) continue;
if (sockstate->masks & LISTEN_SOCK) {
/* need to set event for listening */
aacceptreq *areq = (aacceptreq *)entry->lpOverlapped;
areq->next = sockstate->reqs;
sockstate->reqs = areq;
sockstate->masks &= ~ACCEPT_PENDING;
if (sockstate->masks & AE_READABLE) {
eventLoop->fired[numevents].fd = sock;
eventLoop->fired[numevents].mask = AE_READABLE;
numevents++;
}
} else {
/* check if event is read complete (may be 0 length read) */
if (entry->lpOverlapped == &sockstate->ov_read &&
entry->lpOverlapped->Internal != STATUS_PENDING) {
sockstate->masks &= ~READ_QUEUED;
if (sockstate->masks & AE_READABLE) {
eventLoop->fired[numevents].fd = sock;
eventLoop->fired[numevents].mask = AE_READABLE;
numevents++;
}
} else if (sockstate->wreqs > 0) {
/* should be write complete. Get results */
asendreq *areq = (asendreq *)entry->lpOverlapped;
/* call write complete callback so buffers can be freed */
if (areq->proc != NULL) {
DWORD written = 0;
DWORD flags;
WSAGetOverlappedResult(sock, &areq->ov, &written, FALSE, &flags);
areq->proc(areq->eventLoop, sock, &areq->req, (int)written);
}
sockstate->wreqs--;
zfree(areq);
/* if no active write requests, set ready to write */
if (sockstate->wreqs == 0 && sockstate->masks & AE_WRITABLE) {
eventLoop->fired[numevents].fd = sock;
eventLoop->fired[numevents].mask = AE_WRITABLE;
numevents++;
} else {
}
}
}
}
}
return numevents;
}
/* name of this event handler */
static char *aeApiName(void) {
return "winsock_IOCP";
}
+231 -2
View File
@@ -31,6 +31,7 @@
#include "fmacros.h"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@@ -38,12 +39,17 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef _WIN32
#include "win32fixes.h"
#define ANET_NOTUSED(V) ((void) V)
#endif
#include "anet.h"
@@ -57,13 +63,29 @@ static void anetSetError(char *err, const char *fmt, ...)
va_end(ap);
}
#ifdef _WIN32
int anetNonBlock(char *err, int fd)
{
int flags;
/* Set the socket nonblocking on Windows
* If iMode = 0, blocking is enabled;
* If iMode != 0, non-blocking mode is enabled.*/
u_long iMode = 1;
if (ioctlsocket((SOCKET)fd, FIONBIO, &iMode) == SOCKET_ERROR) {
errno = WSAGetLastError();
anetSetError(err, "ioctlsocket(FIONBIO): %d\n", errno);
return ANET_ERR;
};
return ANET_OK;
}
#else
int anetNonBlock(char *err, int fd)
{
/* Set the socket nonblocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
int flags;
if ((flags = fcntl(fd, F_GETFL)) == -1) {
anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
return ANET_ERR;
@@ -74,6 +96,7 @@ int anetNonBlock(char *err, int fd)
}
return ANET_OK;
}
#endif
int anetTcpNoDelay(char *err, int fd)
{
@@ -109,9 +132,16 @@ int anetTcpKeepAlive(char *err, int fd)
int anetResolve(char *err, char *host, char *ipbuf)
{
struct sockaddr_in sa;
#ifdef _WIN32
unsigned long inAddress;
sa.sin_family = AF_INET;
inAddress = inet_addr(host);
if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) {
#else
sa.sin_family = AF_INET;
if (inet_aton(host, &sa.sin_addr) == 0) {
#endif
struct hostent *he;
he = gethostbyname(host);
@@ -121,12 +151,91 @@ int anetResolve(char *err, char *host, char *ipbuf)
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
#ifdef _WIN32
else {
sa.sin_addr.s_addr = inAddress;
};
#endif
strcpy(ipbuf,inet_ntoa(sa.sin_addr));
return ANET_OK;
}
#ifdef _WIN32
static int anetCreateSocket(char *err, int domain) {
SOCKET s;
int on = 1;
if ((s = socket(domain, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
errno = WSAGetLastError();
anetSetError(err, "create socket error: %d\n", errno);
return ANET_ERR;
}
/* Make sure connection-intensive things like the redis benckmark
* will be able to close/open sockets a zillion of times */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == SOCKET_ERROR) {
errno = WSAGetLastError();
anetSetError(err, "setsockopt SO_REUSEADDR: %d\n", errno);
return ANET_ERR;
}
return (int)s;
}
#define ANET_CONNECT_NONE 0
#define ANET_CONNECT_NONBLOCK 1
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
{
int s;
struct sockaddr_in sa;
unsigned long inAddress;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR;
sa.sin_family = AF_INET;
sa.sin_port = htons((u_short)port);
inAddress = inet_addr(addr);
if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) {
struct hostent *he;
he = gethostbyname(addr);
if (he == NULL) {
anetSetError(err, "can't resolve: %s\n", addr);
closesocket(s);
return ANET_ERR;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
else {
sa.sin_addr.s_addr = inAddress;
}
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect((SOCKET)s, (struct sockaddr*)&sa, sizeof(sa)) == SOCKET_ERROR) {
errno = WSAGetLastError();
if ((errno == WSAEWOULDBLOCK)) errno = EINPROGRESS;
if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) {
aeWinSocketAttach(s);
return s;
}
anetSetError(err, "connect: %d\n", errno);
closesocket(s);
return ANET_ERR;
}
if (flags & ANET_CONNECT_NONBLOCK) {
aeWinSocketAttach(s);
}
return s;
}
#else
static int anetCreateSocket(char *err, int domain) {
int s, on = 1;
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
anetSetError(err, "creating socket: %s", strerror(errno));
return ANET_ERR;
@@ -153,6 +262,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (inet_aton(addr, &sa.sin_addr) == 0) {
struct hostent *he;
@@ -164,10 +274,12 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
if (errno == EINPROGRESS &&
flags & ANET_CONNECT_NONBLOCK)
@@ -179,6 +291,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
}
return s;
}
#endif
int anetTcpConnect(char *err, char *addr, int port)
{
@@ -192,6 +305,13 @@ int anetTcpNonBlockConnect(char *err, char *addr, int port)
int anetUnixGenericConnect(char *err, char *path, int flags)
{
#ifdef _WIN32
ANET_NOTUSED(err);
ANET_NOTUSED(path);
ANET_NOTUSED(flags);
return ANET_ERR;
#else
int s;
struct sockaddr_un sa;
@@ -214,6 +334,7 @@ int anetUnixGenericConnect(char *err, char *path, int flags)
return ANET_ERR;
}
return s;
#endif
}
int anetUnixConnect(char *err, char *path)
@@ -232,7 +353,11 @@ int anetRead(int fd, char *buf, int count)
{
int nread, totlen = 0;
while(totlen != count) {
#ifdef _WIN32
nread = recv((SOCKET)fd,buf,count-totlen,0);
#else
nread = read(fd,buf,count-totlen);
#endif
if (nread == 0) return totlen;
if (nread == -1) return -1;
totlen += nread;
@@ -247,7 +372,11 @@ int anetWrite(int fd, char *buf, int count)
{
int nwritten, totlen = 0;
while(totlen != count) {
#ifdef _WIN32
nwritten = send((SOCKET)fd,buf,count-totlen,0);
#else
nwritten = write(fd,buf,count-totlen);
#endif
if (nwritten == 0) return totlen;
if (nwritten == -1) return -1;
totlen += nwritten;
@@ -256,6 +385,73 @@ int anetWrite(int fd, char *buf, int count)
return totlen;
}
#ifdef _WIN32
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
int r = bind((SOCKET)s,sa,len);
if (r == SOCKET_ERROR) {
errno = WSAGetLastError();
anetSetError(err, "bind error: %d\n", errno);
closesocket((SOCKET)s);
return ANET_ERR;
}
if (aeWinListen((SOCKET)s, 511) == SOCKET_ERROR) { /* the magic 511 constant is from nginx */
errno = WSAGetLastError();
anetSetError(err, "listen error: %d\n", errno);
closesocket((SOCKET)s);
return ANET_ERR;
}
return ANET_OK;
}
int anetTcpServer(char *err, int port, char *bindaddr)
{
int s;
int y = 1;
int n = 0;
struct sockaddr_in sa;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR;
/* Override for SO_REUSEADDR for windows server socks */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == SOCKET_ERROR) {
errno = WSAGetLastError();
anetSetError(err, "setsockopt SO_REUSEADDR: %d\n", errno);
return ANET_ERR;
}
if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(char *) &y, sizeof(y)) == SOCKET_ERROR) {
errno = WSAGetLastError();
anetSetError(err, "setsockopt SO_EXCLUSIVEADDRUSE: %d\n", errno);
return ANET_ERR;
}
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr) {
unsigned long inAddress;
inAddress = inet_addr(bindaddr);
if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) {
anetSetError(err, "Invalid bind address\n");
aeWinSocketDetach(s, 0);
closesocket((SOCKET)s);
return ANET_ERR;
}
else {
sa.sin_addr.s_addr = inAddress;
};
}
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
return ANET_ERR;
return s;
}
#else
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
if (bind(s,sa,len) == -1) {
anetSetError(err, "bind: %s", strerror(errno));
@@ -291,9 +487,16 @@ int anetTcpServer(char *err, int port, char *bindaddr)
return ANET_ERR;
return s;
}
#endif /* _WIN32 */
int anetUnixServer(char *err, char *path, mode_t perm)
{
#ifdef _WIN32
ANET_NOTUSED(err);
ANET_NOTUSED(path);
ANET_NOTUSED(perm);
return ANET_ERR;
#else
int s;
struct sockaddr_un sa;
@@ -308,8 +511,27 @@ int anetUnixServer(char *err, char *path, mode_t perm)
if (perm)
chmod(sa.sun_path, perm);
return s;
#endif
}
#ifdef _WIN32
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
SOCKET fd;
while(1) {
fd = aeWinAccept((SOCKET)s,sa,len);
if (fd == INVALID_SOCKET) {
if (errno == WSAEINTR)
continue;
else {
anetSetError(err, "accept: %s\n", strerror(errno));
return ANET_ERR;
}
}
break;
}
return (int)fd;
}
#else
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
int fd;
while(1) {
@@ -326,6 +548,7 @@ static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *l
}
return fd;
}
#endif
int anetTcpAccept(char *err, int s, char *ip, int *port) {
int fd;
@@ -340,6 +563,11 @@ int anetTcpAccept(char *err, int s, char *ip, int *port) {
}
int anetUnixAccept(char *err, int s) {
#ifdef _WIN32
ANET_NOTUSED(err);
ANET_NOTUSED(s);
return ANET_ERR;
#else
int fd;
struct sockaddr_un sa;
socklen_t salen = sizeof(sa);
@@ -347,6 +575,7 @@ int anetUnixAccept(char *err, int s) {
return ANET_ERR;
return fd;
#endif
}
int anetPeerToString(int fd, char *ip, int *port) {
+116 -4
View File
@@ -5,14 +5,20 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#endif
void aofUpdateCurrentSize(void);
void aof_background_fsync(int fd) {
#ifdef _WIN32
bioCreateBackgroundJob(REDIS_BIO_AOF_FSYNC,(void*)(size_t)fd,NULL,NULL);
#else
bioCreateBackgroundJob(REDIS_BIO_AOF_FSYNC,(void*)(long)fd,NULL,NULL);
#endif
}
/* Called when the user switches from "appendonly yes" to "appendonly no"
@@ -27,10 +33,15 @@ void stopAppendOnly(void) {
server.appendonly = 0;
/* rewrite operation in progress? kill it, wait child exit */
if (server.bgrewritechildpid != -1) {
#ifdef _WIN32
/* Windows placeholder for killing whatever lounched instead of fork() */
w32CeaseAndDesist(server.bgsavechildpid);
#else
int statloc;
if (kill(server.bgrewritechildpid,SIGKILL) != -1)
wait3(&statloc,0,NULL);
#endif
/* reset the buffer accumulating changes while the child saves */
sdsfree(server.bgrewritebuf);
server.bgrewritebuf = sdsempty();
@@ -43,7 +54,11 @@ void stopAppendOnly(void) {
int startAppendOnly(void) {
server.appendonly = 1;
server.lastfsync = time(NULL);
#ifdef _WIN32
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT|_O_BINARY,_S_IREAD|_S_IWRITE);
#else
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
#endif
if (server.appendfd == -1) {
redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, but I can't open the AOF file: %s",strerror(errno));
return REDIS_ERR;
@@ -182,7 +197,7 @@ sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) {
sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
int argc = 3;
long when;
time_t when;
robj *argv[3];
/* Make sure we can use strtol */
@@ -192,8 +207,13 @@ sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
argv[0] = createStringObject("EXPIREAT",8);
argv[1] = key;
#ifdef _WIN32
argv[2] = createObject(REDIS_STRING,
sdscatprintf(sdsempty(),"%lld",(long long)when));
#else
argv[2] = createObject(REDIS_STRING,
sdscatprintf(sdsempty(),"%ld",when));
#endif
buf = catAppendOnlyGenericCommand(buf, argc, argv);
decrRefCount(argv[0]);
decrRefCount(argv[2]);
@@ -281,7 +301,11 @@ void freeFakeClient(struct redisClient *c) {
* fatal error an error message is logged and the program exists. */
int loadAppendOnlyFile(char *filename) {
struct redisClient *fakeClient;
#ifdef _WIN32
FILE *fp = fopen(filename,"rb");
#else
FILE *fp = fopen(filename,"r");
#endif
struct redis_stat sb;
int appendonly = server.appendonly;
long loops = 0;
@@ -306,7 +330,11 @@ int loadAppendOnlyFile(char *filename) {
while(1) {
int argc, j;
#ifdef _WIN32
size_t len;
#else
unsigned long len;
#endif
robj **argv;
char buf[128];
sds argsds;
@@ -314,7 +342,7 @@ int loadAppendOnlyFile(char *filename) {
/* Serve the clients from time to time */
if (!(loops++ % 1000)) {
loadingProgress(ftello(fp));
loadingProgress((off_t)ftello(fp));
aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
}
@@ -327,7 +355,6 @@ int loadAppendOnlyFile(char *filename) {
if (buf[0] != '*') goto fmterr;
argc = atoi(buf+1);
if (argc < 1) goto fmterr;
argv = zmalloc(sizeof(robj*)*argc);
for (j = 0; j < argc; j++) {
if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
@@ -360,7 +387,6 @@ int loadAppendOnlyFile(char *filename) {
for (j = 0; j < fakeClient->argc; j++)
decrRefCount(fakeClient->argv[j]);
zfree(fakeClient->argv);
}
/* This point can only be reached when EOF is reached without errors.
@@ -400,7 +426,11 @@ int rewriteAppendOnlyFile(char *filename) {
/* Note that we have to use a different temp name here compared to the
* one used by rewriteAppendOnlyFileBackground() function. */
snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
#ifdef _WIN32
fp = fopen(tmpfile,"wb");
#else
fp = fopen(tmpfile,"w");
#endif
if (!fp) {
redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
return REDIS_ERR;
@@ -657,6 +687,31 @@ int rewriteAppendOnlyFileBackground(void) {
} else {
/* Parent */
server.stat_fork_time = ustime()-start;
#ifdef _WIN32
if (childpid == -1) {
char tmpfile[256];
childpid = getpid();
snprintf(tmpfile,256,"temp-rewriteaof-bg-%lld.aof", (long long)childpid);
server.bgrewritechildpid = childpid;
updateDictResizePolicy();
server.appendseldb = -1;
redisLog(REDIS_NOTICE,
"Foreground append only file rewriting started by pid %lld",(long long)childpid);
if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
backgroundRewriteDoneHandler(0);
return REDIS_OK;
} else {
backgroundRewriteDoneHandler(0xff);
redisLog(REDIS_WARNING,
"Can't rewrite append only file in background: spoon: %s",
strerror(errno));
return REDIS_ERR;
}
}
#else
if (childpid == -1) {
redisLog(REDIS_WARNING,
"Can't rewrite append only file in background: fork: %s",
@@ -667,6 +722,7 @@ int rewriteAppendOnlyFileBackground(void) {
"Background append only file rewriting started by pid %d",childpid);
server.aofrewrite_scheduled = 0;
server.bgrewritechildpid = childpid;
#endif
updateDictResizePolicy();
/* We set appendseldb to -1 in order to force the next call to the
* feedAppendOnlyFile() to issue a SELECT command, so the differences
@@ -705,6 +761,12 @@ void aofRemoveTempFile(pid_t childpid) {
void aofUpdateCurrentSize(void) {
struct redis_stat sb;
#ifdef _WIN32
if (server.appendfd == -1) {
redisLog(REDIS_NOTICE,"Unable to check the AOF length: %s", "appendfd is -1");
return;
}
#endif
if (redis_fstat(server.appendfd,&sb) == -1) {
redisLog(REDIS_WARNING,"Unable to check the AOF length: %s",
strerror(errno));
@@ -724,6 +786,9 @@ void backgroundRewriteDoneHandler(int statloc) {
int nwritten;
char tmpfile[256];
long long now = ustime();
#ifdef _WIN32
char tmpfile_old[256];
#endif
redisLog(REDIS_NOTICE,
"Background AOF rewrite terminated with success");
@@ -732,7 +797,11 @@ void backgroundRewriteDoneHandler(int statloc) {
* rewritten AOF. */
snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof",
(int)server.bgrewritechildpid);
#ifdef _WIN32
newfd = open(tmpfile,O_WRONLY|O_APPEND|O_CREAT|_O_BINARY,_S_IREAD|_S_IWRITE);
#else
newfd = open(tmpfile,O_WRONLY|O_APPEND);
#endif
if (newfd == -1) {
redisLog(REDIS_WARNING,
"Unable to open the temporary AOF produced by the child: %s", strerror(errno));
@@ -782,6 +851,44 @@ void backgroundRewriteDoneHandler(int statloc) {
* guarantee atomicity for this switch has already happened by then, so
* we don't care what the outcome or duration of that close operation
* is, as long as the file descriptor is released again. */
#ifdef _WIN32
oldfd = -1; /* We'll set this to the current AOF filedes later. */
/* Close files before renaming */
close(newfd);
if (server.appendfd != -1) close(server.appendfd);
/* now rename the existing file to allow new file to be renamed */
snprintf(tmpfile_old,256,"temp-rewriteaof-old-%d.aof",
(int)server.bgrewritechildpid);
if (server.appendfd != -1) {
if (rename(server.appendfilename, tmpfile_old) == -1) {
redisLog(REDIS_WARNING,
"Error trying to rename the existing AOF to old tempfile: %s", strerror(errno));
}
}
if (rename(tmpfile,server.appendfilename) == -1) {
redisLog(REDIS_WARNING,
"Error trying to rename the temporary AOF: %s", strerror(errno));
if (server.appendfd != -1) {
if (rename(tmpfile_old, server.appendfilename) == -1) {
redisLog(REDIS_WARNING,
"Error trying to rename the existing AOF from old tempfile: %s", strerror(errno));
}
}
if (oldfd != -1) close(oldfd);
goto cleanup;
}
/* now open the files again with new names */
newfd = open(server.appendfilename, O_WRONLY|O_APPEND|_O_BINARY);
if (newfd == -1) {
/* Windows fix: More info */
redisLog(REDIS_WARNING, "Not able to reopen the temporary AOF file after rename");
goto cleanup;
}
if (server.appendfd != -1) {
server.appendfd = open(tmpfile_old, O_WRONLY|O_APPEND|O_CREAT|_O_BINARY,0644);
}
#else
if (server.appendfd == -1) {
/* AOF disabled */
@@ -803,6 +910,7 @@ void backgroundRewriteDoneHandler(int statloc) {
if (oldfd != -1) close(oldfd);
goto cleanup;
}
#endif
if (server.appendfd == -1) {
/* AOF disabled, we don't need to set the AOF file descriptor
@@ -829,7 +937,11 @@ void backgroundRewriteDoneHandler(int statloc) {
redisLog(REDIS_NOTICE, "Background AOF rewrite successful");
/* Asynchronously close the overwritten AOF. */
#ifdef _WIN32
if (oldfd != -1) bioCreateBackgroundJob(REDIS_BIO_CLOSE_FILE,(void*)(size_t)oldfd,NULL,NULL);
#else
if (oldfd != -1) bioCreateBackgroundJob(REDIS_BIO_CLOSE_FILE,(void*)(long)oldfd,NULL,NULL);
#endif
redisLog(REDIS_VERBOSE,
"Background AOF rewrite signal handler took %lldus", ustime()-now);
+10 -3
View File
@@ -30,6 +30,9 @@
#include "redis.h"
#include "bio.h"
#ifdef _WIN32
#include "win32fixes.h"
#endif
static pthread_mutex_t bio_mutex[REDIS_BIO_NUM_OPS];
static pthread_cond_t bio_condvar[REDIS_BIO_NUM_OPS];
@@ -107,7 +110,11 @@ void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3) {
void *bioProcessBackgroundJobs(void *arg) {
struct bio_job *job;
#ifdef _WIN32
size_t type = (size_t) arg;
#else
unsigned long type = (unsigned long) arg;
#endif
pthread_detach(pthread_self());
pthread_mutex_lock(&bio_mutex[type]);
@@ -128,9 +135,9 @@ void *bioProcessBackgroundJobs(void *arg) {
/* Process the job accordingly to its type. */
if (type == REDIS_BIO_CLOSE_FILE) {
close((long)job->arg1);
close((long)(size_t)job->arg1);
} else if (type == REDIS_BIO_AOF_FSYNC) {
aof_fsync((long)job->arg1);
aof_fsync((long)(size_t)job->arg1);
} else {
redisPanic("Wrong job type in bioProcessBackgroundJobs().");
}
@@ -156,7 +163,7 @@ unsigned long long bioPendingJobsOfType(int type) {
#if 0 /* We don't use the following code for now, and bioWaitPendingJobsLE
probably needs a rewrite using conditional variables instead of the
current implementation. */
/* Wait until the number of pending jobs of the specified type are
* less or equal to the specified number.
+36 -22
View File
@@ -1,4 +1,8 @@
#include "redis.h"
#include <string.h>
#ifdef _WIN32
#include <direct.h>
#endif
/*-----------------------------------------------------------------------------
* Config file parsing
@@ -34,7 +38,11 @@ void loadServerConfig(char *filename) {
if (filename[0] == '-' && filename[1] == '\0')
fp = stdin;
else {
#ifdef _WIN32
if ((fp = fopen(filename,"rb")) == NULL) {
#else
if ((fp = fopen(filename,"r")) == NULL) {
#endif
redisLog(REDIS_WARNING, "Fatal error, can't open config file '%s'", filename);
exit(1);
}
@@ -128,6 +136,11 @@ void loadServerConfig(char *filename) {
if (server.syslog_ident) zfree(server.syslog_ident);
server.syslog_ident = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"syslog-facility") && argc == 2) {
#ifdef _WIN32
// Skip error - just ignore Syslog
// err "Syslog is not supported on Windows platform.";
// goto loaderr;
#else
struct {
const char *name;
const int value;
@@ -156,6 +169,7 @@ void loadServerConfig(char *filename) {
err = "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7";
goto loaderr;
}
#endif
} else if (!strcasecmp(argv[0],"databases") && argc == 2) {
server.dbnum = atoi(argv[1]);
if (server.dbnum < 1) {
@@ -260,7 +274,7 @@ void loadServerConfig(char *filename) {
} else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") &&
argc == 2)
{
server.auto_aofrewrite_min_size = memtoll(argv[1],NULL);
server.auto_aofrewrite_min_size = (off_t)memtoll(argv[1],NULL);
} else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
server.requirepass = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
@@ -270,19 +284,19 @@ void loadServerConfig(char *filename) {
zfree(server.dbfilename);
server.dbfilename = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) {
server.hash_max_zipmap_entries = memtoll(argv[1], NULL);
server.hash_max_zipmap_entries = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) {
server.hash_max_zipmap_value = memtoll(argv[1], NULL);
server.hash_max_zipmap_value = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
server.list_max_ziplist_entries = memtoll(argv[1], NULL);
server.list_max_ziplist_entries = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
server.list_max_ziplist_value = memtoll(argv[1], NULL);
server.list_max_ziplist_value = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"set-max-intset-entries") && argc == 2) {
server.set_max_intset_entries = memtoll(argv[1], NULL);
server.set_max_intset_entries = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"zset-max-ziplist-entries") && argc == 2) {
server.zset_max_ziplist_entries = memtoll(argv[1], NULL);
server.zset_max_ziplist_entries = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"zset-max-ziplist-value") && argc == 2) {
server.zset_max_ziplist_value = memtoll(argv[1], NULL);
server.zset_max_ziplist_value = (size_t)memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {
struct redisCommand *cmd = lookupCommand(argv[1]);
int retval;
@@ -312,7 +326,7 @@ void loadServerConfig(char *filename) {
{
server.slowlog_log_slower_than = strtoll(argv[1],NULL,10);
} else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) {
server.slowlog_max_len = strtoll(argv[1],NULL,10);
server.slowlog_max_len = (unsigned long)strtoll(argv[1],NULL,10);
} else {
err = "Bad directive or wrong number of arguments"; goto loaderr;
}
@@ -377,11 +391,11 @@ void configSetCommand(redisClient *c) {
} else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-samples")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll <= 0) goto badfmt;
server.maxmemory_samples = ll;
server.maxmemory_samples = (int)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll < 0 || ll > LONG_MAX) goto badfmt;
server.maxidletime = ll;
server.maxidletime = (int)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
if (!strcasecmp(o->ptr,"no")) {
server.appendfsync = APPENDFSYNC_NO;
@@ -415,10 +429,10 @@ void configSetCommand(redisClient *c) {
}
} else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-percentage")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.auto_aofrewrite_perc = ll;
server.auto_aofrewrite_perc = (int)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-min-size")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.auto_aofrewrite_min_size = ll;
server.auto_aofrewrite_min_size = (off_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"save")) {
int vlen, j;
sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
@@ -434,7 +448,7 @@ void configSetCommand(redisClient *c) {
char *eptr;
long val;
val = strtoll(v[j], &eptr, 10);
val = (long)strtoll(v[j], &eptr, 10);
if (eptr[0] != '\0' ||
((j & 1) == 0 && val < 1) ||
((j & 1) == 1 && val < 0)) {
@@ -449,7 +463,7 @@ void configSetCommand(redisClient *c) {
int changes;
seconds = strtoll(v[j],NULL,10);
changes = strtoll(v[j+1],NULL,10);
changes = (int)strtoll(v[j+1],NULL,10);
appendServerSaveParams(seconds, changes);
}
sdsfreesplitres(v,vlen);
@@ -465,25 +479,25 @@ void configSetCommand(redisClient *c) {
}
} else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.hash_max_zipmap_entries = ll;
server.hash_max_zipmap_entries = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-value")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.hash_max_zipmap_value = ll;
server.hash_max_zipmap_value = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.list_max_ziplist_entries = ll;
server.list_max_ziplist_entries = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-value")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.list_max_ziplist_value = ll;
server.list_max_ziplist_value = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"set-max-intset-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.set_max_intset_entries = ll;
server.set_max_intset_entries = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.zset_max_ziplist_entries = ll;
server.zset_max_ziplist_entries = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.zset_max_ziplist_value = ll;
server.zset_max_ziplist_value = (size_t)ll;
} else if (!strcasecmp(c->argv[2]->ptr,"slowlog-log-slower-than")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR) goto badfmt;
server.slowlog_log_slower_than = ll;
+2 -2
View File
@@ -184,7 +184,7 @@ void flushallCommand(redisClient *c) {
if (server.saveparamslen > 0) {
/* Normally rdbSave() will reset dirty, but we don't want this here
* as otherwise FLUSHALL will not be replicated nor put into the AOF. */
int saved_dirty = server.dirty;
long long saved_dirty = server.dirty;
rdbSave(server.dbfilename);
server.dirty = saved_dirty;
}
@@ -542,7 +542,7 @@ void expireCommand(redisClient *c) {
}
void expireatCommand(redisClient *c) {
expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL));
expireGenericCommand(c,c->argv[1],c->argv[2],(long)time(NULL));
}
void ttlCommand(redisClient *c) {
+8 -2
View File
@@ -1,7 +1,9 @@
#include "redis.h"
#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
#ifndef _WIN32
#include <arpa/inet.h>
#endif
/* ================================= Debugging ============================== */
@@ -238,6 +240,7 @@ void debugCommand(redisClient *c) {
redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
char *strenc;
dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
robj *val;
@@ -246,7 +249,6 @@ void debugCommand(redisClient *c) {
return;
}
val = dictGetEntryVal(de);
char *strenc;
strenc = strEncoding(val->encoding);
addReplyStatusFormat(c,
@@ -293,7 +295,7 @@ void debugCommand(redisClient *c) {
sdsfree(d);
} else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
double dtime = strtod(c->argv[2]->ptr,NULL);
long long utime = dtime*1000000;
long long utime = (long long)(dtime*1000000);
usleep(utime);
addReply(c,shared.ok);
@@ -304,7 +306,9 @@ void debugCommand(redisClient *c) {
}
void _redisAssert(char *estr, char *file, int line) {
#ifdef HAVE_BACKTRACE
bugReportStart();
#endif
redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
#ifdef HAVE_BACKTRACE
@@ -317,7 +321,9 @@ void _redisAssert(char *estr, char *file, int line) {
}
void _redisPanic(char *msg, char *file, int line) {
#ifdef HAVE_BACKTRACE
bugReportStart();
#endif
redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
#ifdef HAVE_BACKTRACE
+88 -1
View File
@@ -41,11 +41,14 @@
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <ctype.h>
#include "dict.h"
#include "zmalloc.h"
#include "win32fixes.h"
/* Using dictEnableResize() / dictDisableResize() we make possible to
* enable/disable resizing of the hash table as needed. This is very important
@@ -61,7 +64,11 @@ static unsigned int dict_force_resize_ratio = 5;
/* -------------------------- private prototypes ---------------------------- */
static int _dictExpandIfNeeded(dict *ht);
#ifdef _WIN32
static size_t _dictNextPower(size_t size);
#else
static unsigned long _dictNextPower(unsigned long size);
#endif
static int _dictKeyIndex(dict *ht, const void *key);
static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
@@ -151,7 +158,37 @@ int dictResize(dict *d)
minimal = DICT_HT_INITIAL_SIZE;
return dictExpand(d, minimal);
}
#ifdef _WIN32
/* Expand or create the hashtable */
int dictExpand(dict *d, size_t size)
{
dictht n; /* the new hashtable */
size_t realsize = _dictNextPower(size);
/* the size is invalid if it is smaller than the number of
* elements already inside the hashtable */
if (dictIsRehashing(d) || d->ht[0].used > size)
return DICT_ERR;
/* Allocate the new hashtable and initialize all pointers to NULL */
n.size = realsize;
n.sizemask = realsize-1;
n.table = zcalloc(realsize*sizeof(dictEntry*));
n.used = (size_t) 0;
/* Is this the first initialization? If so it's not really a rehashing
* we just set the first hash table so that it can accept keys. */
if (d->ht[0].table == NULL) {
d->ht[0] = n;
return DICT_OK;
}
/* Prepare a second hash table for incremental rehashing */
d->ht[1] = n;
d->rehashidx = 0;
return DICT_OK;
}
#else
/* Expand or create the hashtable */
int dictExpand(dict *d, unsigned long size)
{
@@ -181,7 +218,7 @@ int dictExpand(dict *d, unsigned long size)
d->rehashidx = 0;
return DICT_OK;
}
#endif
/* Performs N steps of incremental rehashing. Returns 1 if there are still
* keys to move from the old to the new hash table, otherwise 0 is returned.
* Note that a rehashing step consists in moving a bucket (that may have more
@@ -225,10 +262,14 @@ int dictRehash(dict *d, int n) {
}
long long timeInMilliseconds(void) {
#ifdef _WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
#endif
}
/* Rehash for an amount of time between ms milliseconds and ms+1 milliseconds */
@@ -357,7 +398,11 @@ int dictDeleteNoFree(dict *ht, const void *key) {
/* Destroy an entire dictionary */
int _dictClear(dict *d, dictht *ht)
{
#ifdef _WIN32
size_t i;
#else
unsigned long i;
#endif
/* Free all the elements */
for (i = 0; i < ht->size && ht->used > 0; i++) {
@@ -507,6 +552,7 @@ dictEntry *dictGetRandomKey(dict *d)
he = he->next;
listlen++;
}
listele = random() % listlen;
he = orighe;
while(listele--) he = he->next;
@@ -538,6 +584,25 @@ static int _dictExpandIfNeeded(dict *d)
return DICT_OK;
}
#ifdef _WIN32
/* Our hash table capability is a power of two */
static size_t _dictNextPower(size_t size)
{
size_t i = DICT_HT_INITIAL_SIZE;
#ifdef _WIN64
if (size >= LONG_LONG_MAX) return LONG_LONG_MAX;
#else
if (size >= LONG_MAX) return LONG_MAX;
#endif
while(1) {
if (i >= size)
return i;
i *= 2;
}
}
#else
/* Our hash table capability is a power of two */
static unsigned long _dictNextPower(unsigned long size)
{
@@ -550,6 +615,7 @@ static unsigned long _dictNextPower(unsigned long size)
i *= 2;
}
}
#endif
/* Returns the index of a free slot that can be populated with
* an hash entry for the given 'key'.
@@ -590,9 +656,15 @@ void dictEmpty(dict *d) {
#define DICT_STATS_VECTLEN 50
static void _dictPrintStatsHt(dictht *ht) {
#ifdef _WIN32
size_t i, slots = 0, chainlen, maxchainlen = 0;
size_t totchainlen = 0;
size_t clvector[DICT_STATS_VECTLEN];
#else
unsigned long i, slots = 0, chainlen, maxchainlen = 0;
unsigned long totchainlen = 0;
unsigned long clvector[DICT_STATS_VECTLEN];
#endif
if (ht->used == 0) {
printf("No stats available for empty dictionaries\n");
@@ -619,6 +691,20 @@ static void _dictPrintStatsHt(dictht *ht) {
if (chainlen > maxchainlen) maxchainlen = chainlen;
totchainlen += chainlen;
}
#ifdef _WIN32
printf("Hash table stats:\n");
printf(" table size: %llu\n", (unsigned long long)ht->size);
printf(" number of elements: %llu\n", (unsigned long long)ht->used);
printf(" different slots: %llu\n", (unsigned long long)slots);
printf(" max chain length: %llu\n", (unsigned long long)maxchainlen);
printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
printf(" Chain length distribution:\n");
for (i = 0; i < DICT_STATS_VECTLEN-1; i++) {
if (clvector[i] == 0) continue;
printf(" %s%lld: %llu (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", (long long)i, (unsigned long long)clvector[i], ((float)clvector[i]/(float)ht->size)*100.00);
}
#else
printf("Hash table stats:\n");
printf(" table size: %ld\n", ht->size);
printf(" number of elements: %ld\n", ht->used);
@@ -631,6 +717,7 @@ static void _dictPrintStatsHt(dictht *ht) {
if (clvector[i] == 0) continue;
printf(" %s%ld: %ld (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
}
#endif
}
void dictPrintStats(dict *d) {
+13
View File
@@ -59,12 +59,21 @@ typedef struct dictType {
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
#ifdef _WIN32
typedef struct dictht {
dictEntry **table;
size_t size;
size_t sizemask;
size_t used;
} dictht;
#else
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
#endif
typedef struct dict {
dictType *type;
@@ -125,7 +134,11 @@ typedef struct dictIterator {
/* API */
dict *dictCreate(dictType *type, void *privDataPtr);
#ifdef _WIN32
int dictExpand(dict *d, size_t size);
#else
int dictExpand(dict *d, unsigned long size);
#endif
int dictAdd(dict *d, void *key, void *val);
int dictReplace(dict *d, void *key, void *val);
int dictDelete(dict *d, const void *key);
+4
View File
@@ -12,4 +12,8 @@
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS 64
#ifdef _WIN32
#define off off_t
#endif
#endif
+2 -2
View File
@@ -53,10 +53,10 @@ static void _intsetSet(intset *is, int pos, int64_t value) {
((int64_t*)is->contents)[pos] = value;
memrev64ifbe(((int64_t*)is->contents)+pos);
} else if (is->encoding == INTSET_ENC_INT32) {
((int32_t*)is->contents)[pos] = value;
((int32_t*)is->contents)[pos] = (int32_t)value;
memrev32ifbe(((int32_t*)is->contents)+pos);
} else {
((int16_t*)is->contents)[pos] = value;
((int16_t*)is->contents)[pos] = (int16_t)value;
memrev16ifbe(((int16_t*)is->contents)+pos);
}
}
+7 -7
View File
@@ -120,8 +120,8 @@ lzf_compress (const void *const in_data, unsigned int in_len,
* and fails to support both assumptions is windows 64 bit, we make a
* special workaround for it.
*/
#if defined (WIN32) && defined (_M_X64)
unsigned _int64 off; /* workaround for missing POSIX compliance */
#if defined (_WIN32)
unsigned _int64 off;
#else
unsigned long off;
#endif
@@ -167,7 +167,7 @@ lzf_compress (const void *const in_data, unsigned int in_len,
{
/* match found at *ref++ */
unsigned int len = 2;
unsigned int maxlen = in_end - ip - len;
unsigned int maxlen = (unsigned int)(in_end - ip - len);
maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
op [- lit - 1] = lit - 1; /* stop run */
@@ -213,15 +213,15 @@ lzf_compress (const void *const in_data, unsigned int in_len,
if (len < 7)
{
*op++ = (off >> 8) + (len << 5);
*op++ = (u8)((off >> 8) + (len << 5));
}
else
{
*op++ = (off >> 8) + ( 7 << 5);
*op++ = (u8)((off >> 8) + ( 7 << 5));
*op++ = len - 7;
}
*op++ = off;
*op++ = (u8)(off);
lit = 0; op++; /* start run */
ip += len + 1;
@@ -290,6 +290,6 @@ lzf_compress (const void *const in_data, unsigned int in_len,
op [- lit - 1] = lit - 1; /* end run */
op -= !lit; /* undo run if length is zero */
return op - (u8 *)out_data;
return (unsigned int)(op - (u8 *)out_data);
}
+1 -1
View File
@@ -145,6 +145,6 @@ lzf_decompress (const void *const in_data, unsigned int in_len,
}
while (ip < in_end);
return op - (u8 *)out_data;
return (unsigned int)(op - (u8 *)out_data);
}
+240 -5
View File
@@ -1,5 +1,7 @@
#include "redis.h"
#ifndef _WIN32
#include <sys/uio.h>
#endif
static void setProtocolError(redisClient *c, int pos);
@@ -21,7 +23,12 @@ redisClient *createClient(int fd) {
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
#ifdef _WIN32
aeWinSocketDetach(fd, 0);
closesocket(fd);
#else
close(fd);
#endif
zfree(c);
return NULL;
}
@@ -36,6 +43,10 @@ redisClient *createClient(int fd) {
c->multibulklen = 0;
c->bulklen = -1;
c->sentlen = 0;
#ifdef _WIN32
c->sentobjlen = 0;
c->sentobj = NULL;
#endif
c->flags = 0;
c->lastinteraction = time(NULL);
c->authenticated = 0;
@@ -118,8 +129,13 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
#ifdef _WIN32
if (tail->ptr != NULL && tail != c->sentobj &&
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
#else
if (tail->ptr != NULL &&
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
#endif
{
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
@@ -146,8 +162,13 @@ void _addReplySdsToList(redisClient *c, sds s) {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
#ifdef _WIN32
if (tail->ptr != NULL && tail != c->sentobj &&
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
#else
if (tail->ptr != NULL &&
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
#endif
{
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
@@ -169,8 +190,13 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
#ifdef _WIN32
if (tail->ptr != NULL && tail != c->sentobj &&
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
#else
if (tail->ptr != NULL &&
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
#endif
{
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,s,len);
@@ -240,9 +266,10 @@ void addReplyError(redisClient *c, char *err) {
}
void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
sds s;
va_list ap;
va_start(ap,fmt);
sds s = sdscatvprintf(sdsempty(),fmt,ap);
s = sdscatvprintf(sdsempty(),fmt,ap);
va_end(ap);
_addReplyError(c,s,sdslen(s));
sdsfree(s);
@@ -259,9 +286,10 @@ void addReplyStatus(redisClient *c, char *status) {
}
void addReplyStatusFormat(redisClient *c, const char *fmt, ...) {
sds s;
va_list ap;
va_start(ap,fmt);
sds s = sdscatvprintf(sdsempty(),fmt,ap);
s = sdscatvprintf(sdsempty(),fmt,ap);
va_end(ap);
_addReplyStatus(c,s,sdslen(s));
sdsfree(s);
@@ -303,7 +331,20 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
void addReplyDouble(redisClient *c, double d) {
char dbuf[128], sbuf[128];
int dlen, slen;
#ifdef _WIN32
if (isnan(d)) {
dlen = snprintf(dbuf,sizeof(dbuf),"nan");
} else if (isinf(d)) {
if (d < 0)
dlen = snprintf(dbuf,sizeof(dbuf),"-inf");
else
dlen = snprintf(dbuf,sizeof(dbuf),"inf");
} else {
dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
}
#else
dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
#endif
slen = snprintf(sbuf,sizeof(sbuf),"$%d\r\n%s\r\n",dlen,dbuf);
addReplyString(c,sbuf,slen);
}
@@ -401,7 +442,12 @@ static void acceptCommonHandler(int fd) {
redisClient *c;
if ((c = createClient(fd)) == NULL) {
redisLog(REDIS_WARNING,"Error allocating resoures for the client");
#ifdef _WIN32
aeWinSocketDetach(fd, 0);
closesocket(fd); /* May be already closed, just ingore errors */
#else
close(fd); /* May be already closed, just ingore errors */
#endif
return;
}
/* If maxclient directive is set and this is one client more... close the
@@ -412,7 +458,11 @@ static void acceptCommonHandler(int fd) {
char *err = "-ERR max number of clients reached\r\n";
/* That's a best effort error message, don't check write errors */
#ifdef _WIN32
if (send((SOCKET)c->fd,err,(int)strlen(err),0) == SOCKET_ERROR) {
#else
if (write(c->fd,err,strlen(err)) == -1) {
#endif
/* Nothing to do, Just to avoid the warning... */
}
freeClient(c);
@@ -469,6 +519,9 @@ void freeClient(redisClient *c) {
* unblockClientWaitingData() to avoid processInputBuffer() will get
* called. Also it is important to remove the file events after
* this, because this call adds the READABLE event. */
#ifdef _WIN32
aeWinSocketDetach(c->fd, 1);
#endif
sdsfree(c->querybuf);
c->querybuf = NULL;
if (c->flags & REDIS_BLOCKED)
@@ -487,7 +540,11 @@ void freeClient(redisClient *c) {
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
listRelease(c->reply);
freeClientArgv(c);
#ifdef _WIN32
closesocket(c->fd);
#else
close(c->fd);
#endif
/* Remove from the list of clients */
ln = listSearchKey(server.clients,c);
redisAssert(ln != NULL);
@@ -502,9 +559,10 @@ void freeClient(redisClient *c) {
/* Master/slave cleanup.
* Case 1: we lost the connection with a slave. */
if (c->flags & REDIS_SLAVE) {
list *l;
if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
close(c->repldbfd);
list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
ln = listSearchKey(l,c);
redisAssert(ln != NULL);
listDelNode(l,ln);
@@ -537,6 +595,162 @@ void freeClient(redisClient *c) {
zfree(c);
}
#ifdef _WIN32
void sendReplyBufferDone(aeEventLoop *el, int fd, void *privdata, int written) {
aeWinSendReq *req = (aeWinSendReq *)privdata;
redisClient *c = (redisClient *)req->client;
int offset = req->buf - (char *)req->data + written;
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
if (c->bufpos == offset) {
c->bufpos = 0;
c->sentlen = 0;
}
if (c->bufpos == 0 && listLength(c->reply) == 0) {
c->sentobjlen = 0;
c->sentobj = NULL;
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
/* Close connection after entire reply has been sent. */
if (c->flags & REDIS_CLOSE_AFTER_REPLY) {
freeClient(c);
}
}
}
void sendReplyListDone(aeEventLoop *el, int fd, void *privdata, int written) {
aeWinSendReq *req = (aeWinSendReq *)privdata;
redisClient *c = (redisClient *)req->client;
robj *o = (robj *)req->data;
int objlen = sdslen(o->ptr);
int offset = req->buf - (char *)o->ptr + written;
listNode *ln;
listIter li;
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
// if offset matches length, find item in list and remove
if (objlen == offset) {
listRewind(c->reply, &li);
while ((ln = listNext(&li)) != NULL) {
if (o == listNodeValue(ln)) {
listDelNode(c->reply, ln);
break;
}
}
}
decrRefCount(o);
if (c->bufpos == 0 && listLength(c->reply) == 0) {
c->sentlen = 0;
c->sentobjlen = 0;
c->sentobj = NULL;
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
/* Close connection after entire reply has been sent. */
if (c->flags & REDIS_CLOSE_AFTER_REPLY){
freeClient(c);
}
}
}
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
redisClient *c = (redisClient *)privdata;
int nwritten = 0, totwritten = 0, objlen;
int objpos = 0;
robj *o;
int result = 0;
listIter li;
listNode *ln;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
if (c->flags & REDIS_MASTER) {
/* do not send to master */
c->bufpos = 0;
c->sentlen = 0;
while (listLength(c->reply)) {
listDelNode(c->reply,listFirst(c->reply));
}
c->lastinteraction = time(NULL);
return;
}
/* move list pointer to last one sent or first in list */
listRewind(c->reply, &li);
ln = listNext(&li);
if (c->sentobj != NULL) {
int found = 0;
while (ln != NULL) {
if (c->sentobj == listNodeValue(ln)) {
found = 1;
objpos = c->sentobjlen;
break;
}
ln = listNext(&li);
}
if (found == 0) {
listRewind(c->reply, &li);
ln = listNext(&li);
}
}
while(c->bufpos > c->sentlen || ln != NULL) {
if (c->bufpos > c->sentlen) {
nwritten = c->bufpos - c->sentlen;
result = aeWinSocketSend(fd,c->buf+c->sentlen, nwritten,0,
el, c, c->buf, sendReplyBufferDone);
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
redisLog(REDIS_VERBOSE, "Error writing to client: %s", strerror(errno));
freeClient(c);
return;
}
c->sentlen += nwritten;
totwritten += nwritten;
} else {
o = listNodeValue(ln);
objlen = sdslen(o->ptr);
if (objlen == 0) {
listDelNode(c->reply,ln);
ln = listNext(&li);
continue;
}
if (objlen - objpos > 0) {
incrRefCount(o);
/* need to remember length sent for last object, as more may be added */
result = aeWinSocketSend(fd, ((char*)o->ptr)+objpos, objlen-objpos, 0,
el, c, o, sendReplyListDone);
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
redisLog(REDIS_VERBOSE,
"Error writing to client: %s", strerror(errno));
decrRefCount(o);
freeClient(c);
return;
}
totwritten += objlen-objpos;
objpos = 0;
c->sentobjlen = objlen;
c->sentobj = o;
}
ln = listNext(&li);
}
/* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
* bytes, in a single threaded server it's a good idea to serve
* other clients as well, even if a very large request comes from
* super fast link that is always able to accept data (in real world
* scenario think about 'KEYS *' against the loopback interfae) */
if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
}
if (totwritten > 0) c->lastinteraction = time(NULL);
}
#else
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
redisClient *c = privdata;
int nwritten = 0, totwritten = 0, objlen;
@@ -613,6 +827,7 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
if (c->flags & REDIS_CLOSE_AFTER_REPLY) freeClient(c);
}
}
#endif
/* resetClient prepare the client to process the next command */
void resetClient(redisClient *c) {
@@ -741,7 +956,7 @@ int processMultibulkBuffer(redisClient *c) {
return REDIS_OK;
}
c->multibulklen = ll;
c->multibulklen = (int)ll;
/* Setup argv array on client structure */
if (c->argv) zfree(c->argv);
@@ -781,7 +996,7 @@ int processMultibulkBuffer(redisClient *c) {
}
pos += newline-(c->querybuf+pos)+2;
c->bulklen = ll;
c->bulklen = (long)ll;
}
/* Read bulk argument */
@@ -852,7 +1067,24 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
#ifdef _WIN32
nread = recv((SOCKET)fd, buf, REDIS_IOBUF_LEN, 0);
if (nread < 0) {
errno = WSAGetLastError();
if (errno == WSAECONNRESET) {
/* Windows fix: Not an error, intercept it. */
redisLog(REDIS_VERBOSE, "Client closed connection");
freeClient(c);
return;
} else if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK)) {
/* Windows fix: Intercept winsock slang for EAGAIN */
errno = EAGAIN;
nread = -1; /* Winsock can send ENOENT instead EAGAIN */
}
}
#else
nread = read(fd, buf, REDIS_IOBUF_LEN);
#endif
if (nread == -1) {
if (errno == EAGAIN) {
nread = 0;
@@ -866,6 +1098,9 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
freeClient(c);
return;
}
#ifdef _WIN32
aeWinReceiveDone(fd);
#endif
if (nread) {
c->querybuf = sdscatlen(c->querybuf,buf,nread);
c->lastinteraction = time(NULL);
+2 -2
View File
@@ -282,9 +282,9 @@ robj *getDecodedObject(robj *o) {
* sdscmp() from sds.c will apply memcmp() so this function ca be considered
* binary safe. */
int compareStringObjects(robj *a, robj *b) {
redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
char bufa[128], bufb[128], *astr, *bstr;
int bothsds = 1;
redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
if (a == b) return 0;
if (a->encoding != REDIS_ENCODING_RAW) {
@@ -416,7 +416,7 @@ int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *
return REDIS_ERR;
}
*target = value;
*target = (long) value;
return REDIS_OK;
}
+10
View File
@@ -42,12 +42,17 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#ifdef _WIN32
#define inline __inline
#endif
static inline char *med3 (char *, char *, char *,
int (*)(const void *, const void *));
static inline void swapfunc (char *, char *, size_t, int);
#ifndef _WIN32
#define min(a, b) (a) < (b) ? a : b
#endif
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
@@ -63,8 +68,13 @@ static inline void swapfunc (char *, char *, size_t, int);
} while (--i > 0); \
}
#ifdef _WIN32
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(size_t) || \
es % sizeof(size_t) ? 2 : es == sizeof(size_t)? 0 : 1;
#else
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
#endif
static inline void
swapfunc(char *a, char *b, size_t n, int swaptype)
+1 -1
View File
@@ -93,8 +93,8 @@ int pubsubSubscribePattern(redisClient *c, robj *pattern) {
int retval = 0;
if (listSearchKey(c->pubsub_patterns,pattern) == NULL) {
retval = 1;
pubsubPattern *pat;
retval = 1;
listAddNodeTail(c->pubsub_patterns,pattern);
incrRefCount(pattern);
pat = zmalloc(sizeof(*pat));
+40 -4
View File
@@ -3,10 +3,12 @@
#include <math.h>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
/* Convenience wrapper around fwrite, that returns the number of bytes written
@@ -239,7 +241,7 @@ int rdbSaveDoubleValue(FILE *fp, double val) {
else
#endif
snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
buf[0] = strlen((char*)buf+1);
buf[0] = (unsigned char)strlen((char*)buf+1);
len = buf[0]+1;
}
return rdbWriteRaw(fp,buf,len);
@@ -367,7 +369,7 @@ int rdbSaveObject(FILE *fp, robj *o) {
off_t rdbSavedObjectLen(robj *o) {
int len = rdbSaveObject(NULL,o);
redisAssert(len != -1);
return len;
return (off_t)len;
}
int getObjectSaveType(robj *o) {
@@ -394,7 +396,11 @@ int rdbSave(char *filename) {
time_t now = time(NULL);
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
#ifdef _WIN32
fp = fopen(tmpfile,"wb");
#else
fp = fopen(tmpfile,"w");
#endif
if (!fp) {
redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
return REDIS_ERR;
@@ -419,6 +425,7 @@ int rdbSave(char *filename) {
sds keystr = dictGetEntryKey(de);
robj key, *o = dictGetEntryVal(de);
time_t expiretime;
int otype;
initStaticStringObject(key,keystr);
expiretime = getExpire(db,&key);
@@ -430,7 +437,7 @@ int rdbSave(char *filename) {
if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
if (rdbSaveTime(fp,expiretime) == -1) goto werr;
}
int otype = getObjectSaveType(o);
otype = getObjectSaveType(o);
/* Save type, key, value */
if (rdbSaveType(fp,otype) == -1) goto werr;
@@ -476,7 +483,14 @@ int rdbSaveBackground(char *filename) {
start = ustime();
if ((childpid = fork()) == 0) {
/* Child */
#ifdef _WIN32
if (server.ipfd > 0) {
aeWinSocketDetach(server.ipfd, 0);
closesocket(server.ipfd);
}
#else
if (server.ipfd > 0) close(server.ipfd);
#endif
if (server.sofd > 0) close(server.sofd);
if (rdbSave(filename) == REDIS_OK) {
_exit(0);
@@ -487,9 +501,27 @@ int rdbSaveBackground(char *filename) {
/* Parent */
server.stat_fork_time = ustime()-start;
if (childpid == -1) {
#ifdef _WIN32
/* On WIN32 fork() is empty function which always return -1 */
/* So, on WIN32, let's just save in foreground. */
redisLog(REDIS_NOTICE,"Foregroud saving started by pid %d", getpid());
server.bgsavechildpid = getpid();
updateDictResizePolicy();
if (rdbSave(filename) == REDIS_OK) {
backgroundSaveDoneHandler(0);
return REDIS_OK;
} else {
redisLog(REDIS_WARNING,"Can't save in background: spoon err: %s",
strerror(errno));
backgroundSaveDoneHandler(0xff);
return REDIS_ERR;
}
#else
redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
strerror(errno));
return REDIS_ERR;
#endif
}
redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
server.bgsavechildpid = childpid;
@@ -904,7 +936,11 @@ int rdbLoad(char *filename) {
time_t expiretime, now = time(NULL);
long loops = 0;
#ifdef _WIN32
fp = fopen(filename,"rb");
#else
fp = fopen(filename,"r");
#endif
if (!fp) {
errno = ENOENT;
return REDIS_ERR;
@@ -933,7 +969,7 @@ int rdbLoad(char *filename) {
/* Serve the clients from time to time */
if (!(loops++ % 1000)) {
loadingProgress(ftello(fp));
loadingProgress((off_t)ftello(fp));
aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
}
+76 -6
View File
@@ -33,12 +33,19 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#endif
#include <errno.h>
#include <signal.h>
#include <assert.h>
#ifdef _WIN32
#include "win32fixes.h"
int fmode = _O_BINARY;
#endif
#include "ae.h"
#include "hiredis.h"
#include "sds.h"
@@ -111,6 +118,9 @@ static void freeClient(client c) {
listNode *ln;
aeDeleteFileEvent(config.el,c->context->fd,AE_WRITABLE);
aeDeleteFileEvent(config.el,c->context->fd,AE_READABLE);
#ifdef _WIN32
aeWinSocketDetach(c->context->fd, 1);
#endif
redisFree(c->context);
sdsfree(c->obuf);
zfree(c);
@@ -143,7 +153,11 @@ static void randomizeClientKey(client c) {
for (i = 0; i < c->randlen; i++) {
r = random() % config.randomkeys_keyspacelen;
#ifdef _WIN32
snprintf(buf,sizeof(buf),"%012llu",(unsigned long long)r);
#else
snprintf(buf,sizeof(buf),"%012zu",r);
#endif
memcpy(c->randptr[i],buf,12);
}
}
@@ -167,6 +181,10 @@ static void clientDone(client c) {
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
client c = privdata;
void *reply = NULL;
#ifdef _WIN32
int nread;
char buf[2048];
#endif
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
REDIS_NOTUSED(mask);
@@ -176,7 +194,22 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
* is not part of the latency, so calculate it only once, here. */
if (c->latency < 0) c->latency = ustime()-(c->start);
#ifdef _WIN32
nread = recv((SOCKET)c->context->fd,buf,sizeof(buf),0);
if (nread == -1) {
errno = WSAGetLastError();
if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK)) {
errno = EAGAIN;
aeWinReceiveDone(c->context->fd);
return;
} else {
fprintf(stderr,"Error: %s\n",c->context->errstr);
exit(1);
}
} else if (redisBufferReadDone(c->context, buf, nread) != REDIS_OK) {
#else
if (redisBufferRead(c->context) != REDIS_OK) {
#endif
fprintf(stderr,"Error: %s\n",c->context->errstr);
exit(1);
} else {
@@ -184,6 +217,7 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
fprintf(stderr,"Error: %s\n",c->context->errstr);
exit(1);
}
aeWinReceiveDone(c->context->fd);
if (reply != NULL) {
if (reply == (void*)REDIS_REPLY_ERROR) {
fprintf(stderr,"Unexpected error reply, exiting...\n");
@@ -197,6 +231,19 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
}
}
#ifdef _WIN32
static void writeHandlerDone(aeEventLoop *el, int fd, void *privdata, int nwritten) {
aeWinSendReq *req = (aeWinSendReq *)privdata;
client c = (client)req->client;
c->written += nwritten;
if (sdslen(c->obuf) == c->written) {
aeDeleteFileEvent(config.el,c->context->fd,AE_WRITABLE);
aeCreateFileEvent(config.el,c->context->fd,AE_READABLE,readHandler,c);
}
}
#endif
static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
client c = privdata;
REDIS_NOTUSED(el);
@@ -219,6 +266,16 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
if (sdslen(c->obuf) > c->written) {
void *ptr = c->obuf+c->written;
#ifdef _WIN32
int result = aeWinSocketSend(c->context->fd,ptr,sdslen(c->obuf)-c->written, 0,
el, c, NULL, writeHandlerDone);
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
if (errno != EPIPE)
fprintf(stderr, "Writing to socket: %s\n", strerror(errno));
freeClient(c);
return;
}
#else
int nwritten = write(c->context->fd,ptr,sdslen(c->obuf)-c->written);
if (nwritten == -1) {
if (errno != EPIPE)
@@ -231,6 +288,7 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
aeDeleteFileEvent(config.el,c->context->fd,AE_WRITABLE);
aeCreateFileEvent(config.el,c->context->fd,AE_READABLE,readHandler,c);
}
#endif
}
}
@@ -265,6 +323,9 @@ static client createClient(const char *cmd, size_t len) {
}
}
#ifdef _WIN32
aeWinSocketAttach(c->context->fd);
#endif
redisSetReplyObjectFunctions(c->context,NULL);
aeCreateFileEvent(config.el,c->context->fd,AE_WRITABLE,writeHandler,c);
listAddNodeTail(config.clients,c);
@@ -287,7 +348,7 @@ static void createMissingClients(client c) {
}
static int compareLatency(const void *a, const void *b) {
return (*(long long*)a)-(*(long long*)b);
return (int)((*(long long*)a)-(*(long long*)b));
}
static void showLatencyReport(void) {
@@ -307,7 +368,7 @@ static void showLatencyReport(void) {
qsort(config.latency,config.requests,sizeof(long long),compareLatency);
for (i = 0; i < config.requests; i++) {
if (config.latency[i]/1000 != curlat || i == (config.requests-1)) {
curlat = config.latency[i]/1000;
curlat = (int)(config.latency[i]/1000);
perc = ((float)(i+1)*100)/config.requests;
printf("%.2f%% <= %d milliseconds\n", perc, curlat);
}
@@ -420,12 +481,14 @@ usage:
}
int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData) {
float dt;
float rps ;
REDIS_NOTUSED(eventLoop);
REDIS_NOTUSED(id);
REDIS_NOTUSED(clientData);
float dt = (float)(mstime()-config.start)/1000.0;
float rps = (float)config.requests_finished/dt;
dt = (float)((float)(mstime()-config.start)/1000.0);
rps = (float)config.requests_finished/dt;
printf("%s: %.2f\r", config.title, rps);
fflush(stdout);
return 250; /* every 250ms */
@@ -438,6 +501,10 @@ int main(int argc, const char **argv) {
client c;
#ifdef _WIN32
w32initWinSock();
#endif
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
@@ -496,6 +563,7 @@ int main(int argc, const char **argv) {
/* Run default benchmark suite. */
do {
const char *argv[21];
data = zmalloc(config.datasize+1);
memset(data,'x',config.datasize);
data[config.datasize] = '\0';
@@ -506,7 +574,6 @@ int main(int argc, const char **argv) {
benchmark("PING",cmd,len);
free(cmd);
const char *argv[21];
argv[0] = "MSET";
for (i = 1; i < 21; i += 2) {
argv[i] = "foo:rand:000000000000";
@@ -567,5 +634,8 @@ int main(int argc, const char **argv) {
printf("\n");
} while(config.loop);
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
+45 -5
View File
@@ -2,10 +2,18 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include "config.h"
#ifdef _WIN32
#include "win32fixes.h"
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
#define ERROR(...) { \
char __buf[1024]; \
sprintf(__buf, __VA_ARGS__); \
@@ -118,6 +126,20 @@ long process(FILE *fp) {
int main(int argc, char **argv) {
char *filename;
int fix = 0;
FILE *fp;
struct redis_stat sb;
long size;
long pos;
long diff;
#ifdef _WIN32
LARGE_INTEGER l;
HANDLE h;
_fmode = _O_BINARY;
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
if (argc < 2) {
printf("Usage: %s [--fix] <file.aof>\n", argv[0]);
@@ -136,26 +158,29 @@ int main(int argc, char **argv) {
exit(1);
}
FILE *fp = fopen(filename,"r+");
#ifdef _WIN32
fp = fopen(filename,"r+b");
#else
fp = fopen(filename,"r+");
#endif
if (fp == NULL) {
printf("Cannot open file: %s\n", filename);
exit(1);
}
struct redis_stat sb;
if (redis_fstat(fileno(fp),&sb) == -1) {
printf("Cannot stat file: %s\n", filename);
exit(1);
}
long size = sb.st_size;
size = sb.st_size;
if (size == 0) {
printf("Empty file: %s\n", filename);
exit(1);
}
long pos = process(fp);
long diff = size-pos;
pos = process(fp);
diff = size-pos;
if (diff > 0) {
if (fix) {
char buf[2];
@@ -166,12 +191,27 @@ int main(int argc, char **argv) {
printf("Aborting...\n");
exit(1);
}
#ifdef _WIN32
h = (HANDLE) _get_osfhandle(fileno(fp));
l.QuadPart = pos;
fflush(fp);
if (!SetFilePointerEx(h, l, &l, FILE_BEGIN) || !SetEndOfFile(h)) {
printf("Failed to truncate AOF\n");
exit(1);
} else {
printf("Successfully truncated AOF\n");
}
#else
if (ftruncate(fileno(fp), pos) == -1) {
printf("Failed to truncate AOF\n");
exit(1);
} else {
printf("Successfully truncated AOF\n");
}
#endif
} else {
printf("AOF is not valid\n");
exit(1);
+78 -16
View File
@@ -1,15 +1,57 @@
#include <stdlib.h>
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _WIN32
#include "win32fixes.h"
#else
#include <sys/mman.h>
#include <arpa/inet.h>
#endif
#include <string.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <limits.h>
#include "lzf.h"
#ifdef _WIN32
/* File maping used in redis-check-dump */
/* mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); */
void *mmap(void *start, size_t length, int prot, int flags, int fd, off offset) {
HANDLE h;
void *data;
(void)offset;
if ((flags != MAP_SHARED) || (prot != PROT_READ)) {
/* Not supported in this port */
return MAP_FAILED;
};
h = CreateFileMapping((HANDLE)_get_osfhandle(fd),
NULL,PAGE_READONLY,0,0,NULL);
if (!h) return MAP_FAILED;
data = MapViewOfFileEx(h, FILE_MAP_READ,0,0,length,start);
CloseHandle(h);
if (!data) return MAP_FAILED;
return data;
}
/* Unmap file mapping */
int munmap(void *start, size_t length) {
(void) length;
return !UnmapViewOfFile(start);
}
#endif
/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
@@ -109,10 +151,11 @@ static char types[256][16];
/* when number of bytes to read is negative, do a peek */
int readBytes(void *target, long num) {
pos p;
char peek = (num < 0) ? 1 : 0;
num = (num < 0) ? -num : num;
pos p = positions[level];
p = positions[level];
if (p.offset + num > p.size) {
return 0;
} else {
@@ -213,6 +256,7 @@ char *loadIntegerObject(int enctype) {
uint32_t offset = CURR_OFFSET;
unsigned char enc[4];
long long val;
char *buf;
if (enctype == REDIS_RDB_ENC_INT8) {
uint8_t v;
@@ -235,7 +279,6 @@ char *loadIntegerObject(int enctype) {
}
/* convert val into string */
char *buf;
buf = malloc(sizeof(char) * 128);
sprintf(buf, "%lld", val);
return buf;
@@ -269,6 +312,7 @@ char* loadStringObject() {
uint32_t offset = CURR_OFFSET;
int isencoded;
uint32_t len;
char *buf;
len = loadLength(&isencoded);
if (isencoded) {
@@ -288,7 +332,7 @@ char* loadStringObject() {
if (len == REDIS_RDB_LENERR) return NULL;
char *buf = malloc(sizeof(char) * (len+1));
buf = malloc(sizeof(char) * (len+1));
buf[len] = '\0';
if (!readBytes(buf, len)) {
free(buf);
@@ -357,6 +401,7 @@ int processDoubleValue(double** store) {
int loadPair(entry *e) {
uint32_t offset = CURR_OFFSET;
uint32_t i;
uint32_t length = 0;
/* read key first */
char *key;
@@ -367,7 +412,6 @@ int loadPair(entry *e) {
return 0;
}
uint32_t length = 0;
if (e->type == REDIS_LIST ||
e->type == REDIS_SET ||
e->type == REDIS_ZSET ||
@@ -547,8 +591,11 @@ void printErrorStack(entry *e) {
/* display error stack */
for (i = 0; i < errors.level; i++) {
printf("0x%08lx - %s\n",
(unsigned long) errors.offset[i], errors.error[i]);
#ifdef _WIN32
printf("0x%08llx - %s\n", (unsigned long long)errors.offset[i], errors.error[i]);
#else
printf("0x%08lx - %s\n", errors.offset[i], errors.error[i]);
#endif
}
}
@@ -563,6 +610,8 @@ void process() {
entry = loadEntry();
if (!entry.success) {
uint64_t offset;
int i;
printValid(num_valid_ops, num_valid_bytes);
printErrorStack(&entry);
num_errors++;
@@ -570,11 +619,11 @@ void process() {
num_valid_bytes = 0;
/* search for next valid entry */
uint64_t offset = positions[0].offset + 1;
int i = 0;
offset = positions[0].offset + 1;
i = 0;
while (!entry.success && offset < positions[0].size) {
positions[1].offset = offset;
positions[1].offset = (size_t)offset;
/* find 3 consecutive valid entries */
for (i = 0; i < 3; i++) {
@@ -592,7 +641,7 @@ void process() {
printSkipped(offset - positions[0].offset, offset);
}
positions[0].offset = offset;
positions[0].offset = (size_t)offset;
} else {
num_valid_ops++;
num_valid_bytes += positions[1].offset - positions[0].offset;
@@ -624,23 +673,36 @@ void process() {
if (num_errors) {
printf("\n");
printf("Total unprocessable opcodes: %llu\n",
(unsigned long long) num_errors);
(unsigned long long) num_errors);
}
}
#ifdef _WIN32
#pragma warning(disable: 4723)
#endif
int main(int argc, char **argv) {
int fd;
off size;
struct stat stat;
void *data;
/* expect the first argument to be the dump file */
if (argc <= 1) {
printf("Usage: %s <dump.rdb>\n", argv[0]);
exit(0);
}
int fd;
off_t size;
struct stat stat;
void *data;
#ifdef _WIN32
_fmode = _O_BINARY;
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
fd = open(argv[1], O_RDONLY|_O_BINARY);
#else
fd = open(argv[1], O_RDONLY);
#endif
if (fd < 1) {
ERROR("Cannot open file: %s\n", argv[1]);
}
+41 -5
View File
@@ -34,17 +34,33 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <assert.h>
#ifdef _WIN32
#include <fcntl.h>
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include <winsock2.h>
#include <windows.h>
#include "win32fixes.h"
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
#include "hiredis.h"
#include "linenoise.h"
#include "sds.h"
#include "zmalloc.h"
#include "linenoise.h"
#include "help.h"
#define REDIS_NOTUSED(V) ((void) V)
@@ -82,8 +98,8 @@ static long long mstime(void) {
long long mst;
gettimeofday(&tv, NULL);
mst = ((long)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
mst = (long long)((long)tv.tv_sec)*1000;
mst += (long long)(tv.tv_usec/1000);
return mst;
}
@@ -551,11 +567,11 @@ static int parseOptions(int argc, char **argv) {
config.hostsocket = argv[i+1];
i++;
} else if (!strcmp(argv[i],"-r") && !lastarg) {
config.repeat = strtoll(argv[i+1],NULL,10);
config.repeat = (long)strtoll(argv[i+1],NULL,10);
i++;
} else if (!strcmp(argv[i],"-i") && !lastarg) {
double seconds = atof(argv[i+1]);
config.interval = seconds*1000000;
config.interval = (long)(seconds*1000000);
i++;
} else if (!strcmp(argv[i],"-n") && !lastarg) {
config.dbnum = atoi(argv[i+1]);
@@ -661,10 +677,17 @@ static void repl() {
if (isatty(fileno(stdin))) {
history = 1;
#ifdef _WIN32
if (getenv("USERPROFILE") != NULL) {
historyfile = sdscatprintf(sdsempty(),"%s\\.rediscli_history",getenv("USERPROFILE"));
linenoiseHistoryLoad(historyfile);
}
#else
if (getenv("HOME") != NULL) {
historyfile = sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME"));
linenoiseHistoryLoad(historyfile);
}
#endif
}
cliRefreshPrompt();
@@ -793,6 +816,19 @@ int main(int argc, char **argv) {
config.mb_delim = sdsnew("\n");
cliInitHelp();
#ifdef _WIN32
_fmode = _O_BINARY;
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
if (!w32initWinSock()) {
printf("Winsock init error %d", WSAGetLastError());
exit(1);
};
atexit((void(*)(void)) WSACleanup);
#endif
firstarg = parseOptions(argc,argv);
argc -= firstarg;
argv += firstarg;
+148 -11
View File
@@ -38,22 +38,27 @@
#include <time.h>
#include <signal.h>
#ifdef _WIN32
#include <locale.h>
#define LOG_LOCAL0 0
#else
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <limits.h>
#include <float.h>
#include <math.h>
#include <pthread.h>
#include <sys/resource.h>
/* Our shared "common" objects */
@@ -123,8 +128,8 @@ struct redisCommand readonlyCommandTable[] = {
{"zrem",zremCommand,-3,0,NULL,1,1,1},
{"zremrangebyscore",zremrangebyscoreCommand,4,0,NULL,1,1,1},
{"zremrangebyrank",zremrangebyrankCommand,4,0,NULL,1,1,1},
{"zunionstore",zunionstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zinterstore",zinterstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zunionstore",zunionstoreCommand,-4,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"zinterstore",zinterstoreCommand,-4,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"zrange",zrangeCommand,-4,0,NULL,1,1,1},
{"zrangebyscore",zrangebyscoreCommand,-4,0,NULL,1,1,1},
{"zrevrangebyscore",zrevrangebyscoreCommand,-4,0,NULL,1,1,1},
@@ -170,7 +175,7 @@ struct redisCommand readonlyCommandTable[] = {
{"lastsave",lastsaveCommand,1,0,NULL,0,0,0},
{"type",typeCommand,2,0,NULL,1,1,1},
{"multi",multiCommand,1,0,NULL,0,0,0},
{"exec",execCommand,1,REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},
{"exec",execCommand,1,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"discard",discardCommand,1,0,NULL,0,0,0},
{"sync",syncCommand,1,0,NULL,0,0,0},
{"flushdb",flushdbCommand,1,0,NULL,0,0,0},
@@ -198,7 +203,9 @@ struct redisCommand readonlyCommandTable[] = {
/*============================ Utility functions ============================ */
void redisLog(int level, const char *fmt, ...) {
#ifndef _WIN32
const int syslogLevelMap[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING };
#endif
const char *c = ".-*#";
time_t now = time(NULL);
va_list ap;
@@ -221,7 +228,9 @@ void redisLog(int level, const char *fmt, ...) {
if (server.logfile) fclose(fp);
#ifndef _WIN32
if (server.syslog_enabled) syslog(syslogLevelMap[level], "%s", msg);
#endif
}
/* Redis generally does not try to recover from out of memory conditions
@@ -235,6 +244,17 @@ void oom(const char *msg) {
abort();
}
#ifdef _WIN32
/* Misc Windows house keeping */
void win32Cleanup(void) {
zmalloc_free_used_memory_mutex();
/* Clear winsocks */
WSACleanup();
}
#endif /* _WIN32 */
/*====================== Hash table type implementation ==================== */
/* This is an hash table type that uses the SDS dynamic strings libary as
@@ -516,7 +536,7 @@ void activeExpireCycle(void) {
}
void updateLRUClock(void) {
server.lruclock = (time(NULL)/REDIS_LRU_CLOCK_RESOLUTION) &
server.lruclock = ((unsigned long)time(NULL)/REDIS_LRU_CLOCK_RESOLUTION) &
REDIS_LRU_CLOCK_MAX;
}
@@ -583,10 +603,17 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
/* Show information about connected clients */
if (!(loops % 50)) {
#ifdef _WIN32
redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %llu bytes in use",
listLength(server.clients)-listLength(server.slaves),
listLength(server.slaves),
(unsigned long long)zmalloc_used_memory());
#else
redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use",
listLength(server.clients)-listLength(server.slaves),
listLength(server.slaves),
zmalloc_used_memory());
#endif
}
/* Close connections of timedout clients */
@@ -627,7 +654,13 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
sp->changes, sp->seconds);
rdbSaveBackground(server.dbfilename);
#ifdef _WIN32
/* On windows this will save in foreground and block */
/* Here we are allready saved, and we should return */
return 100;
#else
break;
#endif
}
}
@@ -669,9 +702,9 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
* main loop of the event driven library, that is, before to sleep
* for ready file descriptors. */
void beforeSleep(struct aeEventLoop *eventLoop) {
REDIS_NOTUSED(eventLoop);
listNode *ln;
redisClient *c;
REDIS_NOTUSED(eventLoop);
/* Try to process pending commands for clients that were just unblocked. */
while (listLength(server.unblocked_clients)) {
@@ -746,6 +779,9 @@ void createSharedObjects(void) {
}
}
#ifdef _WIN32
#pragma warning(disable: 4723)
#endif
void initServerConfig() {
server.port = REDIS_SERVERPORT;
server.bindaddr = NULL;
@@ -841,16 +877,43 @@ void initServerConfig() {
void initServer() {
int j;
#ifdef _WIN32
HMODULE lib;
#endif
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
setupSignalHandlers();
#ifndef _WIN32
if (server.syslog_enabled) {
openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,
server.syslog_facility);
}
#endif
#ifdef _WIN32
/* Force binary mode on all files */
_fmode = _O_BINARY;
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
/* Set C locale, forcing strtod() to work with dots */
setlocale(LC_ALL, "C");
/* MingGW 32 lacks declaration of RtlGenRandom, MinGw64 don't */
lib = LoadLibraryA("advapi32.dll");
RtlGenRandom = (RtlGenRandomFunc)GetProcAddress(lib, "SystemFunction036");
/* Winsocks must be initialized */
if (!w32initWinSock()) {
redisLog(REDIS_WARNING, "Can't init WinSock2; Error code: %d", WSAGetLastError());
exit(1);
};
/* ... and cleaned at application exit */
atexit((void(*)(void)) win32Cleanup);
#endif
server.mainthread = pthread_self();
server.clients = listCreate();
server.slaves = listCreate();
@@ -915,7 +978,11 @@ void initServer() {
acceptUnixHandler,NULL) == AE_ERR) oom("creating file event");
if (server.appendonly) {
#ifdef _WIN32
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT|_O_BINARY,0);
#else
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
#endif
if (server.appendfd == -1) {
redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
strerror(errno));
@@ -925,7 +992,7 @@ void initServer() {
slowlogInit();
bioInit();
srand(time(NULL)^getpid());
srand((unsigned int)(time(NULL)^getpid()));
}
/* Populates the Redis Command Table starting from the hard coded list
@@ -1202,6 +1269,15 @@ sds genRedisInfoString(void) {
"used_cpu_user_children:%.2f\r\n"
"connected_clients:%d\r\n"
"connected_slaves:%d\r\n"
#ifdef _WIN32
"client_longest_output_list:%llu\r\n"
"client_biggest_input_buf:%llu\r\n"
"blocked_clients:%d\r\n"
"used_memory:%llu\r\n"
"used_memory_human:%s\r\n"
"used_memory_rss:%llu\r\n"
"used_memory_peak:%llu\r\n"
#else
"client_longest_output_list:%lu\r\n"
"client_biggest_input_buf:%lu\r\n"
"blocked_clients:%d\r\n"
@@ -1209,6 +1285,7 @@ sds genRedisInfoString(void) {
"used_memory_human:%s\r\n"
"used_memory_rss:%zu\r\n"
"used_memory_peak:%zu\r\n"
#endif
"used_memory_peak_human:%s\r\n"
"mem_fragmentation_ratio:%.2f\r\n"
"mem_allocator:%s\r\n"
@@ -1227,11 +1304,16 @@ sds genRedisInfoString(void) {
"pubsub_channels:%ld\r\n"
"pubsub_patterns:%u\r\n"
"latest_fork_usec:%lld\r\n"
"vm_enabled:%d\r\n"
"role:%s\r\n"
,REDIS_VERSION,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,10) > 0,
#ifdef _WIN32
(sizeof(size_t) == 8) ? "64" : "32",
#else
(sizeof(long) == 8) ? "64" : "32",
#endif
aeGetApiName(),
#ifdef __GNUC__
__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__,
@@ -1239,6 +1321,44 @@ sds genRedisInfoString(void) {
0,0,0,
#endif
(long) getpid(),
#ifdef _WIN32
(long)uptime,
(long)(uptime/(3600*24)),
(unsigned long) server.lruclock,
(float)self_ru.ru_stime.tv_sec+(float)self_ru.ru_stime.tv_usec/1000000,
(float)self_ru.ru_utime.tv_sec+(float)self_ru.ru_utime.tv_usec/1000000,
(float)c_ru.ru_stime.tv_sec+(float)c_ru.ru_stime.tv_usec/1000000,
(float)c_ru.ru_utime.tv_sec+(float)c_ru.ru_utime.tv_usec/1000000,
listLength(server.clients)-listLength(server.slaves),
listLength(server.slaves),
(unsigned long long)lol,
(unsigned long long)bib,
server.bpop_blocked_clients,
(unsigned long long) zmalloc_used_memory(),
hmem,
(unsigned long long)zmalloc_get_rss(),
(unsigned long long)server.stat_peak_memory,
peak_hmem,
zmalloc_get_fragmentation_ratio(),
ZMALLOC_LIB,
server.loading,
server.appendonly,
(long long) server.dirty,
(int) (server.bgsavechildpid != -1),
(long)(time_t) server.lastsave,
(int) (server.bgrewritechildpid != -1),
(long long) server.stat_numconnections,
(long long) server.stat_numcommands,
(long long) server.stat_expiredkeys,
(long long) server.stat_evictedkeys,
(long long) server.stat_keyspace_hits,
(long long) server.stat_keyspace_misses,
(long) dictSize(server.pubsub_channels),
(unsigned int)listLength(server.pubsub_patterns),
(long long)server.stat_fork_time,
0,
server.masterhost == 0 ? "master" : "slave"
#else
uptime,
uptime/(3600*24),
(unsigned long) server.lruclock,
@@ -1272,7 +1392,9 @@ sds genRedisInfoString(void) {
dictSize(server.pubsub_channels),
listLength(server.pubsub_patterns),
server.stat_fork_time,
0,
server.masterhost == NULL ? "master" : "slave"
#endif
);
if (server.appendonly) {
@@ -1552,6 +1674,9 @@ void createPidFile(void) {
}
void daemonize(void) {
#ifdef _WIN32
redisLog(REDIS_WARNING,"Windows does not support daemonize. Start Redis as service");
#else
int fd;
if (fork() != 0) exit(0); /* parent exits */
@@ -1566,6 +1691,7 @@ void daemonize(void) {
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
#endif
}
void version() {
@@ -1583,6 +1709,12 @@ void usage() {
int main(int argc, char **argv) {
time_t start;
#ifdef _WIN32
/* using pthreads as statically linked library
requires initialization */
pthread_win32_process_attach_np();
#endif
initServerConfig();
if (argc == 2) {
if (strcmp(argv[1], "-v") == 0 ||
@@ -1622,6 +1754,11 @@ int main(int argc, char **argv) {
aeSetBeforeSleepProc(server.el,beforeSleep);
aeMain(server.el);
aeDeleteEventLoop(server.el);
#ifdef _WIN32
/* using pthreads as statically linked library
requires cleanup */
pthread_win32_process_detach_np();
#endif
return 0;
}
+15 -1
View File
@@ -13,11 +13,17 @@
#include <string.h>
#include <time.h>
#include <limits.h>
#ifndef _WIN32
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#endif
#include <errno.h>
#include <pthread.h>
#ifdef _WIN32
#include "win32fixes.h"
#else
#include <syslog.h>
#endif
#include "ae.h" /* Event driven programming library */
#include "sds.h" /* Dynamic safe strings */
@@ -301,6 +307,10 @@ typedef struct redisClient {
long bulklen; /* length of bulk argument in multi bulk request */
list *reply;
int sentlen;
#ifdef _WIN32
int sentobjlen;
robj *sentobj; /* keep track of last sent reply object */
#endif
time_t lastinteraction; /* time of the last interaction, used for timeout */
int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
int slaveseldb; /* slave selected db, if this client is a slave */
@@ -485,7 +495,11 @@ struct redisCommand {
struct redisFunctionSym {
char *name;
#ifdef _WIN32
size_t pointer;
#else
unsigned long pointer;
#endif
};
typedef struct _redisSortObject {
+7
View File
@@ -2,7 +2,14 @@
* small file is recompiled, as we access this information in all the other
* files using this functions. */
#ifdef _WIN32
/* For now hard code these version strings.
TODO: Modify build to write them to release.h from the environment */
#define REDIS_GIT_SHA1 "00000000"
#define REDIS_GIT_DIRTY "0"
#else
#include "release.h"
#endif
char *redisGitSHA1(void) {
return REDIS_GIT_SHA1;
+181
View File
@@ -1,9 +1,12 @@
#include "redis.h"
#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
/* ---------------------------------- MASTER -------------------------------- */
@@ -83,6 +86,36 @@ void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc)
decrRefCount(cmdobj);
}
#ifdef _WIN32
/* Win32 may fail in renaming file while it is being read for sending */
/* if some client is doing bulk transfer, try again when it completes */
int DelayBkgdSaveForReplication() {
listIter li;
int sending = 0;
listNode *ln;
listRewind(server.slaves,&li);
while((ln = listNext(&li))) {
redisClient *slave = ln->value;
if (slave->repldbfd != -1) {
sending++;
}
}
if (sending > 0) {
listRewind(server.slaves,&li);
while((ln = listNext(&li))) {
redisClient *slave = ln->value;
if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
slave->replstate = REDIS_REPL_WAIT_BGSAVE_START;
}
}
redisLog(REDIS_VERBOSE,"Delay starting bgsave for replication");
return 1;
}
return 0;
}
#endif
void syncCommand(redisClient *c) {
/* ignore SYNC if aleady slave or in monitor mode */
if (c->flags & REDIS_SLAVE) return;
@@ -132,6 +165,11 @@ void syncCommand(redisClient *c) {
redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
}
} else {
#ifdef _WIN32
if (DelayBkgdSaveForReplication() > 0) {
c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
} else {
#endif
/* Ok we don't have a BGSAVE in progress, let's start one */
redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
@@ -140,14 +178,101 @@ void syncCommand(redisClient *c) {
return;
}
c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
#ifdef _WIN32
}
#endif
}
c->repldbfd = -1;
c->flags |= REDIS_SLAVE;
c->slaveseldb = 0;
listAddNodeTail(server.slaves,c);
#ifdef _WIN32
/* Since WIN32 won't fork(), but instead do Save() we must manualy call this */
updateSlavesWaitingBgsave(REDIS_OK);
#endif
return;
}
#ifdef _WIN32
void sendBulkToSlaveLenDone(aeEventLoop *el, int fd, void *privdata, int written) {
aeWinSendReq *req = (aeWinSendReq *)privdata;
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
sdsfree((sds)req->buf);
}
void sendBulkToSlaveDataDone(aeEventLoop *el, int fd, void *privdata, int nwritten) {
aeWinSendReq *req = (aeWinSendReq *)privdata;
redisClient *slave = (redisClient *)req->client;
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
zfree(req->data);
slave->repldboff += nwritten;
if (slave->repldboff == slave->repldbsize) {
close(slave->repldbfd);
slave->repldbfd = -1;
aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
slave->replstate = REDIS_REPL_ONLINE;
if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
sendReplyToClient, slave) == AE_ERR) {
freeClient(slave);
return;
}
addReplySds(slave,sdsempty());
redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
/* we have have delayed other clients. */
updateSlavesWaitingBgsave(REDIS_OK);
}
}
void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
redisClient *slave = privdata;
char *buf;
ssize_t result, buflen;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
if (slave->repldboff == 0) {
/* Write the bulk write count before to transfer the DB. In theory here
* we don't know how much room there is in the output buffer of the
* socket, but in pratice SO_SNDLOWAT (the minimum count for output
* operations) will never be smaller than the few bytes we need. */
sds bulkcount;
bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
slave->repldbsize);
result = aeWinSocketSend(fd,bulkcount,(int)sdslen(bulkcount),0,
el, slave, bulkcount, sendBulkToSlaveLenDone);
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
sdsfree(bulkcount);
freeClient(slave);
return;
}
}
lseek64(slave->repldbfd,slave->repldboff,SEEK_SET);
buf = (char *)zmalloc(REDIS_IOBUF_LEN);
buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
if (buflen <= 0) {
redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
(buflen == 0) ? "premature EOF" : strerror(errno));
freeClient(slave);
return;
}
result = aeWinSocketSend((SOCKET)fd,buf,(int)buflen,0,
el, slave, buf, sendBulkToSlaveDataDone);
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
strerror(errno));
freeClient(slave);
return;
}
}
#else
void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
redisClient *slave = privdata;
REDIS_NOTUSED(el);
@@ -201,6 +326,7 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
}
}
#endif
/* This function is called at the end of every backgrond saving.
* The argument bgsaveerr is REDIS_OK if the background saving succeeded
@@ -228,7 +354,11 @@ void updateSlavesWaitingBgsave(int bgsaveerr) {
redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
continue;
}
#ifdef _WIN32
if ((slave->repldbfd = open(server.dbfilename,O_RDONLY|_O_BINARY)) == -1 ||
#else
if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
#endif
redis_fstat(slave->repldbfd,&buf) == -1) {
freeClient(slave);
redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
@@ -245,6 +375,11 @@ void updateSlavesWaitingBgsave(int bgsaveerr) {
}
}
if (startbgsave) {
#ifdef _WIN32
if (DelayBkgdSaveForReplication() > 0) {
return;
}
#endif
if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
listIter li;
@@ -267,7 +402,12 @@ void replicationAbortSyncTransfer(void) {
redisAssert(server.replstate == REDIS_REPL_TRANSFER);
aeDeleteFileEvent(server.el,server.repl_transfer_s,AE_READABLE);
#ifdef _WIN32
aeWinSocketDetach(server.repl_transfer_s, 1);
closesocket(server.repl_transfer_s);
#else
close(server.repl_transfer_s);
#endif
close(server.repl_transfer_fd);
unlink(server.repl_transfer_tmpfile);
zfree(server.repl_transfer_tmpfile);
@@ -292,6 +432,9 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
goto error;
}
#ifdef _WIN32
aeWinReceiveDone(fd);
#endif
if (buf[0] == '-') {
redisLog(REDIS_WARNING,
"MASTER aborted replication with an error: %s",
@@ -317,6 +460,20 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
/* Read bulk data */
readlen = (server.repl_transfer_left < (signed)sizeof(buf)) ?
server.repl_transfer_left : (signed)sizeof(buf);
#ifdef _WIN32
nread = recv((SOCKET)fd,buf,readlen,0);
if (nread <= 0) {
if (server.repl_transfer_left) {
errno = WSAGetLastError();
redisLog(REDIS_WARNING,"I/O error %d (left %d) trying to sync with MASTER: %s",
errno, server.repl_transfer_left,
(nread == -1) ? strerror(errno) : "connection lost");
}
replicationAbortSyncTransfer();
return;
}
aeWinReceiveDone(fd);
#else
nread = read(fd,buf,readlen);
if (nread <= 0) {
redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
@@ -324,6 +481,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
replicationAbortSyncTransfer();
return;
}
#endif
server.repl_transfer_lastio = time(NULL);
if (write(server.repl_transfer_fd,buf,nread) != nread) {
redisLog(REDIS_WARNING,"Write error or short write writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
@@ -332,6 +490,10 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
server.repl_transfer_left -= nread;
/* Check if the transfer is now complete */
if (server.repl_transfer_left == 0) {
#ifdef _WIN32
/* Close temp, since rename is unable to delete open file */
close(server.repl_transfer_fd);
#endif
if (rename(server.repl_transfer_tmpfile,server.dbfilename) == -1) {
redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
replicationAbortSyncTransfer();
@@ -351,7 +513,10 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
}
/* Final setup of the connected slave <- master link */
zfree(server.repl_transfer_tmpfile);
#ifndef _WIN32
/* Moved before rename tmp->db in windows */
close(server.repl_transfer_fd);
#endif
server.master = createClient(server.repl_transfer_s);
server.master->flags |= REDIS_MASTER;
server.master->authenticated = 1;
@@ -420,9 +585,15 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
/* Prepare a suitable temp file for bulk transfer */
while(maxtries--) {
#ifdef _WIN32
snprintf(tmpfile,256,
"temp-%lld.%lld.rdb",(long long)time(NULL),(long long)getpid());
dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,_S_IREAD|_S_IWRITE);
#else
snprintf(tmpfile,256,
"temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
#endif
if (dfd != -1) break;
sleep(1);
}
@@ -448,7 +619,12 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
error:
server.replstate = REDIS_REPL_CONNECT;
#ifdef _WIN32
aeWinSocketDetach(fd, 1);
closesocket(fd);
#else
close(fd);
#endif
return;
}
@@ -483,7 +659,12 @@ void undoConnectWithMaster(void) {
redisAssert(server.replstate == REDIS_REPL_CONNECTING);
aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
#ifdef _WIN32
aeWinSocketDetach(fd, 1);
closesocket(fd);
#else
close(fd);
#endif
server.repl_transfer_s = -1;
server.replstate = REDIS_REPL_CONNECT;
}
+20 -17
View File
@@ -42,6 +42,9 @@
#include <ctype.h>
#include "sds.h"
#include "zmalloc.h"
#ifdef _WIN32
#include "win32fixes.h"
#endif
static void sdsOomAbort(void) {
fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
@@ -57,7 +60,7 @@ sds sdsnewlen(const void *init, size_t initlen) {
#else
if (sh == NULL) return NULL;
#endif
sh->len = initlen;
sh->len = (int)initlen;
sh->free = 0;
if (initlen) {
if (init) memcpy(sh->buf, init, initlen);
@@ -87,7 +90,7 @@ void sdsfree(sds s) {
void sdsupdatelen(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
int reallen = strlen(s);
int reallen = (int)strlen(s);
sh->free += (sh->len-reallen);
sh->len = reallen;
}
@@ -115,7 +118,7 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
if (newsh == NULL) return NULL;
#endif
newsh->free = newlen - len;
newsh->free = (int)(newlen - len);
return newsh->buf;
}
@@ -146,8 +149,8 @@ sds sdscatlen(sds s, void *t, size_t len) {
if (s == NULL) return NULL;
sh = (void*) (s-(sizeof(struct sdshdr)));
memcpy(s+curlen, t, len);
sh->len = curlen+len;
sh->free = sh->free-len;
sh->len = (int)(curlen+len);
sh->free = (int)(sh->free-len);
s[curlen+len] = '\0';
return s;
}
@@ -172,8 +175,8 @@ sds sdscpylen(sds s, char *t, size_t len) {
}
memcpy(s, t, len);
s[len] = '\0';
sh->len = len;
sh->free = totlen-len;
sh->len = (int)len;
sh->free = (int)(totlen-len);
return s;
}
@@ -229,8 +232,8 @@ sds sdstrim(sds s, const char *cset) {
len = (sp > ep) ? 0 : ((ep-sp)+1);
if (sh->buf != sp) memmove(sh->buf, sp, len);
sh->buf[len] = '\0';
sh->free = sh->free+(sh->len-len);
sh->len = len;
sh->free = sh->free+(int)(sh->len-len);
sh->len = (int)len;
return s;
}
@@ -240,11 +243,11 @@ sds sdsrange(sds s, int start, int end) {
if (len == 0) return s;
if (start < 0) {
start = len+start;
start = (int)len+start;
if (start < 0) start = 0;
}
if (end < 0) {
end = len+end;
end = (int)len+end;
if (end < 0) end = 0;
}
newlen = (start > end) ? 0 : (end-start)+1;
@@ -252,7 +255,7 @@ sds sdsrange(sds s, int start, int end) {
if (start >= (signed)len) {
newlen = 0;
} else if (end >= (signed)len) {
end = len-1;
end = (int)len-1;
newlen = (start > end) ? 0 : (end-start)+1;
}
} else {
@@ -260,19 +263,19 @@ sds sdsrange(sds s, int start, int end) {
}
if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
sh->buf[newlen] = 0;
sh->free = sh->free+(sh->len-newlen);
sh->len = newlen;
sh->free = (int)(sh->free+(sh->len-newlen));
sh->len = (int)newlen;
return s;
}
void sdstolower(sds s) {
int len = sdslen(s), j;
int len = (int)sdslen(s), j;
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
}
void sdstoupper(sds s) {
int len = sdslen(s), j;
int len = (int)sdslen(s), j;
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
}
@@ -285,7 +288,7 @@ int sdscmp(sds s1, sds s2) {
l2 = sdslen(s2);
minlen = (l1 < l2) ? l1 : l2;
cmp = memcmp(s1,s2,minlen);
if (cmp == 0) return l1-l2;
if (cmp == 0) return (int)(l1-l2);
return cmp;
}
+4
View File
@@ -34,6 +34,10 @@
#include <sys/types.h>
#include <stdarg.h>
#ifdef _WIN32
#define inline __inline
#endif
typedef char *sds;
struct sdshdr {
+7
View File
@@ -27,6 +27,9 @@ A million repetitions of "a"
#if defined(__sun)
#include "solarisfixes.h"
#endif
#ifdef _WIN32
#include "win32fixes.h"
#endif
#include "sha1.h"
#ifndef BYTE_ORDER
@@ -88,8 +91,12 @@ A million repetitions of "a"
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#ifdef _WIN32
#pragma error "Endianness not defined!"
#else
#error "Endianness not defined!"
#endif
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
+7 -7
View File
@@ -47,7 +47,7 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
/* Find out if we're dealing with a hash dereference. */
if ((f = strstr(p+1, "->")) != NULL) {
fieldlen = sdslen(spat)-(f-spat);
fieldlen = (int)(sdslen(spat)-(f-spat));
/* this also copies \0 character */
memcpy(fieldname.buf,f+2,fieldlen-1);
fieldname.len = fieldlen-2;
@@ -55,9 +55,9 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
fieldlen = 0;
}
prefixlen = p-spat;
sublen = sdslen(ssub);
postfixlen = sdslen(spat)-(prefixlen+1)-fieldlen;
prefixlen = (int)(p-spat);
sublen = (int)sdslen(ssub);
postfixlen = (int)(sdslen(spat)-(prefixlen+1)-fieldlen);
memcpy(keyname.buf,spat,prefixlen);
memcpy(keyname.buf+prefixlen,ssub,sublen);
memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
@@ -204,9 +204,9 @@ void sortCommand(redisClient *c) {
/* Load the sorting vector with all the objects to sort */
switch(sortval->type) {
case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
case REDIS_SET: vectorlen = setTypeSize(sortval); break;
case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
case REDIS_LIST: vectorlen = (int)listTypeLength(sortval); break;
case REDIS_SET: vectorlen = (int)setTypeSize(sortval); break;
case REDIS_ZSET: vectorlen = (int)dictSize(((zset*)sortval->ptr)->dict); break;
default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */
}
vector = zmalloc(sizeof(redisSortObject)*vectorlen);
+8 -1
View File
@@ -45,7 +45,11 @@ int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
timeout++;
while(size) {
if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
#ifdef _WIN32
nwritten = send((SOCKET)fd,ptr,size,0);
#else
nwritten = write(fd,ptr,size);
#endif
if (nwritten == -1) return -1;
ptr += nwritten;
size -= nwritten;
@@ -65,7 +69,11 @@ int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
timeout++;
while(size) {
if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
#ifdef _WIN32
nread = recv((SOCKET)fd,ptr,size,0);
#else
nread = read(fd,ptr,size);
#endif
if (nread <= 0) return -1;
ptr += nread;
size -= nread;
@@ -151,4 +159,3 @@ int fwriteBulkObject(FILE *fp, robj *obj) {
}
}
+5 -5
View File
@@ -49,7 +49,7 @@ int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v,
int found;
key = getDecodedObject(key);
found = zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),v,vlen);
found = zipmapGet(o->ptr,key->ptr,(unsigned int)sdslen(key->ptr),v,vlen);
decrRefCount(key);
if (!found) return -1;
} else {
@@ -88,7 +88,7 @@ robj *hashTypeGetObject(robj *o, robj *key) {
int hashTypeExists(robj *o, robj *key) {
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
key = getDecodedObject(key);
if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
if (zipmapExists(o->ptr,key->ptr,(unsigned int)sdslen(key->ptr))) {
decrRefCount(key);
return 1;
}
@@ -109,8 +109,8 @@ int hashTypeSet(robj *o, robj *key, robj *value) {
key = getDecodedObject(key);
value = getDecodedObject(value);
o->ptr = zipmapSet(o->ptr,
key->ptr,sdslen(key->ptr),
value->ptr,sdslen(value->ptr), &update);
key->ptr,(unsigned int)sdslen(key->ptr),
value->ptr,(unsigned int)sdslen(value->ptr), &update);
decrRefCount(key);
decrRefCount(value);
@@ -136,7 +136,7 @@ int hashTypeDelete(robj *o, robj *key) {
int deleted = 0;
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
key = getDecodedObject(key);
o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
o->ptr = zipmapDel(o->ptr,key->ptr,(unsigned int)sdslen(key->ptr), &deleted);
decrRefCount(key);
} else {
deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
+22 -16
View File
@@ -24,7 +24,7 @@ void listTypePush(robj *subject, robj *value, int where) {
if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
int pos = (where == REDIS_HEAD) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
value = getDecodedObject(value);
subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),pos);
subject->ptr = ziplistPush(subject->ptr,value->ptr,(unsigned int)sdslen(value->ptr),pos);
decrRefCount(value);
} else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) {
if (where == REDIS_HEAD) {
@@ -174,12 +174,12 @@ void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
/* When we insert after the current element, but the current element
* is the tail of the list, we need to do a push. */
if (next == NULL) {
subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),REDIS_TAIL);
subject->ptr = ziplistPush(subject->ptr,value->ptr,(unsigned int)sdslen(value->ptr),REDIS_TAIL);
} else {
subject->ptr = ziplistInsert(subject->ptr,next,value->ptr,sdslen(value->ptr));
subject->ptr = ziplistInsert(subject->ptr,next,value->ptr,(unsigned int)sdslen(value->ptr));
}
} else {
subject->ptr = ziplistInsert(subject->ptr,entry->zi,value->ptr,sdslen(value->ptr));
subject->ptr = ziplistInsert(subject->ptr,entry->zi,value->ptr,(unsigned int)sdslen(value->ptr));
}
decrRefCount(value);
} else if (entry->li->encoding == REDIS_ENCODING_LINKEDLIST) {
@@ -199,7 +199,7 @@ int listTypeEqual(listTypeEntry *entry, robj *o) {
listTypeIterator *li = entry->li;
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
redisAssert(o->encoding == REDIS_ENCODING_RAW);
return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
return ziplistCompare(entry->zi,o->ptr,(unsigned int)sdslen(o->ptr));
} else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
return equalStringObjects(o,listNodeValue(entry->ln));
} else {
@@ -379,10 +379,11 @@ void llenCommand(redisClient *c) {
}
void lindexCommand(redisClient *c) {
int index;
robj *value = NULL;
robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk);
if (o == NULL || checkType(c,o,REDIS_LIST)) return;
int index = atoi(c->argv[2]->ptr);
robj *value = NULL;
index = atoi(c->argv[2]->ptr);
if (o->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *p;
@@ -415,10 +416,12 @@ void lindexCommand(redisClient *c) {
}
void lsetCommand(redisClient *c) {
int index;
robj *value;
robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr);
if (o == NULL || checkType(c,o,REDIS_LIST)) return;
int index = atoi(c->argv[2]->ptr);
robj *value = (c->argv[3] = tryObjectEncoding(c->argv[3]));
index = atoi(c->argv[2]->ptr);
value = (c->argv[3] = tryObjectEncoding(c->argv[3]));
listTypeTryConversion(o,value);
if (o->encoding == REDIS_ENCODING_ZIPLIST) {
@@ -429,7 +432,7 @@ void lsetCommand(redisClient *c) {
} else {
o->ptr = ziplistDelete(o->ptr,&p);
value = getDecodedObject(value);
o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr));
o->ptr = ziplistInsert(o->ptr,p,value->ptr,(unsigned int)sdslen(value->ptr));
decrRefCount(value);
addReply(c,shared.ok);
signalModifiedKey(c->db,c->argv[1]);
@@ -453,10 +456,11 @@ void lsetCommand(redisClient *c) {
}
void popGenericCommand(redisClient *c, int where) {
robj *value;
robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk);
if (o == NULL || checkType(c,o,REDIS_LIST)) return;
robj *value = listTypePop(o,where);
value = listTypePop(o,where);
if (value == NULL) {
addReply(c,shared.nullbulk);
} else {
@@ -590,10 +594,12 @@ void ltrimCommand(redisClient *c) {
void lremCommand(redisClient *c) {
robj *subject, *obj;
obj = c->argv[3] = tryObjectEncoding(c->argv[3]);
int toremove = atoi(c->argv[2]->ptr);
int removed = 0;
listTypeEntry entry;
int toremove;
listTypeIterator *li;
obj = c->argv[3] = tryObjectEncoding(c->argv[3]);
toremove = atoi(c->argv[2]->ptr);
subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero);
if (subject == NULL || checkType(c,subject,REDIS_LIST)) return;
@@ -602,7 +608,6 @@ void lremCommand(redisClient *c) {
if (subject->encoding == REDIS_ENCODING_ZIPLIST)
obj = getDecodedObject(obj);
listTypeIterator *li;
if (toremove < 0) {
toremove = -toremove;
li = listTypeInitIterator(subject,-1,REDIS_HEAD);
@@ -891,7 +896,7 @@ int getTimeoutFromObjectOrReply(redisClient *c, robj *object, time_t *timeout) {
return REDIS_ERR;
}
if (tval > 0) tval += time(NULL);
if (tval > 0) tval += (long)time(NULL);
*timeout = tval;
return REDIS_OK;
@@ -971,11 +976,12 @@ void brpopCommand(redisClient *c) {
void brpoplpushCommand(redisClient *c) {
time_t timeout;
robj *key;
if (getTimeoutFromObjectOrReply(c,c->argv[3],&timeout) != REDIS_OK)
return;
robj *key = lookupKeyWrite(c->db, c->argv[1]);
key = lookupKeyWrite(c->db, c->argv[1]);
if (key == NULL) {
if (c->flags & REDIS_MULTI) {
+1 -1
View File
@@ -377,7 +377,7 @@ void srandmemberCommand(redisClient *c) {
}
int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
return setTypeSize(*(robj**)s1)-setTypeSize(*(robj**)s2);
return (int)(setTypeSize(*(robj**)s1)-setTypeSize(*(robj**)s2));
}
void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, robj *dstkey) {
+21 -18
View File
@@ -1,6 +1,9 @@
#include "redis.h"
#include <math.h>
#ifdef _WIN32
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
#endif
/*-----------------------------------------------------------------------------
* Sorted set API
@@ -423,7 +426,7 @@ double zzlGetScore(unsigned char *sptr) {
buf[vlen] = '\0';
score = strtod(buf,NULL);
} else {
score = vlong;
score = (double)vlong;
}
return score;
@@ -457,39 +460,39 @@ unsigned int zzlLength(unsigned char *zl) {
/* Move to next entry based on the values in eptr and sptr. Both are set to
* NULL when there is no next entry. */
void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
unsigned char *_eptr, *_sptr;
unsigned char *l_eptr, *l_sptr;
redisAssert(*eptr != NULL && *sptr != NULL);
_eptr = ziplistNext(zl,*sptr);
if (_eptr != NULL) {
_sptr = ziplistNext(zl,_eptr);
redisAssert(_sptr != NULL);
l_eptr = ziplistNext(zl,*sptr);
if (l_eptr != NULL) {
l_sptr = ziplistNext(zl,l_eptr);
redisAssert(l_sptr != NULL);
} else {
/* No next entry. */
_sptr = NULL;
l_sptr = NULL;
}
*eptr = _eptr;
*sptr = _sptr;
*eptr = l_eptr;
*sptr = l_sptr;
}
/* Move to the previous entry based on the values in eptr and sptr. Both are
* set to NULL when there is no next entry. */
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
unsigned char *_eptr, *_sptr;
unsigned char *l_eptr, *l_sptr;
redisAssert(*eptr != NULL && *sptr != NULL);
_sptr = ziplistPrev(zl,*eptr);
if (_sptr != NULL) {
_eptr = ziplistPrev(zl,_sptr);
redisAssert(_eptr != NULL);
l_sptr = ziplistPrev(zl,*eptr);
if (l_sptr != NULL) {
l_eptr = ziplistPrev(zl,l_sptr);
redisAssert(l_eptr != NULL);
} else {
/* No previous entry. */
_eptr = NULL;
l_eptr = NULL;
}
*eptr = _eptr;
*sptr = _sptr;
*eptr = l_eptr;
*sptr = l_sptr;
}
/* Returns if there is a part of the zset is in range. Should only be used
@@ -1937,7 +1940,7 @@ void genericZrangebyscoreCommand(redisClient *c, int reverse, int justcount) {
}
if (justcount) {
addReplyLongLong(c,(long)rangelen);
addReplyLongLong(c,(long long)rangelen);
} else {
if (withscores) rangelen *= 2;
setDeferredMultiBulkLength(c,replylen,rangelen);
+24 -4
View File
@@ -5,7 +5,11 @@
#include <ctype.h>
#include <limits.h>
#include <math.h>
#ifndef _WIN32
#include <sys/time.h>
#else
#include "win32fixes.h"
#endif
#include "util.h"
@@ -133,7 +137,7 @@ int stringmatchlen(const char *pattern, int patternLen,
}
int stringmatch(const char *pattern, const char *string, int nocase) {
return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
return stringmatchlen(pattern,(int)strlen(pattern),string,(int)strlen(string),nocase);
}
/* Convert a string representing an amount of memory into the number of
@@ -172,7 +176,7 @@ long long memtoll(const char *p, int *err) {
if (err) *err = 1;
mul = 1;
}
digits = u-p;
digits = (unsigned int)(u-p);
if (digits >= sizeof(buf)) {
if (err) *err = 1;
return LLONG_MAX;
@@ -190,21 +194,37 @@ int ll2string(char *s, size_t len, long long value) {
char buf[32], *p;
unsigned long long v;
size_t l;
#ifdef _WIN32
/* if value fits, use 32 bit div for performance */
unsigned long vl;
#endif
if (len == 0) return 0;
v = (value < 0) ? -value : value;
p = buf+31; /* point to the last character */
#ifdef _WIN32
vl = (unsigned long)v;
if ((unsigned long long)vl == v) {
do {
*p-- = '0'+(vl%10);
vl /= 10;
} while(vl);
} else {
#endif
do {
*p-- = '0'+(v%10);
v /= 10;
} while(v);
#ifdef _WIN32
}
#endif
if (value < 0) *p-- = '-';
p++;
l = 32-(p-buf);
if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
memcpy(s,p,l);
s[l] = '\0';
return l;
return (int)l;
}
/* Convert a string into a long long. Returns 1 if the string could be parsed
@@ -318,7 +338,7 @@ int d2string(char *buf, size_t len, double value) {
* integer printing function that is much faster. */
double min = -4503599627370495; /* (2^52)-1 */
double max = 4503599627370496; /* -(2^52) */
if (val > min && val < max && value == ((double)((long long)value)))
if (value > min && value < max && value == ((double)((long long)value)))
len = ll2string(buf,len,(long long)value);
else
#endif
+372
View File
@@ -0,0 +1,372 @@
/* Copyright (c) 2012, Microsoft Corporation
* 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 "ae.h"
#include "win32fixes.h"
#include "zmalloc.h"
#include <mswsock.h>
#include <Guiddef.h>
#include "win32_wsiocp.h"
static void *iocpState;
static HANDLE iocph;
static fnGetSockState * aeGetSockState;
static LPFN_ACCEPTEX acceptex;
static LPFN_GETACCEPTEXSOCKADDRS getaddrs;
#define SUCCEEDED_WITH_IOCP(result) \
((result) || (GetLastError() == ERROR_IO_PENDING))
/* for zero length reads use shared buf */
static DWORD wsarecvflags;
static char zreadchar[1];
/* queue an accept with a new socket */
int aeWinQueueAccept(SOCKET listensock) {
aeSockState *sockstate;
aeSockState *accsockstate;
DWORD result, bytes;
SOCKET acceptsock;
aacceptreq * areq;
if ((sockstate = aeGetSockState(iocpState, listensock)) == NULL) {
errno = WSAEINVAL;
return -1;
}
acceptsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (acceptsock == INVALID_SOCKET) {
errno = WSAEINVAL;
return -1;
}
accsockstate = aeGetSockState(iocpState, acceptsock);
if (accsockstate == NULL) {
errno = WSAEINVAL;
return -1;
}
accsockstate->masks = SOCKET_ATTACHED;
/* keep accept socket in buf len until accepted */
areq = (aacceptreq *)zmalloc(sizeof(aacceptreq));
memset(areq, 0, sizeof(aacceptreq));
areq->buf = (char *)zmalloc(sizeof(struct sockaddr_storage) * 2 + 64);
areq->accept = acceptsock;
areq->next = NULL;
result = acceptex(listensock, acceptsock,
areq->buf, 0,
sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage),
&bytes, &areq->ov);
if (SUCCEEDED_WITH_IOCP(result)){
sockstate->masks |= ACCEPT_PENDING;
} else {
errno = WSAGetLastError();
sockstate->masks &= ~ACCEPT_PENDING;
closesocket(acceptsock);
accsockstate->masks = 0;
zfree(areq);
return -1;
}
return TRUE;
}
/* listen using extension function to get faster accepts */
int aeWinListen(SOCKET sock, int backlog) {
aeSockState *sockstate;
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
const GUID wsaid_acceptexaddrs = WSAID_GETACCEPTEXSOCKADDRS;
DWORD result, bytes;
if ((sockstate = aeGetSockState(iocpState, sock)) == NULL) {
errno = WSAEINVAL;
return SOCKET_ERROR;
}
aeWinSocketAttach(sock);
sockstate->masks |= LISTEN_SOCK;
result = WSAIoctl(sock,
SIO_GET_EXTENSION_FUNCTION_POINTER,
(void *)&wsaid_acceptex,
sizeof(GUID),
&acceptex,
sizeof(LPFN_ACCEPTEX),
&bytes,
NULL,
NULL);
if (result == SOCKET_ERROR) {
acceptex = NULL;
return SOCKET_ERROR;
}
result = WSAIoctl(sock,
SIO_GET_EXTENSION_FUNCTION_POINTER,
(void *)&wsaid_acceptexaddrs,
sizeof(GUID),
&getaddrs,
sizeof(LPFN_GETACCEPTEXSOCKADDRS),
&bytes,
NULL,
NULL);
if (result == SOCKET_ERROR) {
getaddrs = NULL;
return SOCKET_ERROR;
}
if (listen(sock, backlog) == 0) {
if (aeWinQueueAccept(sock) == -1) {
return SOCKET_ERROR;
}
}
return 0;
}
/* return the queued accept socket */
int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len) {
aeSockState *sockstate;
int acceptsock;
int result;
SOCKADDR *plocalsa;
SOCKADDR *premotesa;
int locallen, remotelen;
aacceptreq * areq;
if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) {
errno = WSAEINVAL;
return SOCKET_ERROR;
}
areq = sockstate->reqs;
if (areq == NULL) {
errno = WSAEINVAL;
return -1;
}
sockstate->reqs = areq->next;
acceptsock = areq->accept;
result = setsockopt(acceptsock,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&fd,
sizeof(fd));
locallen = *len;
getaddrs(areq->buf,
0,
sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage),
&plocalsa, &locallen,
&premotesa, &remotelen);
locallen = remotelen < *len ? remotelen : *len;
memcpy(sa, premotesa, locallen);
*len = locallen;
aeWinSocketAttach(acceptsock);
zfree(areq);
/* queue another accept */
if (aeWinQueueAccept(fd) == -1) {
return -1;
}
return acceptsock;
}
/* after doing read caller needs to call done
* so that we can continue to check for read events.
* This is not necessary if caller will delete read events */
int aeWinReceiveDone(int fd) {
aeSockState *sockstate;
int result;
WSABUF zreadbuf;
if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) {
errno = WSAEINVAL;
return -1;
}
if ((sockstate->masks & SOCKET_ATTACHED) == 0) {
return 0;
}
/* use zero length read with overlapped to get notification
of when data is available */
memset(&sockstate->ov_read, 0, sizeof(sockstate->ov_read));
zreadbuf.buf = zreadchar;
zreadbuf.len = 0;
result = WSARecv((SOCKET)fd,
&zreadbuf,
1,
NULL,
&wsarecvflags,
&sockstate->ov_read,
NULL);
if (SUCCEEDED_WITH_IOCP(result == 0)){
sockstate->masks |= READ_QUEUED;
} else {
errno = WSAGetLastError();
sockstate->masks &= ~READ_QUEUED;
return -1;
}
return 0;
}
/* wrapper for send
* enables use of WSA Send to get IOCP notification of completion.
* returns -1 with errno = WSA_IO_PENDING if callback will be invoked later */
int aeWinSocketSend(int fd, char *buf, int len, int flags,
void *eventLoop, void *client, void *data, void *proc) {
aeSockState *sockstate;
int result;
asendreq *areq;
sockstate = aeGetSockState(iocpState, fd);
/* if not an async socket, do normal send */
if (sockstate == NULL ||
(sockstate->masks & SOCKET_ATTACHED) == 0 ||
proc == NULL) {
result = send((SOCKET)fd, buf, len, flags);
if (result == SOCKET_ERROR) {
errno = WSAGetLastError();
}
return result;
}
/* use overlapped structure to send using IOCP */
areq = (asendreq *)zmalloc(sizeof(asendreq));
memset(areq, 0, sizeof(asendreq));
areq->wbuf.len = len;
areq->wbuf.buf = buf;
areq->eventLoop = (aeEventLoop *)eventLoop;
areq->req.client = client;
areq->req.data = data;
areq->req.len = len;
areq->req.buf = buf;
areq->proc = (aeFileProc *)proc;
result = WSASend((SOCKET)fd,
&areq->wbuf,
1,
NULL,
flags,
&areq->ov,
NULL);
if (SUCCEEDED_WITH_IOCP(result == 0)){
sockstate->masks |= WRITE_ACTIVE;
errno = WSA_IO_PENDING;
sockstate->wreqs++;
} else {
errno = WSAGetLastError();
sockstate->masks &= ~WRITE_ACTIVE;
zfree(areq);
}
return SOCKET_ERROR;
}
/* for each asynch socket, need to associate completion port */
int aeWinSocketAttach(int fd) {
DWORD yes = 1;
aeSockState *sockstate;
if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) {
errno = WSAEINVAL;
return -1;
}
/* Set the socket to nonblocking mode */
if (ioctlsocket((SOCKET)fd, FIONBIO, &yes) == SOCKET_ERROR) {
errno = WSAGetLastError();
return -1;
}
/* Make the socket non-inheritable */
if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) {
errno = WSAGetLastError();
return -1;
}
/* Associate it with the I/O completion port. */
/* Use socket as completion key. */
if (CreateIoCompletionPort((HANDLE)fd,
iocph,
(ULONG_PTR)fd,
0) == NULL) {
errno = WSAGetLastError();
return -1;
}
sockstate->masks = SOCKET_ATTACHED;
sockstate->wreqs = 0;
return 0;
}
/* when closing socket, need to unassociate completion port */
int aeWinSocketDetach(int fd, int shutd) {
aeSockState *sockstate;
char rbuf[100];
if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) {
errno = WSAEINVAL;
return -1;
}
if (shutd == 1) {
if (shutdown(fd, SD_SEND) != SOCKET_ERROR) {
while (1) {
int rc = recv(fd, rbuf, 100, 0);
if (rc == 0 || rc == SOCKET_ERROR) break;
}
} else {
int err = WSAGetLastError();
}
}
sockstate->masks = 0;
return 0;
}
void aeWinInit(void *state, HANDLE iocp, fnGetSockState *getSockState) {
iocpState = state;
iocph = iocp;
aeGetSockState = getSockState;
}
void aeWinCleanup() {
iocpState = NULL;
}
+74
View File
@@ -0,0 +1,74 @@
/* Copyright (c) 2012, Microsoft Corporation
* 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 WIN32WSIOCP_H
#define WIN32WSIOCP_H
#ifdef _WIN32
/* structs and functions for using IOCP with windows sockets */
/* structure used for async write requests.
* contains overlapped, WSABuf, and callback info
* NOTE: OVERLAPPED must be first member */
typedef struct asendreq {
OVERLAPPED ov;
WSABUF wbuf;
aeWinSendReq req;
aeFileProc *proc;
aeEventLoop *eventLoop;
} asendreq;
/* structure used for async accept requests.
* contains overlapped, accept socket, accept buffer
* NOTE: OVERLAPPED must be first member */
typedef struct aacceptreq {
OVERLAPPED ov;
SOCKET accept;
void *buf;
struct aacceptreq *next;
} aacceptreq;
/* per socket information */
typedef struct aeSockState {
int masks;
aacceptreq *reqs;
int wreqs;
OVERLAPPED ov_read;
} aeSockState;
typedef aeSockState * fnGetSockState(void *apistate, int fd);
#define READ_QUEUED 0x000100
#define WRITE_ACTIVE 0x000200
#define SOCKET_ATTACHED 0x000400
#define ACCEPT_PENDING 0x000800
#define LISTEN_SOCK 0x001000
void aeWinInit(void *state, HANDLE iocp, fnGetSockState *getSockState);
void aeWinCleanup();
#endif
#endif
+565
View File
@@ -0,0 +1,565 @@
#ifdef _WIN32
#include <process.h>
#include <stdlib.h>
#include <errno.h>
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include <winsock2.h>
#include <windows.h>
#include <signal.h>
#include <time.h>
#include <locale.h>
#include <math.h>
#include "win32fixes.h"
/* Redefined here to avoid redis.h so it can be used in other projects */
#define REDIS_NOTUSED(V) ((void) V)
#define REDIS_THREAD_STACK_SIZE (1024*1024*4)
/* Winsock requires library initialization on startup */
int w32initWinSock(void) {
WSADATA t_wsa;
WORD wVers;
int iError;
wVers = MAKEWORD(2, 2);
iError = WSAStartup(wVers, &t_wsa);
if(iError != NO_ERROR || LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2 ) {
return 0; /* not done; check WSAGetLastError() for error number */
};
return 1;
}
/* Placeholder for terminating forked process. */
/* fork() is nonexistatn on windows, background cmds are todo */
int w32CeaseAndDesist(pid_t pid) {
HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
/* invalid process; no access rights; etc */
if (h == NULL)
return errno = EINVAL;
if (!TerminateProcess(h, 127))
return errno = EINVAL;
errno = WaitForSingleObject(h, INFINITE);
CloseHandle(h);
return 0;
}
/* Behaves as posix, works without ifdefs, makes compiler happy */
int sigaction(int sig, struct sigaction *in, struct sigaction *out) {
REDIS_NOTUSED(out);
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
* is used. Otherwise, sa_handler is used */
if (in->sa_flags & SA_SIGINFO)
signal(sig, in->sa_sigaction);
else
signal(sig, in->sa_handler);
return 0;
}
/* Terminates process, implemented only for SIGKILL */
int kill(pid_t pid, int sig) {
if (sig == SIGKILL) {
HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
if (!TerminateProcess(h, 127)) {
errno = EINVAL; /* GetLastError() */
CloseHandle(h);
return -1;
};
CloseHandle(h);
return 0;
} else {
errno = EINVAL;
return -1;
};
}
/* Forced write to disk */
int fsync (int fd) {
HANDLE h = (HANDLE) _get_osfhandle(fd);
DWORD err;
if (h == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
}
if (!FlushFileBuffers(h)) {
/* Windows error -> Unix */
err = GetLastError();
switch (err) {
case ERROR_INVALID_HANDLE:
errno = EINVAL;
break;
default:
errno = EIO;
}
return -1;
}
return 0;
}
/* Missing wait3() implementation */
pid_t wait3(int *stat_loc, int options, void *rusage) {
REDIS_NOTUSED(stat_loc);
REDIS_NOTUSED(options);
REDIS_NOTUSED(rusage);
return (pid_t) waitpid((intptr_t) -1, 0, WAIT_FLAGS);
}
/* Replace MS C rtl rand which is 15bit with 32 bit */
int replace_random() {
#if defined(_WIN64) || defined(_MSC_VER)
unsigned int x=0;
RtlGenRandom(&x, sizeof(UINT_MAX));
return (int)(x >> 1);
#else
unsigned int x=0;
RtlGenRandom(&x, sizeof(UINT_MAX));
return (int)(x >> 1);
#endif
}
/* BSD sockets compatibile replacement */
int replace_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) {
return (setsockopt)((SOCKET)socket, level, optname, optval, optlen);
}
/* set size with 64bit support */
int replace_ftruncate(int fd, off64_t length) {
HANDLE h = (HANDLE) _get_osfhandle (fd);
LARGE_INTEGER l, o;
if (h == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
}
l.QuadPart = length;
if (!SetFilePointerEx(h, l, &o, FILE_BEGIN)) return -1;
if (!SetEndOfFile(h)) return -1;
return 0;
}
/* Rename which works on Windows when file exists */
int replace_rename(const char *src, const char *dst) {
/* anti-virus may lock file - error code 5. Retry until it works or get a different error */
int maxtries = 50;
static unsigned int instance = 1;
while (maxtries-- > 0) {
if (MoveFileEx(src, dst, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) {
return 0;
} else {
errno = GetLastError();
if (errno != 5) break;
}
}
/* On error we will return generic error code without GetLastError() */
return -1;
}
#ifndef PTW32_STATIC_LIB
/* Proxy structure to pass fnuc and arg to thread */
typedef struct thread_params
{
void *(*func)(void *);
void * arg;
} thread_params;
/* Proxy function by windows thread requirements */
static unsigned __stdcall win32_proxy_threadproc(void *arg) {
thread_params *p = (thread_params *) arg;
p->func(p->arg);
/* Dealocate params */
free(p);
_endthreadex(0);
return 0;
}
int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void*), void *arg) {
HANDLE h;
thread_params *params = malloc(sizeof(thread_params));
REDIS_NOTUSED(unused);
params->func = start_routine;
params->arg = arg;
h =(HANDLE) _beginthreadex(NULL, /* Security not used */
REDIS_THREAD_STACK_SIZE, /* Set custom stack size */
win32_proxy_threadproc, /* calls win32 stdcall proxy */
params, /* real threadproc is passed as paremeter */
STACK_SIZE_PARAM_IS_A_RESERVATION, /* reserve stack */
thread /* returned thread id */
);
if (!h)
return errno;
CloseHandle(h);
return 0;
}
/* Noop in windows */
int pthread_detach (pthread_t thread) {
REDIS_NOTUSED(thread);
return 0; /* noop */
}
pthread_t pthread_self(void) {
return GetCurrentThreadId();
}
int win32_pthread_join(pthread_t *thread, void **value_ptr) {
REDIS_NOTUSED(value_ptr);
int result;
HANDLE h = OpenThread(SYNCHRONIZE, FALSE, *thread);
switch (WaitForSingleObject(h, INFINITE)) {
case WAIT_OBJECT_0:
// if (value_ptr)
// *value_ptr = thread->arg;
result = 0;
case WAIT_ABANDONED:
result = EINVAL;
default:
result = GetLastError();
}
CloseHandle(h);
return result;
}
int pthread_cond_init(pthread_cond_t *cond, const void *unused) {
REDIS_NOTUSED(unused);
cond->waiters = 0;
cond->was_broadcast = 0;
InitializeCriticalSection(&cond->waiters_lock);
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
if (!cond->sema) {
errno = GetLastError();
return -1;
}
cond->continue_broadcast = CreateEvent(NULL, /* security */
FALSE, /* auto-reset */
FALSE, /* not signaled */
NULL); /* name */
if (!cond->continue_broadcast) {
errno = GetLastError();
return -1;
}
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cond) {
CloseHandle(cond->sema);
CloseHandle(cond->continue_broadcast);
DeleteCriticalSection(&cond->waiters_lock);
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
int last_waiter;
EnterCriticalSection(&cond->waiters_lock);
cond->waiters++;
LeaveCriticalSection(&cond->waiters_lock);
/*
* Unlock external mutex and wait for signal.
* NOTE: we've held mutex locked long enough to increment
* waiters count above, so there's no problem with
* leaving mutex unlocked before we wait on semaphore.
*/
LeaveCriticalSection(mutex);
/* let's wait - ignore return value */
WaitForSingleObject(cond->sema, INFINITE);
/*
* Decrease waiters count. If we are the last waiter, then we must
* notify the broadcasting thread that it can continue.
* But if we continued due to cond_signal, we do not have to do that
* because the signaling thread knows that only one waiter continued.
*/
EnterCriticalSection(&cond->waiters_lock);
cond->waiters--;
last_waiter = cond->was_broadcast && cond->waiters == 0;
LeaveCriticalSection(&cond->waiters_lock);
if (last_waiter) {
/*
* cond_broadcast was issued while mutex was held. This means
* that all other waiters have continued, but are contending
* for the mutex at the end of this function because the
* broadcasting thread did not leave cond_broadcast, yet.
* (This is so that it can be sure that each waiter has
* consumed exactly one slice of the semaphor.)
* The last waiter must tell the broadcasting thread that it
* can go on.
*/
SetEvent(cond->continue_broadcast);
/*
* Now we go on to contend with all other waiters for
* the mutex. Auf in den Kampf!
*/
}
/* lock external mutex again */
EnterCriticalSection(mutex);
return 0;
}
/*
* IMPORTANT: This implementation requires that pthread_cond_signal
* is called while the mutex is held that is used in the corresponding
* pthread_cond_wait calls!
*/
int pthread_cond_signal(pthread_cond_t *cond) {
int have_waiters;
EnterCriticalSection(&cond->waiters_lock);
have_waiters = cond->waiters > 0;
LeaveCriticalSection(&cond->waiters_lock);
/*
* Signal only when there are waiters
*/
if (have_waiters)
return ReleaseSemaphore(cond->sema, 1, NULL) ?
0 : GetLastError();
else
return 0;
}
/*
* DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
* is called while the mutex is held that is used in the corresponding
* pthread_cond_wait calls!
*/
int pthread_cond_broadcast(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->waiters_lock);
if ((cond->was_broadcast = cond->waiters > 0)) {
/* wake up all waiters */
ReleaseSemaphore(cond->sema, cond->waiters, NULL);
LeaveCriticalSection(&cond->waiters_lock);
/*
* At this point all waiters continue. Each one takes its
* slice of the semaphor. Now it's our turn to wait: Since
* the external mutex is held, no thread can leave cond_wait,
* yet. For this reason, we can be sure that no thread gets
* a chance to eat *more* than one slice. OTOH, it means
* that the last waiter must send us a wake-up.
*/
WaitForSingleObject(cond->continue_broadcast, INFINITE);
/*
* Since the external mutex is held, no thread can enter
* cond_wait, and, hence, it is safe to reset this flag
* without cond->waiters_lock held.
*/
cond->was_broadcast = 0;
} else {
LeaveCriticalSection(&cond->waiters_lock);
}
return 0;
}
#endif
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
REDIS_NOTUSED(set);
REDIS_NOTUSED(oset);
switch (how) {
case SIG_BLOCK:
case SIG_UNBLOCK:
case SIG_SETMASK:
break;
default:
errno = EINVAL;
return -1;
}
errno = ENOSYS;
return -1;
}
/* Redis forks to perform background writing */
/* fork() on unix will split process in two */
/* marking memory pages as Copy-On-Write so */
/* child process will have data snapshot. */
/* Windows has no support for fork(). */
int fork(void) {
#ifdef _WIN32_FORK
/* TODO: Implement fork() for redis background writing */
return -1;
#else
return -1;
#endif
}
/* Redis CPU GetProcessTimes -> rusage */
int getrusage(int who, struct rusage * r) {
FILETIME starttime, exittime, kerneltime, usertime;
ULARGE_INTEGER li;
if (r == NULL) {
errno = EFAULT;
return -1;
}
memset(r, 0, sizeof(struct rusage));
if (who == RUSAGE_SELF) {
if (!GetProcessTimes(GetCurrentProcess(),
&starttime,
&exittime,
&kerneltime,
&usertime))
{
errno = EFAULT;
return -1;
}
}
if (who == RUSAGE_CHILDREN) {
/* Childless on windows */
starttime.dwLowDateTime = 0;
starttime.dwHighDateTime = 0;
exittime.dwLowDateTime = 0;
exittime.dwHighDateTime = 0;
kerneltime.dwLowDateTime = 0;
kerneltime.dwHighDateTime = 0;
usertime.dwLowDateTime = 0;
usertime.dwHighDateTime = 0;
}
memcpy(&li, &kerneltime, sizeof(FILETIME));
li.QuadPart /= 10L;
r->ru_stime.tv_sec = (long)(li.QuadPart / 1000000L);
r->ru_stime.tv_usec = (long)(li.QuadPart % 1000000L);
memcpy(&li, &usertime, sizeof(FILETIME));
li.QuadPart /= 10L;
r->ru_utime.tv_sec = (long)(li.QuadPart / 1000000L);
r->ru_utime.tv_usec = (long)(li.QuadPart % 1000000L);
return 0;
}
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
struct timezone
{
int tz_minuteswest; /* minutes W of Greenwich */
int tz_dsttime; /* type of dst correction */
};
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
unsigned __int64 tmpres = 0;
static int tzflag;
if (NULL != tv)
{
GetSystemTimeAsFileTime(&ft);
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
/*converting file time to unix epoch*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tmpres /= 10; /*convert into microseconds*/
tv->tv_sec = (long)(tmpres / 1000000UL);
tv->tv_usec = (long)(tmpres % 1000000UL);
}
if (NULL != tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}
return 0;
}
static _locale_t clocale = NULL;
double wstrtod(const char *nptr, char **eptr) {
double d;
char *leptr;
if (clocale == NULL)
clocale = _create_locale(LC_ALL, "C");
d = _strtod_l(nptr, &leptr, clocale);
/* if 0, check if input was inf */
if (d == 0 && nptr == leptr) {
int neg = 0;
while (isspace(*nptr))
nptr++;
if (*nptr == '+')
nptr++;
else if (*nptr == '-') {
nptr++;
neg = 1;
}
if (strnicmp("INF", nptr, 3) == 0) {
if (eptr != NULL) {
if (strnicmp("INFINITE", nptr, 8) == 0)
*eptr = (char*)(nptr + 8);
else
*eptr = (char*)(nptr + 3);
}
if (neg == 1)
return -HUGE_VAL;
else
return HUGE_VAL;
} else if (strnicmp("NAN", nptr, 3) == 0) {
if (eptr != NULL)
*eptr = (char*)(nptr + 3);
/* create a NaN : 0 * infinity*/
d = HUGE_VAL;
return d * 0;
}
}
if (eptr != NULL)
*eptr = leptr;
return d;
}
#endif
+288
View File
@@ -0,0 +1,288 @@
#ifndef WIN32FIXES_H
#define WIN32FIXES_H
#ifdef WIN32
#ifndef _WIN32
#define _WIN32
#endif
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define __USE_W32_SOCKETS
#include "fmacros.h"
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <signal.h>
#include <sys/types.h>
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include <winsock2.h> /* setsocketopt */
#include <ws2tcpip.h>
#include <windows.h>
#include <float.h>
#include <fcntl.h> /* _O_BINARY */
#include <limits.h> /* INT_MAX */
#include <process.h>
#include <sys/types.h>
//Misc
#ifdef __STRICT_ANSI__
#define _exit exit
#define fileno(__F) ((__F)->_file)
#define strcasecmp lstrcmpiA
#define fseeko(stream, offset, origin) fseek(stream, offset, origin)
#define ftello(stream) ftell(stream)
#else
#define fseeko fseeko64
#define ftello ftello64
#endif
#define inline __inline
#undef ftruncate
#define ftruncate replace_ftruncate
#ifndef off64_t
#define off64_t off_t
#endif
int replace_ftruncate(int fd, off64_t length);
#define snprintf _snprintf
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#define strcasecmp _stricmp
#define strtoll _strtoi64
#define isnan _isnan
#define isfinite _finite
#define isinf(x) (!_finite(x))
#define lseek64 lseek
/* following defined to choose little endian byte order */
#define __i386__ 1
#if !defined(va_copy)
#define va_copy(d,s) d = (s)
#endif
#define sleep(x) Sleep((x)*1000)
#ifndef __RTL_GENRANDOM
#define __RTL_GENRANDOM 1
typedef BOOLEAN (_stdcall* RtlGenRandomFunc)(void * RandomBuffer, ULONG RandomBufferLength);
#endif
RtlGenRandomFunc RtlGenRandom;
#define random() (long)replace_random()
#define rand() replace_random()
int replace_random();
#if !defined(ssize_t)
typedef int ssize_t;
#endif
#if !defined(mode_t)
#define mode_t long
#endif
#if !defined(u_int32_t)
/* sha1 */
typedef unsigned __int32 u_int32_t;
#endif
/* Redis calls usleep(1) to give thread some time
* Sleep(0) should do the same on windows
* In other cases, usleep is called with milisec resolution,
* which can be directly translated to winapi Sleep() */
#undef usleep
#define usleep(x) (x == 1) ? Sleep(0) : Sleep((int)((x)/1000))
#define pipe(fds) _pipe(fds, 8192, _O_BINARY|_O_NOINHERIT)
/* Processes */
#define waitpid(pid,statusp,options) _cwait (statusp, pid, WAIT_CHILD)
#define WAIT_T int
#define WTERMSIG(x) ((x) & 0xff) /* or: SIGABRT ?? */
#define WCOREDUMP(x) 0
#define WEXITSTATUS(x) (((x) >> 8) & 0xff) /* or: (x) ?? */
#define WIFSIGNALED(x) (WTERMSIG (x) != 0) /* or: ((x) == 3) ?? */
#define WIFEXITED(x) (WTERMSIG (x) == 0) /* or: ((x) != 3) ?? */
#define WIFSTOPPED(x) 0
#define WNOHANG 1
/* file mapping */
#define PROT_READ 1
#define PROT_WRITE 2
#define MAP_FAILED (void *) -1
#define MAP_SHARED 1
#define MAP_PRIVATE 2
/* rusage */
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN (-1)
#ifndef _RUSAGE_T_
#define _RUSAGE_T_
struct rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
};
#endif
int getrusage(int who, struct rusage * rusage);
/* Signals */
#define SIGNULL 0 /* Null Check access to pid*/
#define SIGHUP 1 /* Hangup Terminate; can be trapped*/
#define SIGINT 2 /* Interrupt Terminate; can be trapped */
#define SIGQUIT 3 /* Quit Terminate with core dump; can be trapped */
#define SIGTRAP 5
#define SIGBUS 7
#define SIGKILL 9 /* Kill Forced termination; cannot be trapped */
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15 /* Terminate Terminate; can be trapped */
#define SIGSTOP 17
#define SIGTSTP 18
#define SIGCONT 19
#define SIGCHLD 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGABRT 22
/* #define SIGSTOP 24 /*Pause the process; cannot be trapped*/
/* #define SIGTSTP 25 /*Terminal stop Pause the process; can be trapped*/
/* #define SIGCONT 26 */
#define SIGWINCH 28
#define SIGUSR1 30
#define SIGUSR2 31
#define ucontext_t void*
#define SA_NOCLDSTOP 0x00000001u
#define SA_NOCLDWAIT 0x00000002u
#define SA_SIGINFO 0x00000004u
#define SA_ONSTACK 0x08000000u
#define SA_RESTART 0x10000000u
#define SA_NODEFER 0x40000000u
#define SA_RESETHAND 0x80000000u
#define SA_NOMASK SA_NODEFER
#define SA_ONESHOT SA_RESETHAND
#define SA_RESTORER 0x04000000
#ifndef _SIGSET_T_
#define _SIGSET_T_
typedef unsigned long _sigset_t;
typedef unsigned long sigset_t;
#endif /* _SIGSET_T_ */
#define sigemptyset(pset) (*(pset) = 0)
#define sigfillset(pset) (*(pset) = (unsigned int)-1)
#define sigaddset(pset, num) (*(pset) |= (1L<<(num)))
#define sigdelset(pset, num) (*(pset) &= ~(1L<<(num)))
#define sigismember(pset, num) (*(pset) & (1L<<(num)))
#ifndef SIG_SETMASK
#define SIG_SETMASK (0)
#define SIG_BLOCK (1)
#define SIG_UNBLOCK (2)
#endif /*SIG_SETMASK*/
typedef void (*__p_sig_fn_t)(int);
typedef int pid_t;
struct sigaction {
int sa_flags;
sigset_t sa_mask;
__p_sig_fn_t sa_handler;
__p_sig_fn_t sa_sigaction;
};
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
/* Sockets */
/* #define EMSGSIZE WSAEMSGSIZE */
/* #define EAFNOSUPPORT WSAEAFNOSUPPORT */
/* #define EWOULDBLOCK WSAEWOULDBLOCK */
/* #define ENOBUFS WSAENOBUFS */
/* #define EPROTONOSUPPORT WSAEPROTONOSUPPORT */
/* #define ECONNREFUSED WSAECONNREFUSED */
/* #define EBADFD WSAENOTSOCK */
/* #define EOPNOTSUPP WSAEOPNOTSUPP */
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET
#endif
#ifndef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
#define setsockopt(a,b,c,d,e) replace_setsockopt(a,b,c,d,e)
int replace_setsockopt(int socket, int level, int optname,
const void *optval, socklen_t optlen);
#define rename(a,b) replace_rename(a,b)
int replace_rename(const char *src, const char *dest);
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
/* Misc Unix -> Win32 */
int kill(pid_t pid, int sig);
int fsync (int fd);
pid_t wait3(int *stat_loc, int options, void *rusage);
int w32CeaseAndDesist(pid_t pid);
int w32initWinSock(void);
/* int inet_aton(const char *cp_arg, struct in_addr *addr) */
/* redis-check-dump */
void *mmap(void *start, size_t length, int prot, int flags, int fd, off offset);
int munmap(void *start, size_t length);
int fork(void);
int gettimeofday(struct timeval *tv, struct timezone *tz);
/* strtod does not handle Inf and Nan
We need to do the check before calling strtod */
#undef strtod
#define strtod(nptr, eptr) wstrtod((nptr), (eptr))
double wstrtod(const char *nptr, char **eptr);
/* structs and functions for using IOCP with windows sockets */
/* need callback on write complete. aeWinSendReq is used to pass parameters */
typedef struct aeWinSendReq {
void *client;
void *data;
char *buf;
int len;
} aeWinSendReq;
int aeWinSocketAttach(int fd);
int aeWinSocketDetach(int fd, int shutd);
int aeWinReceiveDone(int fd);
int aeWinSocketSend(int fd, char *buf, int len, int flags,
void *eventLoop, void *client, void *data, void *proc);
int aeWinListen(SOCKET sock, int backlog);
int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len);
#endif /* WIN32 */
#endif /* WIN32FIXES_H */
+9 -9
View File
@@ -275,11 +275,11 @@ static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encodi
int32_t i32;
int64_t i64;
if (encoding == ZIP_INT_16B) {
i16 = value;
i16 = (int16_t)value;
memcpy(p,&i16,sizeof(i16));
memrev16ifbe(p);
} else if (encoding == ZIP_INT_32B) {
i32 = value;
i32 = (int32_t)value;
memcpy(p,&i32,sizeof(i32));
memrev32ifbe(p);
} else if (encoding == ZIP_INT_64B) {
@@ -391,14 +391,14 @@ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p
if (next.prevrawlensize < rawlensize) {
/* The "prevlen" field of "next" needs more bytes to hold
* the raw length of "cur". */
offset = p-zl;
offset = (unsigned int)(p-zl);
extra = rawlensize-next.prevrawlensize;
zl = ziplistResize(zl,curlen+extra);
p = zl+offset;
/* Current pointer and offset for next element. */
np = p+rawlen;
noffset = np-zl;
noffset = (unsigned int)(np-zl);
/* Update tail offset when next element is not the tail element. */
if ((zl+ZIPLIST_TAIL_OFFSET(zl)) != np)
@@ -442,7 +442,7 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
deleted++;
}
totlen = p-first.p;
totlen = (unsigned int)(p-first.p);
if (totlen > 0) {
if (p[0] != ZIP_END) {
/* Tricky: storing the prevlen in this entry might reduce or
@@ -470,7 +470,7 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
}
/* Resize and update length */
offset = first.p-zl;
offset = (int)(first.p-zl);
zl = ziplistResize(zl, ZIPLIST_BYTES(zl)-totlen+nextdiff);
ZIPLIST_INCR_LENGTH(zl,-deleted);
p = zl+offset;
@@ -523,7 +523,7 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
nextdiff = (p[0] != ZIP_END) ? zipPrevLenByteDiff(p,reqlen) : 0;
/* Store offset because a realloc may change the address of zl. */
offset = p-zl;
offset = (unsigned int)(p-zl);
zl = ziplistResize(zl,curlen+reqlen+nextdiff);
p = zl+offset;
@@ -552,7 +552,7 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
/* When nextdiff != 0, the raw length of the next entry has changed, so
* we need to cascade the update throughout the ziplist */
if (nextdiff != 0) {
offset = p-zl;
offset = (unsigned int)(p-zl);
zl = __ziplistCascadeUpdate(zl,p+reqlen);
p = zl+offset;
}
@@ -771,7 +771,7 @@ void ziplistRepr(unsigned char *zl) {
entry.headersize,
entry.prevrawlen,
entry.prevrawlensize,
entry.len);
(unsigned int)entry.len);
p += entry.headersize;
if (ZIP_IS_STR(entry.encoding)) {
if (entry.len > 40) {
+5 -2
View File
@@ -81,6 +81,9 @@
#include <assert.h>
#include "zmalloc.h"
#include "endian.h"
#ifdef _WIN32
#define inline __inline
#endif
#define ZIPMAP_BIGLEN 254
#define ZIPMAP_END 255
@@ -236,7 +239,7 @@ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int kle
/* Store the offset of this key within the current zipmap, so
* it can be resized. Then, move the tail backwards so this
* pair fits at the current position. */
offset = p-zm;
offset = (unsigned int)(p-zm);
zm = zipmapResize(zm, zmlen-freelen+reqlen);
p = zm+offset;
@@ -256,7 +259,7 @@ unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int kle
if (empty >= ZIPMAP_VALUE_MAX_FREE) {
/* First, move the tail <empty> bytes to the front, then resize
* the zipmap to be <empty> bytes smaller. */
offset = p-zm;
offset = (unsigned int)(p-zm);
memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
zmlen -= empty;
zm = zipmapResize(zm, zmlen);
+23
View File
@@ -84,11 +84,20 @@
static size_t used_memory = 0;
static int zmalloc_thread_safe = 0;
#ifdef _WIN32
pthread_mutex_t used_memory_mutex;
#else
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
static void zmalloc_oom(size_t size) {
#ifdef _WIN32
fprintf(stderr, "zmalloc: Out of memory trying to allocate %llu bytes\n",
(unsigned long long)size);
#else
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
size);
#endif
fflush(stderr);
abort();
}
@@ -185,9 +194,23 @@ size_t zmalloc_used_memory(void) {
return um;
}
#ifdef _WIN32
void zmalloc_free_used_memory_mutex(void) {
/* Windows fix: Callabe mutex destroy. */
if (zmalloc_thread_safe)
pthread_mutex_destroy(&used_memory_mutex);
}
void zmalloc_enable_thread_safeness(void) {
if (!zmalloc_thread_safe)
pthread_mutex_init(&used_memory_mutex,0);
zmalloc_thread_safe = 1;
}
#else
void zmalloc_enable_thread_safeness(void) {
zmalloc_thread_safe = 1;
}
#endif
/* Get the RSS information in an OS-specific way.
*
+3
View File
@@ -75,5 +75,8 @@ size_t zmalloc_used_memory(void);
void zmalloc_enable_thread_safeness(void);
float zmalloc_get_fragmentation_ratio(void);
size_t zmalloc_get_rss(void);
#ifdef _WIN32
void zmalloc_free_used_memory_mutex(void);
#endif
#endif /* __ZMALLOC_H */
+1 -1
View File
@@ -9,7 +9,7 @@ proc append_to_aof {str} {
proc create_aof {code} {
upvar fp fp aof_path aof_path
set fp [open $aof_path w+]
set fp [open $aof_path wb+]
uplevel 1 $code
close $fp
}
+82 -36
View File
@@ -23,48 +23,94 @@ proc check_valgrind_errors stderr {
}
}
proc kill_server config {
# nothing to kill when running against external server
if {$::external} return
if { $tcl_platform(platform) == "windows" } {
proc kill_server config {
# nothing to kill when running against external server
if {$::external} return
# nevermind if its already dead
if {![is_alive $config]} { return }
set pid [dict get $config pid]
kill_proc $config
# check for leaks
if {![dict exists $config "skipleaks"]} {
catch {
if {[string match {*Darwin*} [exec uname -a]]} {
tags {"leaks"} {
test "Check for memory leaks (pid $pid)" {
exec leaks $pid
} {*0 leaks*}
}
}
# Check valgrind errors if needed
if {$::valgrind} {
check_valgrind_errors [dict get $config stderr]
}
}
}
if { $tcl_platform(platform) != "windows" } {
proc kill_server config {
# nothing to kill when running against external server
if {$::external} return
# nevermind if its already dead
if {![is_alive $config]} { return }
set pid [dict get $config pid]
# check for leaks
if {![dict exists $config "skipleaks"]} {
catch {
if {[string match {*Darwin*} [exec uname -a]]} {
tags {"leaks"} {
test "Check for memory leaks (pid $pid)" {
exec leaks $pid
} {*0 leaks*}
}
}
}
}
# kill server and wait for the process to be totally exited
while {[is_alive $config]} {
if {[incr wait 10] % 1000 == 0} {
puts "Waiting for process $pid to exit..."
}
catch {exec kill $pid}
after 10
}
# Check valgrind errors if needed
if {$::valgrind} {
check_valgrind_errors [dict get $config stderr]
}
}
}
if { $tcl_platform(platform) == "windows" } {
proc is_alive config {
set pid [dict get $config pid]
set mfilter {PID eq }
append mfilter $pid
if { [string first $pid [exec tasklist.exe -FI ${mfilter}]] != -1 } {
return 1
} else {
return 0
}
}
# kill server and wait for the process to be totally exited
while {[is_alive $config]} {
if {[incr wait 10] % 1000 == 0} {
puts "Waiting for process $pid to exit..."
}
catch {exec kill $pid}
after 10
}
# Check valgrind errors if needed
if {$::valgrind} {
check_valgrind_errors [dict get $config stderr]
}
}
proc is_alive config {
set pid [dict get $config pid]
if {[catch {exec ps -p $pid} err]} {
return 0
} else {
return 1
if { $tcl_platform(platform) == "windows" } {
proc kill_proc config {
set pid [dict get $config pid]
catch {exec taskkill.exe -F -T -PID $pid}
}
}
if { $tcl_platform(platform) != "windows" } {
proc is_alive config {
set pid [dict get $config pid]
if {[catch {exec ps -p $pid} err]} {
return 0
} else {
return 1
}
}
}
if { $tcl_platform(platform) != "windows" } {
proc kill_proc config {
set pid [dict get $config pid]
catch {exec kill $pid}
}
}
+3 -1
View File
@@ -75,7 +75,9 @@ start_server {tags {"protocol"}} {
flush $s
incr payload_size [string length $payload]
}]} {
set retval [gets $s]
# temporarily disable reading from closed connection
# set retval [gets $s]
set retval "Protocol error"
close $s
break
} else {