windows sockets with IOCP
This commit is contained in:
committed by
Igor Zinkovsky
parent
734dabb6b7
commit
ac1cdea778
+20
@@ -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
|
||||
|
||||
|
||||
Vendored
+9
-2
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+65
@@ -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'.
|
||||
|
||||
Vendored
+10
@@ -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);
|
||||
|
||||
Vendored
+83
-7
@@ -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 */
|
||||
|
||||
Vendored
+20
@@ -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
|
||||
|
||||
Vendored
+179
-1
@@ -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
|
||||
}
|
||||
|
||||
Vendored
+7
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+244
-2
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -12,4 +12,8 @@
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#ifdef _WIN32
|
||||
#define off off_t
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
struct sdshdr {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user