Commit 05ba119f authored by Salvatore Sanfilippo's avatar Salvatore Sanfilippo
Browse files

Merge pull request #2143 from mattsta/quicklist

Quicklist (linked list + ziplist)
parents 9e718a1f 5870e224
...@@ -209,43 +209,49 @@ int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) { ...@@ -209,43 +209,49 @@ int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
return rdbEncodeInteger(value,enc); return rdbEncodeInteger(value,enc);
} }
int rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) { int rdbSaveLzfBlob(rio *rdb, void *data, size_t compress_len,
size_t comprlen, outlen; size_t original_len) {
unsigned char byte; unsigned char byte;
int n, nwritten = 0; int n, nwritten = 0;
void *out;
/* We require at least four bytes compression for this to be worth it */
if (len <= 4) return 0;
outlen = len-4;
if ((out = zmalloc(outlen+1)) == NULL) return 0;
comprlen = lzf_compress(s, len, out, outlen);
if (comprlen == 0) {
zfree(out);
return 0;
}
/* Data compressed! Let's save it on disk */ /* Data compressed! Let's save it on disk */
byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF; byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
if ((n = rdbWriteRaw(rdb,&byte,1)) == -1) goto writeerr; if ((n = rdbWriteRaw(rdb,&byte,1)) == -1) goto writeerr;
nwritten += n; nwritten += n;
if ((n = rdbSaveLen(rdb,comprlen)) == -1) goto writeerr; if ((n = rdbSaveLen(rdb,compress_len)) == -1) goto writeerr;
nwritten += n; nwritten += n;
if ((n = rdbSaveLen(rdb,len)) == -1) goto writeerr; if ((n = rdbSaveLen(rdb,original_len)) == -1) goto writeerr;
nwritten += n; nwritten += n;
if ((n = rdbWriteRaw(rdb,out,comprlen)) == -1) goto writeerr; if ((n = rdbWriteRaw(rdb,data,compress_len)) == -1) goto writeerr;
nwritten += n; nwritten += n;
zfree(out);
return nwritten; return nwritten;
writeerr: writeerr:
zfree(out);
return -1; return -1;
} }
int rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) {
size_t comprlen, outlen;
void *out;
/* We require at least four bytes compression for this to be worth it */
if (len <= 4) return 0;
outlen = len-4;
if ((out = zmalloc(outlen+1)) == NULL) return 0;
comprlen = lzf_compress(s, len, out, outlen);
if (comprlen == 0) {
zfree(out);
return 0;
}
size_t nwritten = rdbSaveLzfBlob(rdb, out, comprlen, len);
zfree(out);
return nwritten;
}
robj *rdbLoadLzfStringObject(rio *rdb) { robj *rdbLoadLzfStringObject(rio *rdb) {
unsigned int len, clen; unsigned int len, clen;
unsigned char *c = NULL; unsigned char *c = NULL;
...@@ -433,10 +439,8 @@ int rdbSaveObjectType(rio *rdb, robj *o) { ...@@ -433,10 +439,8 @@ int rdbSaveObjectType(rio *rdb, robj *o) {
case REDIS_STRING: case REDIS_STRING:
return rdbSaveType(rdb,REDIS_RDB_TYPE_STRING); return rdbSaveType(rdb,REDIS_RDB_TYPE_STRING);
case REDIS_LIST: case REDIS_LIST:
if (o->encoding == REDIS_ENCODING_ZIPLIST) if (o->encoding == REDIS_ENCODING_QUICKLIST)
return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST_ZIPLIST); return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST_QUICKLIST);
else if (o->encoding == REDIS_ENCODING_LINKEDLIST)
return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST);
else else
redisPanic("Unknown list encoding"); redisPanic("Unknown list encoding");
case REDIS_SET: case REDIS_SET:
...@@ -477,7 +481,7 @@ int rdbLoadObjectType(rio *rdb) { ...@@ -477,7 +481,7 @@ int rdbLoadObjectType(rio *rdb) {
/* Save a Redis object. Returns -1 on error, number of bytes written on success. */ /* Save a Redis object. Returns -1 on error, number of bytes written on success. */
int rdbSaveObject(rio *rdb, robj *o) { int rdbSaveObject(rio *rdb, robj *o) {
int n, nwritten = 0; int n = 0, nwritten = 0;
if (o->type == REDIS_STRING) { if (o->type == REDIS_STRING) {
/* Save a string value */ /* Save a string value */
...@@ -485,25 +489,24 @@ int rdbSaveObject(rio *rdb, robj *o) { ...@@ -485,25 +489,24 @@ int rdbSaveObject(rio *rdb, robj *o) {
nwritten += n; nwritten += n;
} else if (o->type == REDIS_LIST) { } else if (o->type == REDIS_LIST) {
/* Save a list value */ /* Save a list value */
if (o->encoding == REDIS_ENCODING_ZIPLIST) { if (o->encoding == REDIS_ENCODING_QUICKLIST) {
size_t l = ziplistBlobLen((unsigned char*)o->ptr); quicklist *ql = o->ptr;
quicklistNode *node = ql->head;
if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
nwritten += n;
} else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
list *list = o->ptr;
listIter li;
listNode *ln;
if ((n = rdbSaveLen(rdb,listLength(list))) == -1) return -1; if ((n = rdbSaveLen(rdb,ql->len)) == -1) return -1;
nwritten += n; nwritten += n;
listRewind(list,&li); do {
while((ln = listNext(&li))) { if (quicklistNodeIsCompressed(node)) {
robj *eleobj = listNodeValue(ln); void *data;
if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1; size_t compress_len = quicklistGetLzf(node, &data);
nwritten += n; if ((n = rdbSaveLzfBlob(rdb,data,compress_len,node->sz)) == -1) return -1;
} nwritten += n;
} else {
if ((n = rdbSaveRawString(rdb,node->zl,node->sz)) == -1) return -1;
nwritten += n;
}
} while ((node = node->next));
} else { } else {
redisPanic("Unknown list encoding"); redisPanic("Unknown list encoding");
} }
...@@ -720,7 +723,7 @@ int rdbSave(char *filename) { ...@@ -720,7 +723,7 @@ int rdbSave(char *filename) {
char tmpfile[256]; char tmpfile[256];
FILE *fp; FILE *fp;
rio rdb; rio rdb;
int error; int error = 0;
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid()); snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
fp = fopen(tmpfile,"w"); fp = fopen(tmpfile,"w");
...@@ -831,33 +834,18 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -831,33 +834,18 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* Read list value */ /* Read list value */
if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL; if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
/* Use a real list when there are too many entries */ o = createQuicklistObject();
if (len > server.list_max_ziplist_entries) { quicklistSetOptions(o->ptr, server.list_max_ziplist_size,
o = createListObject(); server.list_compress_depth);
} else {
o = createZiplistObject();
}
/* Load every single element of the list */ /* Load every single element of the list */
while(len--) { while(len--) {
if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
dec = getDecodedObject(ele);
/* If we are using a ziplist and the value is too big, convert size_t len = sdslen(dec->ptr);
* the object to a real list. */ quicklistPushTail(o->ptr, dec->ptr, len);
if (o->encoding == REDIS_ENCODING_ZIPLIST && decrRefCount(dec);
sdsEncodedObject(ele) && decrRefCount(ele);
sdslen(ele->ptr) > server.list_max_ziplist_value)
listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
if (o->encoding == REDIS_ENCODING_ZIPLIST) {
dec = getDecodedObject(ele);
o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
decrRefCount(dec);
decrRefCount(ele);
} else {
ele = tryObjectEncoding(ele);
listAddNodeTail(o->ptr,ele);
}
} }
} else if (rdbtype == REDIS_RDB_TYPE_SET) { } else if (rdbtype == REDIS_RDB_TYPE_SET) {
/* Read list/set value */ /* Read list/set value */
...@@ -994,20 +982,30 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -994,20 +982,30 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* All pairs should be read by now */ /* All pairs should be read by now */
redisAssert(len == 0); redisAssert(len == 0);
} else if (rdbtype == REDIS_RDB_TYPE_LIST_QUICKLIST) {
if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
o = createQuicklistObject();
quicklistSetOptions(o->ptr, server.list_max_ziplist_size,
server.list_compress_depth);
while (len--) {
if ((ele = rdbLoadStringObject(rdb)) == NULL) return NULL;
/* 'ele' contains a sds of the ziplist, but we need to extract
* the actual ziplist for future usage. We must copy the
* sds contents to a new buffer. */
unsigned char *zl = (unsigned char *)sdsnative(ele->ptr);
zfree(ele); /* free robj container since we keep the ziplist */
quicklistAppendZiplist(o->ptr, zl);
}
} else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP || } else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP ||
rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST || rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST ||
rdbtype == REDIS_RDB_TYPE_SET_INTSET || rdbtype == REDIS_RDB_TYPE_SET_INTSET ||
rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST || rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST ||
rdbtype == REDIS_RDB_TYPE_HASH_ZIPLIST) rdbtype == REDIS_RDB_TYPE_HASH_ZIPLIST)
{ {
robj *aux = rdbLoadStringObject(rdb); o = rdbLoadStringObject(rdb);
if (o == NULL) return NULL;
if (aux == NULL) return NULL; o->ptr = sdsnative(o->ptr);
o = createObject(REDIS_STRING,NULL); /* string is just placeholder */
o->ptr = zmalloc(sdslen(aux->ptr));
memcpy(o->ptr,aux->ptr,sdslen(aux->ptr));
decrRefCount(aux);
/* Fix the object encoding, and make sure to convert the encoded /* Fix the object encoding, and make sure to convert the encoded
* data type into the base type if accordingly to the current * data type into the base type if accordingly to the current
...@@ -1048,8 +1046,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -1048,8 +1046,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
case REDIS_RDB_TYPE_LIST_ZIPLIST: case REDIS_RDB_TYPE_LIST_ZIPLIST:
o->type = REDIS_LIST; o->type = REDIS_LIST;
o->encoding = REDIS_ENCODING_ZIPLIST; o->encoding = REDIS_ENCODING_ZIPLIST;
if (ziplistLen(o->ptr) > server.list_max_ziplist_entries) listTypeConvert(o,REDIS_ENCODING_QUICKLIST);
listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
break; break;
case REDIS_RDB_TYPE_SET_INTSET: case REDIS_RDB_TYPE_SET_INTSET:
o->type = REDIS_SET; o->type = REDIS_SET;
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
/* The current RDB version. When the format changes in a way that is no longer /* The current RDB version. When the format changes in a way that is no longer
* backward compatible this number gets incremented. */ * backward compatible this number gets incremented. */
#define REDIS_RDB_VERSION 6 #define REDIS_RDB_VERSION 7
/* Defines related to the dump file format. To store 32 bits lengths for short /* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of * keys requires a lot of space, so we check the most significant 2 bits of
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
#define REDIS_RDB_TYPE_SET 2 #define REDIS_RDB_TYPE_SET 2
#define REDIS_RDB_TYPE_ZSET 3 #define REDIS_RDB_TYPE_ZSET 3
#define REDIS_RDB_TYPE_HASH 4 #define REDIS_RDB_TYPE_HASH 4
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* Object types for encoded objects. */ /* Object types for encoded objects. */
#define REDIS_RDB_TYPE_HASH_ZIPMAP 9 #define REDIS_RDB_TYPE_HASH_ZIPMAP 9
...@@ -81,9 +82,11 @@ ...@@ -81,9 +82,11 @@
#define REDIS_RDB_TYPE_SET_INTSET 11 #define REDIS_RDB_TYPE_SET_INTSET 11
#define REDIS_RDB_TYPE_ZSET_ZIPLIST 12 #define REDIS_RDB_TYPE_ZSET_ZIPLIST 12
#define REDIS_RDB_TYPE_HASH_ZIPLIST 13 #define REDIS_RDB_TYPE_HASH_ZIPLIST 13
#define REDIS_RDB_TYPE_LIST_QUICKLIST 14
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* Test if a type is an object type. */ /* Test if a type is an object type. */
#define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 13)) #define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 14))
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */ /* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
#define REDIS_RDB_OPCODE_EXPIRETIME_MS 252 #define REDIS_RDB_OPCODE_EXPIRETIME_MS 252
......
...@@ -738,12 +738,24 @@ int main(int argc, const char **argv) { ...@@ -738,12 +738,24 @@ int main(int argc, const char **argv) {
free(cmd); free(cmd);
} }
if (test_is_selected("rpush")) {
len = redisFormatCommand(&cmd,"RPUSH mylist %s",data);
benchmark("RPUSH",cmd,len);
free(cmd);
}
if (test_is_selected("lpop")) { if (test_is_selected("lpop")) {
len = redisFormatCommand(&cmd,"LPOP mylist"); len = redisFormatCommand(&cmd,"LPOP mylist");
benchmark("LPOP",cmd,len); benchmark("LPOP",cmd,len);
free(cmd); free(cmd);
} }
if (test_is_selected("rpop")) {
len = redisFormatCommand(&cmd,"RPOP mylist");
benchmark("RPOP",cmd,len);
free(cmd);
}
if (test_is_selected("sadd")) { if (test_is_selected("sadd")) {
len = redisFormatCommand(&cmd, len = redisFormatCommand(&cmd,
"SADD myset element:__rand_int__"); "SADD myset element:__rand_int__");
......
...@@ -629,6 +629,9 @@ static int cliSendCommand(int argc, char **argv, int repeat) { ...@@ -629,6 +629,9 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
output_raw = 0; output_raw = 0;
if (!strcasecmp(command,"info") || if (!strcasecmp(command,"info") ||
(argc == 3 && !strcasecmp(command,"debug") &&
(!strcasecmp(argv[1],"jemalloc") &&
!strcasecmp(argv[2],"info"))) ||
(argc == 2 && !strcasecmp(command,"cluster") && (argc == 2 && !strcasecmp(command,"cluster") &&
(!strcasecmp(argv[1],"nodes") || (!strcasecmp(argv[1],"nodes") ||
!strcasecmp(argv[1],"info"))) || !strcasecmp(argv[1],"info"))) ||
......
...@@ -1449,8 +1449,8 @@ void initServerConfig(void) { ...@@ -1449,8 +1449,8 @@ void initServerConfig(void) {
server.maxmemory_samples = REDIS_DEFAULT_MAXMEMORY_SAMPLES; server.maxmemory_samples = REDIS_DEFAULT_MAXMEMORY_SAMPLES;
server.hash_max_ziplist_entries = REDIS_HASH_MAX_ZIPLIST_ENTRIES; server.hash_max_ziplist_entries = REDIS_HASH_MAX_ZIPLIST_ENTRIES;
server.hash_max_ziplist_value = REDIS_HASH_MAX_ZIPLIST_VALUE; server.hash_max_ziplist_value = REDIS_HASH_MAX_ZIPLIST_VALUE;
server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES; server.list_max_ziplist_size = REDIS_LIST_MAX_ZIPLIST_SIZE;
server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE; server.list_compress_depth = REDIS_LIST_COMPRESS_DEPTH;
server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES; server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
server.zset_max_ziplist_entries = REDIS_ZSET_MAX_ZIPLIST_ENTRIES; server.zset_max_ziplist_entries = REDIS_ZSET_MAX_ZIPLIST_ENTRIES;
server.zset_max_ziplist_value = REDIS_ZSET_MAX_ZIPLIST_VALUE; server.zset_max_ziplist_value = REDIS_ZSET_MAX_ZIPLIST_VALUE;
...@@ -3058,11 +3058,7 @@ void infoCommand(redisClient *c) { ...@@ -3058,11 +3058,7 @@ void infoCommand(redisClient *c) {
addReply(c,shared.syntaxerr); addReply(c,shared.syntaxerr);
return; return;
} }
sds info = genRedisInfoString(section); addReplyBulkSds(c, genRedisInfoString(section));
addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
(unsigned long)sdslen(info)));
addReplySds(c,info);
addReply(c,shared.crlf);
} }
void monitorCommand(redisClient *c) { void monitorCommand(redisClient *c) {
...@@ -3659,6 +3655,32 @@ int redisIsSupervised(void) { ...@@ -3659,6 +3655,32 @@ int redisIsSupervised(void) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct timeval tv; struct timeval tv;
#ifdef REDIS_TEST
if (argc == 3 && !strcasecmp(argv[1], "test")) {
if (!strcasecmp(argv[2], "ziplist")) {
return ziplistTest(argc, argv);
} else if (!strcasecmp(argv[2], "quicklist")) {
quicklistTest(argc, argv);
} else if (!strcasecmp(argv[2], "intset")) {
return intsetTest(argc, argv);
} else if (!strcasecmp(argv[2], "zipmap")) {
return zipmapTest(argc, argv);
} else if (!strcasecmp(argv[2], "sha1test")) {
return sha1Test(argc, argv);
} else if (!strcasecmp(argv[2], "util")) {
return utilTest(argc, argv);
} else if (!strcasecmp(argv[2], "sds")) {
return sdsTest(argc, argv);
} else if (!strcasecmp(argv[2], "endianconv")) {
return endianconvTest(argc, argv);
} else if (!strcasecmp(argv[2], "crc64")) {
return crc64Test(argc, argv);
}
return -1; /* test not found */
}
#endif
/* We need to initialize our libraries, and the server configuration. */ /* We need to initialize our libraries, and the server configuration. */
#ifdef INIT_SETPROCTITLE_REPLACEMENT #ifdef INIT_SETPROCTITLE_REPLACEMENT
spt_init(argc, argv); spt_init(argc, argv);
......
...@@ -65,6 +65,13 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -65,6 +65,13 @@ typedef long long mstime_t; /* millisecond time type. */
#include "util.h" /* Misc functions useful in many places */ #include "util.h" /* Misc functions useful in many places */
#include "latency.h" /* Latency monitor API */ #include "latency.h" /* Latency monitor API */
#include "sparkline.h" /* ASII graphs API */ #include "sparkline.h" /* ASII graphs API */
#include "quicklist.h"
/* Following includes allow test functions to be called from Redis main() */
#include "zipmap.h"
#include "sha1.h"
#include "endianconv.h"
#include "crc64.h"
/* Error codes */ /* Error codes */
#define REDIS_OK 0 #define REDIS_OK 0
...@@ -198,6 +205,7 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -198,6 +205,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */ #define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ #define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */ #define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define REDIS_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
/* Defines related to the dump file format. To store 32 bits lengths for short /* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of * keys requires a lot of space, so we check the most significant 2 bits of
...@@ -323,12 +331,14 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -323,12 +331,14 @@ typedef long long mstime_t; /* millisecond time type. */
/* Zip structure related defaults */ /* Zip structure related defaults */
#define REDIS_HASH_MAX_ZIPLIST_ENTRIES 512 #define REDIS_HASH_MAX_ZIPLIST_ENTRIES 512
#define REDIS_HASH_MAX_ZIPLIST_VALUE 64 #define REDIS_HASH_MAX_ZIPLIST_VALUE 64
#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512
#define REDIS_LIST_MAX_ZIPLIST_VALUE 64
#define REDIS_SET_MAX_INTSET_ENTRIES 512 #define REDIS_SET_MAX_INTSET_ENTRIES 512
#define REDIS_ZSET_MAX_ZIPLIST_ENTRIES 128 #define REDIS_ZSET_MAX_ZIPLIST_ENTRIES 128
#define REDIS_ZSET_MAX_ZIPLIST_VALUE 64 #define REDIS_ZSET_MAX_ZIPLIST_VALUE 64
/* List defaults */
#define REDIS_LIST_MAX_ZIPLIST_SIZE -2
#define REDIS_LIST_COMPRESS_DEPTH 0
/* HyperLogLog defines */ /* HyperLogLog defines */
#define REDIS_DEFAULT_HLL_SPARSE_MAX_BYTES 3000 #define REDIS_DEFAULT_HLL_SPARSE_MAX_BYTES 3000
...@@ -863,12 +873,14 @@ struct redisServer { ...@@ -863,12 +873,14 @@ struct redisServer {
/* Zip structure config, see redis.conf for more information */ /* Zip structure config, see redis.conf for more information */
size_t hash_max_ziplist_entries; size_t hash_max_ziplist_entries;
size_t hash_max_ziplist_value; size_t hash_max_ziplist_value;
size_t list_max_ziplist_entries;
size_t list_max_ziplist_value;
size_t set_max_intset_entries; size_t set_max_intset_entries;
size_t zset_max_ziplist_entries; size_t zset_max_ziplist_entries;
size_t zset_max_ziplist_value; size_t zset_max_ziplist_value;
size_t hll_sparse_max_bytes; size_t hll_sparse_max_bytes;
/* List parameters */
int list_max_ziplist_size;
int list_compress_depth;
/* time cache */
time_t unixtime; /* Unix time sampled every cron cycle. */ time_t unixtime; /* Unix time sampled every cron cycle. */
long long mstime; /* Like 'unixtime' but with milliseconds resolution. */ long long mstime; /* Like 'unixtime' but with milliseconds resolution. */
/* Pubsub */ /* Pubsub */
...@@ -958,15 +970,13 @@ typedef struct { ...@@ -958,15 +970,13 @@ typedef struct {
robj *subject; robj *subject;
unsigned char encoding; unsigned char encoding;
unsigned char direction; /* Iteration direction */ unsigned char direction; /* Iteration direction */
unsigned char *zi; quicklistIter *iter;
listNode *ln;
} listTypeIterator; } listTypeIterator;
/* Structure for an entry while iterating over a list. */ /* Structure for an entry while iterating over a list. */
typedef struct { typedef struct {
listTypeIterator *li; listTypeIterator *li;
unsigned char *zi; /* Entry in ziplist */ quicklistEntry entry; /* Entry in quicklist */
listNode *ln; /* Entry in linked list */
} listTypeEntry; } listTypeEntry;
/* Structure to hold set iteration abstraction. */ /* Structure to hold set iteration abstraction. */
...@@ -1043,6 +1053,7 @@ void addReplyBulkCBuffer(redisClient *c, void *p, size_t len); ...@@ -1043,6 +1053,7 @@ void addReplyBulkCBuffer(redisClient *c, void *p, size_t len);
void addReplyBulkLongLong(redisClient *c, long long ll); void addReplyBulkLongLong(redisClient *c, long long ll);
void addReply(redisClient *c, robj *obj); void addReply(redisClient *c, robj *obj);
void addReplySds(redisClient *c, sds s); void addReplySds(redisClient *c, sds s);
void addReplyBulkSds(redisClient *c, sds s);
void addReplyError(redisClient *c, char *err); void addReplyError(redisClient *c, char *err);
void addReplyStatus(redisClient *c, char *status); void addReplyStatus(redisClient *c, char *status);
void addReplyDouble(redisClient *c, double d); void addReplyDouble(redisClient *c, double d);
...@@ -1092,7 +1103,7 @@ int listTypeNext(listTypeIterator *li, listTypeEntry *entry); ...@@ -1092,7 +1103,7 @@ int listTypeNext(listTypeIterator *li, listTypeEntry *entry);
robj *listTypeGet(listTypeEntry *entry); robj *listTypeGet(listTypeEntry *entry);
void listTypeInsert(listTypeEntry *entry, robj *value, int where); void listTypeInsert(listTypeEntry *entry, robj *value, int where);
int listTypeEqual(listTypeEntry *entry, robj *o); int listTypeEqual(listTypeEntry *entry, robj *o);
void listTypeDelete(listTypeEntry *entry); void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry);
void listTypeConvert(robj *subject, int enc); void listTypeConvert(robj *subject, int enc);
void unblockClientWaitingData(redisClient *c); void unblockClientWaitingData(redisClient *c);
void handleClientsBlockedOnLists(void); void handleClientsBlockedOnLists(void);
...@@ -1130,7 +1141,7 @@ robj *getDecodedObject(robj *o); ...@@ -1130,7 +1141,7 @@ robj *getDecodedObject(robj *o);
size_t stringObjectLen(robj *o); size_t stringObjectLen(robj *o);
robj *createStringObjectFromLongLong(long long value); robj *createStringObjectFromLongLong(long long value);
robj *createStringObjectFromLongDouble(long double value, int humanfriendly); robj *createStringObjectFromLongDouble(long double value, int humanfriendly);
robj *createListObject(void); robj *createQuicklistObject(void);
robj *createZiplistObject(void); robj *createZiplistObject(void);
robj *createSetObject(void); robj *createSetObject(void);
robj *createIntsetObject(void); robj *createIntsetObject(void);
......
...@@ -88,6 +88,17 @@ void sdsfree(sds s) { ...@@ -88,6 +88,17 @@ void sdsfree(sds s) {
zfree(s-sizeof(struct sdshdr)); zfree(s-sizeof(struct sdshdr));
} }
/* Remove sds header so we can use buffer as malloc'd byte array.
* Returns the contents of 's' usable as a full malloc'd C string. */
char *sdsnative(sds s) {
if (!s) return NULL;
size_t len = sdslen(s);
char *base = s-sizeof(struct sdshdr);
memmove(base, s, len);
return zrealloc(base, len);
}
/* Set the sds string length to the length as obtained with strlen(), so /* Set the sds string length to the length as obtained with strlen(), so
* considering as content only up to the first null term character. * considering as content only up to the first null term character.
* *
...@@ -962,12 +973,15 @@ sds sdsjoin(char **argv, int argc, char *sep) { ...@@ -962,12 +973,15 @@ sds sdsjoin(char **argv, int argc, char *sep) {
return join; return join;
} }
#ifdef SDS_TEST_MAIN #if defined(REDIS_TEST) || defined(SDS_TEST_MAIN)
#include <stdio.h> #include <stdio.h>
#include "testhelp.h" #include "testhelp.h"
#include "limits.h" #include "limits.h"
int main(void) { #define UNUSED(x) (void)(x)
int sdsTest(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);
{ {
struct sdshdr *sh; struct sdshdr *sh;
sds x = sdsnew("foo"), y; sds x = sdsnew("foo"), y;
...@@ -1092,7 +1106,7 @@ int main(void) { ...@@ -1092,7 +1106,7 @@ int main(void) {
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
{ {
int oldfree; unsigned int oldfree;
sdsfree(x); sdsfree(x);
x = sdsnew("0"); x = sdsnew("0");
...@@ -1113,3 +1127,9 @@ int main(void) { ...@@ -1113,3 +1127,9 @@ int main(void) {
return 0; return 0;
} }
#endif #endif
#ifdef SDS_TEST_MAIN
int main(void) {
return sdsTest();
}
#endif
...@@ -60,6 +60,7 @@ sds sdsempty(void); ...@@ -60,6 +60,7 @@ sds sdsempty(void);
size_t sdslen(const sds s); size_t sdslen(const sds s);
sds sdsdup(const sds s); sds sdsdup(const sds s);
void sdsfree(sds s); void sdsfree(sds s);
char *sdsnative(sds s);
size_t sdsavail(const sds s); size_t sdsavail(const sds s);
sds sdsgrowzero(sds s, size_t len); sds sdsgrowzero(sds s, size_t len);
sds sdscatlen(sds s, const void *t, size_t len); sds sdscatlen(sds s, const void *t, size_t len);
...@@ -98,4 +99,8 @@ void sdsIncrLen(sds s, int incr); ...@@ -98,4 +99,8 @@ void sdsIncrLen(sds s, int incr);
sds sdsRemoveFreeSpace(sds s); sds sdsRemoveFreeSpace(sds s);
size_t sdsAllocSize(sds s); size_t sdsAllocSize(sds s);
#ifdef REDIS_TEST
int sdsTest(int argc, char *argv[]);
#endif
#endif #endif
...@@ -577,7 +577,7 @@ void sentinelEvent(int level, char *type, sentinelRedisInstance *ri, ...@@ -577,7 +577,7 @@ void sentinelEvent(int level, char *type, sentinelRedisInstance *ri,
if (level == REDIS_WARNING && ri != NULL) { if (level == REDIS_WARNING && ri != NULL) {
sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ? sentinelRedisInstance *master = (ri->flags & SRI_MASTER) ?
ri : ri->master; ri : ri->master;
if (master->notification_script) { if (master && master->notification_script) {
sentinelScheduleScriptExecution(master->notification_script, sentinelScheduleScriptExecution(master->notification_script,
type,msg,NULL); type,msg,NULL);
} }
...@@ -2908,10 +2908,7 @@ void sentinelInfoCommand(redisClient *c) { ...@@ -2908,10 +2908,7 @@ void sentinelInfoCommand(redisClient *c) {
dictReleaseIterator(di); dictReleaseIterator(di);
} }
addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n", addReplyBulkSds(c, info);
(unsigned long)sdslen(info)));
addReplySds(c,info);
addReply(c,shared.crlf);
} }
/* Implements Sentinel verison of the ROLE command. The output is /* Implements Sentinel verison of the ROLE command. The output is
......
...@@ -199,16 +199,19 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context) ...@@ -199,16 +199,19 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
} }
/* ================ end of sha1.c ================ */ /* ================ end of sha1.c ================ */
#if 0 #ifdef REDIS_TEST
#define BUFSIZE 4096 #define BUFSIZE 4096
int #define UNUSED(x) (void)(x)
main(int argc, char **argv) int sha1Test(int argc, char **argv)
{ {
SHA1_CTX ctx; SHA1_CTX ctx;
unsigned char hash[20], buf[BUFSIZE]; unsigned char hash[20], buf[BUFSIZE];
int i; int i;
UNUSED(argc);
UNUSED(argv);
for(i=0;i<BUFSIZE;i++) for(i=0;i<BUFSIZE;i++)
buf[i] = i; buf[i] = i;
...@@ -223,6 +226,4 @@ main(int argc, char **argv) ...@@ -223,6 +226,4 @@ main(int argc, char **argv)
printf("\n"); printf("\n");
return 0; return 0;
} }
#endif #endif
#ifndef SHA1_H
#define SHA1_H
/* ================ sha1.h ================ */ /* ================ sha1.h ================ */
/* /*
SHA-1 in C SHA-1 in C
...@@ -15,3 +17,8 @@ void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]); ...@@ -15,3 +17,8 @@ void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context); void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len); void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context); void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
#ifdef REDIS_TEST
int sha1Test(int argc, char **argv);
#endif
#endif
...@@ -220,7 +220,7 @@ void sortCommand(redisClient *c) { ...@@ -220,7 +220,7 @@ void sortCommand(redisClient *c) {
if (sortval) if (sortval)
incrRefCount(sortval); incrRefCount(sortval);
else else
sortval = createListObject(); sortval = createQuicklistObject();
/* The SORT command has an SQL-alike syntax, parse it */ /* The SORT command has an SQL-alike syntax, parse it */
while(j < c->argc) { while(j < c->argc) {
...@@ -420,6 +420,7 @@ void sortCommand(redisClient *c) { ...@@ -420,6 +420,7 @@ void sortCommand(redisClient *c) {
} else { } else {
redisPanic("Unknown type"); redisPanic("Unknown type");
} }
printf("j: %d; vectorlen: %d\n", j, vectorlen);
redisAssertWithInfo(c,sortval,j == vectorlen); redisAssertWithInfo(c,sortval,j == vectorlen);
/* Now it's time to load the right scores in the sorting vector */ /* Now it's time to load the right scores in the sorting vector */
...@@ -509,7 +510,7 @@ void sortCommand(redisClient *c) { ...@@ -509,7 +510,7 @@ void sortCommand(redisClient *c) {
} }
} }
} else { } else {
robj *sobj = createZiplistObject(); robj *sobj = createQuicklistObject();
/* STORE option specified, set the sorting result as a List object */ /* STORE option specified, set the sorting result as a List object */
for (j = start; j <= end; j++) { for (j = start; j <= end; j++) {
......
This diff is collapsed.
...@@ -1382,7 +1382,7 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) { ...@@ -1382,7 +1382,7 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) {
robj *key = c->argv[1]; robj *key = c->argv[1];
robj *zobj; robj *zobj;
int keyremoved = 0; int keyremoved = 0;
unsigned long deleted; unsigned long deleted = 0;
zrangespec range; zrangespec range;
zlexrangespec lexrange; zlexrangespec lexrange;
long start, end, llen; long start, end, llen;
......
...@@ -529,10 +529,10 @@ int pathIsBaseName(char *path) { ...@@ -529,10 +529,10 @@ int pathIsBaseName(char *path) {
return strchr(path,'/') == NULL && strchr(path,'\\') == NULL; return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;
} }
#ifdef UTIL_TEST_MAIN #ifdef REDIS_TEST
#include <assert.h> #include <assert.h>
void test_string2ll(void) { static void test_string2ll(void) {
char buf[32]; char buf[32];
long long v; long long v;
...@@ -587,7 +587,7 @@ void test_string2ll(void) { ...@@ -587,7 +587,7 @@ void test_string2ll(void) {
assert(string2ll(buf,strlen(buf),&v) == 0); assert(string2ll(buf,strlen(buf),&v) == 0);
} }
void test_string2l(void) { static void test_string2l(void) {
char buf[32]; char buf[32];
long v; long v;
...@@ -636,9 +636,55 @@ void test_string2l(void) { ...@@ -636,9 +636,55 @@ void test_string2l(void) {
#endif #endif
} }
int main(int argc, char **argv) { static void test_ll2string(void) {
char buf[32];
long long v;
int sz;
v = 0;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 1);
assert(!strcmp(buf, "0"));
v = -1;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 2);
assert(!strcmp(buf, "-1"));
v = 99;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 2);
assert(!strcmp(buf, "99"));
v = -99;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 3);
assert(!strcmp(buf, "-99"));
v = -2147483648;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 11);
assert(!strcmp(buf, "-2147483648"));
v = LLONG_MIN;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 20);
assert(!strcmp(buf, "-9223372036854775808"));
v = LLONG_MAX;
sz = ll2string(buf, sizeof buf, v);
assert(sz == 19);
assert(!strcmp(buf, "9223372036854775807"));
}
#define UNUSED(x) (void)(x)
int utilTest(int argc, char **argv) {
UNUSED(argc);
UNUSED(argv);
test_string2ll(); test_string2ll();
test_string2l(); test_string2l();
test_ll2string();
return 0; return 0;
} }
#endif #endif
...@@ -42,4 +42,8 @@ int d2string(char *buf, size_t len, double value); ...@@ -42,4 +42,8 @@ int d2string(char *buf, size_t len, double value);
sds getAbsolutePath(char *filename); sds getAbsolutePath(char *filename);
int pathIsBaseName(char *path); int pathIsBaseName(char *path);
#ifdef REDIS_TEST
int utilTest(int argc, char **argv);
#endif
#endif #endif
This diff is collapsed.
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define ZIPLIST_TAIL 1 #define ZIPLIST_TAIL 1
unsigned char *ziplistNew(void); unsigned char *ziplistNew(void);
unsigned char *ziplistMerge(unsigned char **first, unsigned char **second);
unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where); unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where);
unsigned char *ziplistIndex(unsigned char *zl, int index); unsigned char *ziplistIndex(unsigned char *zl, int index);
unsigned char *ziplistNext(unsigned char *zl, unsigned char *p); unsigned char *ziplistNext(unsigned char *zl, unsigned char *p);
...@@ -39,8 +40,12 @@ unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p); ...@@ -39,8 +40,12 @@ unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p);
unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, long long *lval); unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, long long *lval);
unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen); unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p); unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p);
unsigned char *ziplistDeleteRange(unsigned char *zl, unsigned int index, unsigned int num); unsigned char *ziplistDeleteRange(unsigned char *zl, int index, unsigned int num);
unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen); unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip); unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip);
unsigned int ziplistLen(unsigned char *zl); unsigned int ziplistLen(unsigned char *zl);
size_t ziplistBlobLen(unsigned char *zl); size_t ziplistBlobLen(unsigned char *zl);
#ifdef REDIS_TEST
int ziplistTest(int argc, char *argv[]);
#endif
...@@ -370,8 +370,8 @@ size_t zipmapBlobLen(unsigned char *zm) { ...@@ -370,8 +370,8 @@ size_t zipmapBlobLen(unsigned char *zm) {
return totlen; return totlen;
} }
#ifdef ZIPMAP_TEST_MAIN #ifdef REDIS_TEST
void zipmapRepr(unsigned char *p) { static void zipmapRepr(unsigned char *p) {
unsigned int l; unsigned int l;
printf("{status %u}",*p++); printf("{status %u}",*p++);
...@@ -404,9 +404,13 @@ void zipmapRepr(unsigned char *p) { ...@@ -404,9 +404,13 @@ void zipmapRepr(unsigned char *p) {
printf("\n"); printf("\n");
} }
int main(void) { #define UNUSED(x) (void)(x)
int zipmapTest(int argc, char *argv[]) {
unsigned char *zm; unsigned char *zm;
UNUSED(argc);
UNUSED(argv);
zm = zipmapNew(); zm = zipmapNew();
zm = zipmapSet(zm,(unsigned char*) "name",4, (unsigned char*) "foo",3,NULL); zm = zipmapSet(zm,(unsigned char*) "name",4, (unsigned char*) "foo",3,NULL);
......
...@@ -46,4 +46,8 @@ unsigned int zipmapLen(unsigned char *zm); ...@@ -46,4 +46,8 @@ unsigned int zipmapLen(unsigned char *zm);
size_t zipmapBlobLen(unsigned char *zm); size_t zipmapBlobLen(unsigned char *zm);
void zipmapRepr(unsigned char *p); void zipmapRepr(unsigned char *p);
#ifdef REDIS_TEST
int zipmapTest(int argc, char *argv[]);
#endif
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment