diff options
-rw-r--r-- | src/aof.c | 16 | ||||
-rw-r--r-- | src/cluster.c | 1 | ||||
-rw-r--r-- | src/cluster.h | 2 | ||||
-rw-r--r-- | src/db.c | 40 | ||||
-rw-r--r-- | src/expire.c | 9 | ||||
-rw-r--r-- | src/networking.c | 2 | ||||
-rw-r--r-- | src/redis-benchmark.c | 7 | ||||
-rw-r--r-- | src/redis-cli.c | 4 | ||||
-rw-r--r-- | src/server.c | 8 | ||||
-rw-r--r-- | src/server.h | 4 | ||||
-rw-r--r-- | src/slowlog.c | 15 | ||||
-rw-r--r-- | src/slowlog.h | 6 | ||||
-rw-r--r-- | tests/unit/expire.tcl | 15 | ||||
-rw-r--r-- | tests/unit/slowlog.tcl | 13 | ||||
-rw-r--r-- | utils/create-cluster/README | 8 |
15 files changed, 124 insertions, 26 deletions
@@ -536,6 +536,22 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a buf = catAppendOnlyGenericCommand(buf,3,tmpargv); decrRefCount(tmpargv[0]); buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]); + } else if (cmd->proc == setCommand && argc > 3) { + int i; + robj *exarg = NULL, *pxarg = NULL; + /* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */ + buf = catAppendOnlyGenericCommand(buf,3,argv); + for (i = 3; i < argc; i ++) { + if (!strcasecmp(argv[i]->ptr, "ex")) exarg = argv[i+1]; + if (!strcasecmp(argv[i]->ptr, "px")) pxarg = argv[i+1]; + } + serverAssert(!(exarg && pxarg)); + if (exarg) + buf = catAppendOnlyExpireAtCommand(buf,server.expireCommand,argv[1], + exarg); + if (pxarg) + buf = catAppendOnlyExpireAtCommand(buf,server.pexpireCommand,argv[1], + pxarg); } else { /* All the other commands don't need translation or need the * same translation already operated in the command vector diff --git a/src/cluster.c b/src/cluster.c index d5ad85fe7..77ec2f1b1 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -37,7 +37,6 @@ #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> -#include <sys/socket.h> #include <sys/stat.h> #include <sys/file.h> #include <math.h> diff --git a/src/cluster.h b/src/cluster.h index 5e228c0f9..af85841c9 100644 --- a/src/cluster.h +++ b/src/cluster.h @@ -232,7 +232,7 @@ union clusterMsgData { typedef struct { char sig[4]; /* Siganture "RCmb" (Redis Cluster message bus). */ uint32_t totlen; /* Total length of this message */ - uint16_t ver; /* Protocol version, currently set to 0. */ + uint16_t ver; /* Protocol version, currently set to 1. */ uint16_t port; /* TCP base port number. */ uint16_t type; /* Message type */ uint16_t count; /* Only used for some kind of messages. */ @@ -93,7 +93,7 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) { if (expireIfNeeded(db,key) == 1) { /* Key expired. If we are in the context of a master, expireIfNeeded() - * returns 0 only when the key does not exist at all, so it's save + * returns 0 only when the key does not exist at all, so it's safe * to return NULL ASAP. */ if (server.masterhost == NULL) return NULL; @@ -1312,6 +1312,44 @@ int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkey return keys; } +/* Helper function to extract keys from following commands: + * GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC] + * [COUNT count] [STORE key] [STOREDIST key] + * GEORADIUSBYMEMBER key member radius unit ... options ... */ +int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { + int i, num, *keys; + UNUSED(cmd); + + /* Check for the presence of the stored key in the command */ + int stored_key = -1; + for (i = 5; i < argc; i++) { + char *arg = argv[i]->ptr; + /* For the case when user specifies both "store" and "storedist" options, the + * second key specified would override the first key. This behavior is kept + * the same as in georadiusCommand method. + */ + if ((!strcasecmp(arg, "store") || !strcasecmp(arg, "storedist")) && ((i+1) < argc)) { + stored_key = i+1; + i++; + } + } + num = 1 + (stored_key == -1 ? 0 : 1); + + /* Keys in the command come from two places: + * argv[1] = key, + * argv[5...n] = stored key if present + */ + keys = zmalloc(sizeof(int) * num); + + /* Add all key positions to keys[] */ + keys[0] = 1; + if(num > 1) { + keys[1] = stored_key; + } + *numkeys = num; + return keys; +} + /* Slot to Key API. This is used by Redis Cluster in order to obtain in * a fast way a key that belongs to a specified hash slot. This is useful * while rehashing the cluster and in other conditions when we need to diff --git a/src/expire.c b/src/expire.c index 0e258ecbb..14da78ec3 100644 --- a/src/expire.c +++ b/src/expire.c @@ -481,18 +481,15 @@ void pttlCommand(client *c) { /* PERSIST key */ void persistCommand(client *c) { - dictEntry *de; - - de = dictFind(c->db->dict,c->argv[1]->ptr); - if (de == NULL) { - addReply(c,shared.czero); - } else { + if (lookupKeyWrite(c->db,c->argv[1])) { if (removeExpire(c->db,c->argv[1])) { addReply(c,shared.cone); server.dirty++; } else { addReply(c,shared.czero); } + } else { + addReply(c,shared.czero); } } diff --git a/src/networking.c b/src/networking.c index efaca1bc6..ec591245e 100644 --- a/src/networking.c +++ b/src/networking.c @@ -937,11 +937,11 @@ int writeToClient(int fd, client *c, int handler_installed) { * * However if we are over the maxmemory limit we ignore that and * just deliver as much data as it is possible to deliver. */ - server.stat_net_output_bytes += totwritten; if (totwritten > NET_MAX_WRITES_PER_EVENT && (server.maxmemory == 0 || zmalloc_used_memory() < server.maxmemory)) break; } + server.stat_net_output_bytes += totwritten; if (nwritten == -1) { if (errno == EAGAIN) { nwritten = 0; diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index f382019a4..be15b2417 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -779,6 +779,13 @@ int main(int argc, const char **argv) { free(cmd); } + if (test_is_selected("hset")) { + len = redisFormatCommand(&cmd, + "HSET myset:__rand_int__ element:__rand_int__ %s",data); + benchmark("HSET",cmd,len); + free(cmd); + } + if (test_is_selected("spop")) { len = redisFormatCommand(&cmd,"SPOP myset"); benchmark("SPOP",cmd,len); diff --git a/src/redis-cli.c b/src/redis-cli.c index 0cb74bf04..ee24cf3c7 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1353,7 +1353,9 @@ static void repl(void) { } elapsed = mstime()-start_time; - if (elapsed >= 500) { + if (elapsed >= 500 && + config.output == OUTPUT_STANDARD) + { printf("(%.2fs)\n",(double)elapsed/1000); } } diff --git a/src/server.c b/src/server.c index 9abda682b..a3c132840 100644 --- a/src/server.c +++ b/src/server.c @@ -290,8 +290,8 @@ struct redisCommand redisCommandTable[] = { {"wait",waitCommand,3,"s",0,NULL,0,0,0,0,0}, {"command",commandCommand,0,"lt",0,NULL,0,0,0,0,0}, {"geoadd",geoaddCommand,-5,"wm",0,NULL,1,1,1,0,0}, - {"georadius",georadiusCommand,-6,"w",0,NULL,1,1,1,0,0}, - {"georadiusbymember",georadiusByMemberCommand,-5,"w",0,NULL,1,1,1,0,0}, + {"georadius",georadiusCommand,-6,"w",0,georadiusGetKeys,1,1,1,0,0}, + {"georadiusbymember",georadiusByMemberCommand,-5,"w",0,georadiusGetKeys,1,1,1,0,0}, {"geohash",geohashCommand,-2,"r",0,NULL,1,1,1,0,0}, {"geopos",geoposCommand,-2,"r",0,NULL,1,1,1,0,0}, {"geodist",geodistCommand,-4,"r",0,NULL,1,1,1,0,0}, @@ -1500,6 +1500,8 @@ void initServerConfig(void) { server.rpopCommand = lookupCommandByCString("rpop"); server.sremCommand = lookupCommandByCString("srem"); server.execCommand = lookupCommandByCString("exec"); + server.expireCommand = lookupCommandByCString("expire"); + server.pexpireCommand = lookupCommandByCString("pexpire"); /* Slow log */ server.slowlog_log_slower_than = CONFIG_DEFAULT_SLOWLOG_LOG_SLOWER_THAN; @@ -2214,7 +2216,7 @@ void call(client *c, int flags) { char *latency_event = (c->cmd->flags & CMD_FAST) ? "fast-command" : "command"; latencyAddSampleIfNeeded(latency_event,duration/1000); - slowlogPushEntryIfNeeded(c->argv,c->argc,duration); + slowlogPushEntryIfNeeded(c,c->argv,c->argc,duration); } if (flags & CMD_CALL_STATS) { c->lastcmd->microseconds += duration; diff --git a/src/server.h b/src/server.h index 8403ed5ba..aaad64bdd 100644 --- a/src/server.h +++ b/src/server.h @@ -909,7 +909,8 @@ struct redisServer { off_t loading_process_events_interval_bytes; /* Fast pointers to often looked up command */ struct redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand, - *rpopCommand, *sremCommand, *execCommand; + *rpopCommand, *sremCommand, *execCommand, *expireCommand, + *pexpireCommand; /* Fields used only for stats */ time_t stat_starttime; /* Server start time */ long long stat_numcommands; /* Number of processed commands */ @@ -1730,6 +1731,7 @@ int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *num int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); +int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); /* Cluster */ void clusterInit(void); diff --git a/src/slowlog.c b/src/slowlog.c index 484cf06bf..805ee1d77 100644 --- a/src/slowlog.c +++ b/src/slowlog.c @@ -45,7 +45,7 @@ /* Create a new slowlog entry. * Incrementing the ref count of all the objects retained is up to * this function. */ -slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) { +slowlogEntry *slowlogCreateEntry(client *c, robj **argv, int argc, long long duration) { slowlogEntry *se = zmalloc(sizeof(*se)); int j, slargc = argc; @@ -81,6 +81,8 @@ slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) { se->time = time(NULL); se->duration = duration; se->id = server.slowlog_entry_id++; + se->peerid = sdsnew(getClientPeerId(c)); + se->cname = c->name ? sdsnew(c->name->ptr) : sdsempty(); return se; } @@ -95,6 +97,8 @@ void slowlogFreeEntry(void *septr) { for (j = 0; j < se->argc; j++) decrRefCount(se->argv[j]); zfree(se->argv); + sdsfree(se->peerid); + sdsfree(se->cname); zfree(se); } @@ -109,10 +113,11 @@ void slowlogInit(void) { /* Push a new entry into the slow log. * This function will make sure to trim the slow log accordingly to the * configured max length. */ -void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) { +void slowlogPushEntryIfNeeded(client *c, robj **argv, int argc, long long duration) { if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */ if (duration >= server.slowlog_log_slower_than) - listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration)); + listAddNodeHead(server.slowlog, + slowlogCreateEntry(c,argv,argc,duration)); /* Remove old entries if needed. */ while (listLength(server.slowlog) > server.slowlog_max_len) @@ -152,13 +157,15 @@ void slowlogCommand(client *c) { int j; se = ln->value; - addReplyMultiBulkLen(c,4); + addReplyMultiBulkLen(c,6); addReplyLongLong(c,se->id); addReplyLongLong(c,se->time); addReplyLongLong(c,se->duration); addReplyMultiBulkLen(c,se->argc); for (j = 0; j < se->argc; j++) addReplyBulk(c,se->argv[j]); + addReplyBulkCBuffer(c,se->peerid,sdslen(se->peerid)); + addReplyBulkCBuffer(c,se->cname,sdslen(se->cname)); sent++; } setDeferredMultiBulkLength(c,totentries,sent); diff --git a/src/slowlog.h b/src/slowlog.h index 81df0b054..655fb25f4 100644 --- a/src/slowlog.h +++ b/src/slowlog.h @@ -35,13 +35,15 @@ typedef struct slowlogEntry { robj **argv; int argc; long long id; /* Unique entry identifier. */ - long long duration; /* Time spent by the query, in nanoseconds. */ + long long duration; /* Time spent by the query, in microseconds. */ time_t time; /* Unix time at which the query was executed. */ + sds cname; /* Client name. */ + sds peerid; /* Client network address. */ } slowlogEntry; /* Exported API */ void slowlogInit(void); -void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration); +void slowlogPushEntryIfNeeded(client *c, robj **argv, int argc, long long duration); /* Exported commands */ void slowlogCommand(client *c); diff --git a/tests/unit/expire.tcl b/tests/unit/expire.tcl index 0a50dd31b..eddc7c303 100644 --- a/tests/unit/expire.tcl +++ b/tests/unit/expire.tcl @@ -204,4 +204,19 @@ start_server {tags {"expire"}} { catch {r expire foo ""} e set e } {*not an integer*} + + test {SET - use EX/PX option, TTL should not be reseted after loadaof} { + r config set appendonly yes + r set foo bar EX 100 + after 2000 + r debug loadaof + set ttl [r ttl foo] + assert {$ttl <= 98 && $ttl > 90} + + r set foo bar PX 100000 + after 2000 + r debug loadaof + set ttl [r ttl foo] + assert {$ttl <= 98 && $ttl > 90} + } } diff --git a/tests/unit/slowlog.tcl b/tests/unit/slowlog.tcl index b25b91e2c..fce02498b 100644 --- a/tests/unit/slowlog.tcl +++ b/tests/unit/slowlog.tcl @@ -31,12 +31,14 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} { } {0} test {SLOWLOG - logged entry sanity check} { + r client setname foobar r debug sleep 0.2 set e [lindex [r slowlog get] 0] - assert_equal [llength $e] 4 + assert_equal [llength $e] 6 assert_equal [lindex $e 0] 105 assert_equal [expr {[lindex $e 2] > 100000}] 1 assert_equal [lindex $e 3] {debug sleep 0.2} + assert_equal {foobar} [lindex $e 5] } test {SLOWLOG - commands with too many arguments are trimmed} { @@ -67,4 +69,13 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} { set e [lindex [r slowlog get] 0] assert_equal [lindex $e 3] {debug sleep 0.2} } + + test {SLOWLOG - can clean older entires} { + r client setname lastentry_client + r config set slowlog-max-len 1 + r debug sleep 0.2 + assert {[llength [r slowlog get]] == 1} + set e [lindex [r slowlog get] 0] + assert_equal {lastentry_client} [lindex $e 5] + } } diff --git a/utils/create-cluster/README b/utils/create-cluster/README index 1f43748ee..f2a89839b 100644 --- a/utils/create-cluster/README +++ b/utils/create-cluster/README @@ -2,7 +2,7 @@ Create-custer is a small script used to easily start a big number of Redis instances configured to run in cluster mode. Its main goal is to allow manual testing in a condition which is not easy to replicate with the Redis cluster unit tests, for example when a lot of instances are needed in order to trigger -a give bug. +a given bug. The tool can also be used just to easily create a number of instances in a Redis Cluster in order to experiment a bit with the system. @@ -10,7 +10,7 @@ Redis Cluster in order to experiment a bit with the system. USAGE --- -To create a cluster, follow this steps: +To create a cluster, follow these steps: 1. Edit create-cluster and change the start / end port, depending on the number of instances you want to create. @@ -21,7 +21,7 @@ an actual Redis cluster will be created. In order to stop a cluster: -1. Use "./craete-cluster stop" to stop all the instances. After you stopped the instances you can use "./create-cluster start" to restart them if you change ideas. -2. Use "./create-cluster clean" to remove all the AOF / log files to restat with a clean environment. +1. Use "./create-cluster stop" to stop all the instances. After you stopped the instances you can use "./create-cluster start" to restart them if you change your mind. +2. Use "./create-cluster clean" to remove all the AOF / log files to restart with a clean environment. Use the command "./create-cluster help" to get the full list of features. |