summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/aof.c16
-rw-r--r--src/cluster.c1
-rw-r--r--src/cluster.h2
-rw-r--r--src/db.c40
-rw-r--r--src/expire.c9
-rw-r--r--src/networking.c2
-rw-r--r--src/redis-benchmark.c7
-rw-r--r--src/redis-cli.c4
-rw-r--r--src/server.c8
-rw-r--r--src/server.h4
-rw-r--r--src/slowlog.c15
-rw-r--r--src/slowlog.h6
-rw-r--r--tests/unit/expire.tcl15
-rw-r--r--tests/unit/slowlog.tcl13
-rw-r--r--utils/create-cluster/README8
15 files changed, 124 insertions, 26 deletions
diff --git a/src/aof.c b/src/aof.c
index 9b15ad1d0..0593b2707 100644
--- a/src/aof.c
+++ b/src/aof.c
@@ -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. */
diff --git a/src/db.c b/src/db.c
index 86dabac8f..7d1504d30 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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.