提交 12d293ca 编写于 作者: A antirez

high resolution expires API modified to use separated commands. AOF transation...

high resolution expires API modified to use separated commands. AOF transation to PEXPIREAT of all the expire-style commands fixed.
上级 dab5332f
......@@ -181,21 +181,38 @@ sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) {
return dst;
}
sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
int argc = 3;
long when;
/* Create the sds representation of an PEXPIREAT command, using
* 'seconds' as time to live and 'cmd' to understand what command
* we are translating into a PEXPIREAT.
*
* This command is used in order to translate EXPIRE and PEXPIRE commands
* into PEXPIREAT command so that we retain precision in the append only
* file, and the time is always absolute and not relative. */
sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, robj *seconds) {
long long when;
robj *argv[3];
/* Make sure we can use strtol */
seconds = getDecodedObject(seconds);
when = time(NULL)+strtol(seconds->ptr,NULL,10);
when = strtoll(seconds->ptr,NULL,10);
/* Convert argument into milliseconds for EXPIRE, SETEX, EXPIREAT */
if (cmd->proc == expireCommand || cmd->proc == setexCommand ||
cmd->proc == expireatCommand)
{
when *= 1000;
}
/* Convert into absolute time for EXPIRE, PEXPIRE, SETEX, PSETEX */
if (cmd->proc == expireCommand || cmd->proc == pexpireCommand ||
cmd->proc == setexCommand || cmd->proc == psetexCommand)
{
when += mstime();
}
decrRefCount(seconds);
argv[0] = createStringObject("EXPIREAT",8);
argv[0] = createStringObject("PEXPIREAT",9);
argv[1] = key;
argv[2] = createObject(REDIS_STRING,
sdscatprintf(sdsempty(),"%ld",when));
buf = catAppendOnlyGenericCommand(buf, argc, argv);
argv[2] = createStringObjectFromLongLong(when);
buf = catAppendOnlyGenericCommand(buf, 3, argv);
decrRefCount(argv[0]);
decrRefCount(argv[2]);
return buf;
......@@ -216,18 +233,22 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
server.appendseldb = dictid;
}
if (cmd->proc == expireCommand) {
/* Translate EXPIRE into EXPIREAT */
buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
} else if (cmd->proc == setexCommand) {
/* Translate SETEX to SET and EXPIREAT */
if (cmd->proc == expireCommand || cmd->proc == pexpireCommand ||
cmd->proc == expireatCommand) {
/* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */
buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);
} else if (cmd->proc == setexCommand || cmd->proc == psetexCommand) {
/* Translate SETEX/PSETEX to SET and PEXPIREAT */
tmpargv[0] = createStringObject("SET",3);
tmpargv[1] = argv[1];
tmpargv[2] = argv[3];
buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
decrRefCount(tmpargv[0]);
buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);
} else {
/* All the other commands don't need translation or need the
* same translation already operated in the command vector
* for the replication itself. */
buf = catAppendOnlyGenericCommand(buf,argc,argv);
}
......@@ -608,13 +629,12 @@ int rewriteAppendOnlyFile(char *filename) {
}
/* Save the expire time */
if (expiretime != -1) {
char cmd[]="*4\r\n$8\r\nEXPIREAT\r\n";
char cmd[]="*3\r\n$9\r\nPEXPIREAT\r\n";
/* If this key is already expired skip it */
if (expiretime < now) continue;
if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
if (rioWriteBulkLongLong(&aof,expiretime) == 0) goto werr;
if (rioWriteBulkString(&aof,"ms",2) == 0) goto werr;
}
}
dictReleaseIterator(di);
......
......@@ -522,25 +522,15 @@ int stringObjectEqualsMs(robj *a) {
return tolower(arg[0]) == 'm' && tolower(arg[1]) == 's' && arg[2] == '\0';
}
void expireGenericCommand(redisClient *c, long long offset) {
void expireGenericCommand(redisClient *c, long long offset, int unit) {
dictEntry *de;
robj *key = c->argv[1], *param = c->argv[2];
long long milliseconds;
int time_in_seconds = 1;
if (getLongLongFromObjectOrReply(c, param, &milliseconds, NULL) != REDIS_OK)
return;
/* If no "ms" argument was passed the time is in second, so we need
* to multilpy it by 1000 */
if (c->argc == 4) {
if (!stringObjectEqualsMs(c->argv[3])) {
addReply(c,shared.syntaxerr);
return;
}
time_in_seconds = 0; /* "ms" argument passed. */
}
if (time_in_seconds) milliseconds *= 1000;
if (unit == UNIT_SECONDS) milliseconds *= 1000;
milliseconds -= offset;
de = dictFind(c->db->dict,key->ptr);
......@@ -578,33 +568,23 @@ void expireGenericCommand(redisClient *c, long long offset) {
}
void expireCommand(redisClient *c) {
if (c->argc > 4) {
addReply(c,shared.syntaxerr);
return;
}
expireGenericCommand(c,0);
expireGenericCommand(c,0,UNIT_SECONDS);
}
void expireatCommand(redisClient *c) {
if (c->argc > 4) {
addReply(c,shared.syntaxerr);
return;
}
expireGenericCommand(c,mstime());
expireGenericCommand(c,mstime(),UNIT_SECONDS);
}
void ttlCommand(redisClient *c) {
long long expire, ttl = -1;
int output_ms = 0;
void pexpireCommand(redisClient *c) {
expireGenericCommand(c,0,UNIT_MILLISECONDS);
}
if (c->argc == 3) {
if (stringObjectEqualsMs(c->argv[2])) {
output_ms = 1;
} else {
addReply(c,shared.syntaxerr);
return;
}
}
void pexpireatCommand(redisClient *c) {
expireGenericCommand(c,mstime(),UNIT_MILLISECONDS);
}
void ttlGenericCommand(redisClient *c, int output_ms) {
long long expire, ttl = -1;
expire = getExpire(c->db,c->argv[1]);
if (expire != -1) {
......@@ -618,6 +598,14 @@ void ttlCommand(redisClient *c) {
}
}
void ttlCommand(redisClient *c) {
ttlGenericCommand(c, 0);
}
void pttlCommand(redisClient *c) {
ttlGenericCommand(c, 1);
}
void persistCommand(redisClient *c) {
dictEntry *de;
......
......@@ -91,6 +91,7 @@ struct redisCommand redisCommandTable[] = {
{"set",setCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"setnx",setnxCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,noPreloadGetKeys,2,2,1,0,0},
{"psetex",psetexCommand,4,"wm",0,noPreloadGetKeys,2,2,1,0,0},
{"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0},
{"strlen",strlenCommand,2,"r",0,NULL,1,1,1,0,0},
{"del",delCommand,-2,"w",0,noPreloadGetKeys,1,-1,1,0,0},
......@@ -172,8 +173,10 @@ struct redisCommand redisCommandTable[] = {
{"move",moveCommand,3,"w",0,NULL,1,1,1,0,0},
{"rename",renameCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
{"renamenx",renamenxCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
{"expire",expireCommand,-3,"w",0,NULL,1,1,1,0,0},
{"expireat",expireatCommand,-3,"w",0,NULL,1,1,1,0,0},
{"expire",expireCommand,3,"w",0,NULL,1,1,1,0,0},
{"expireat",expireatCommand,3,"w",0,NULL,1,1,1,0,0},
{"pexpire",pexpireCommand,3,"w",0,NULL,1,1,1,0,0},
{"pexpireat",pexpireatCommand,3,"w",0,NULL,1,1,1,0,0},
{"keys",keysCommand,2,"r",0,NULL,0,0,0,0,0},
{"dbsize",dbsizeCommand,1,"r",0,NULL,0,0,0,0,0},
{"auth",authCommand,2,"r",0,NULL,0,0,0,0,0},
......@@ -194,7 +197,8 @@ struct redisCommand redisCommandTable[] = {
{"sort",sortCommand,-2,"wm",0,NULL,1,1,1,0,0},
{"info",infoCommand,-1,"r",0,NULL,0,0,0,0,0},
{"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0},
{"ttl",ttlCommand,-2,"r",0,NULL,1,1,1,0,0},
{"ttl",ttlCommand,2,"r",0,NULL,1,1,1,0,0},
{"pttl",pttlCommand,2,"r",0,NULL,1,1,1,0,0},
{"persist",persistCommand,2,"w",0,NULL,1,1,1,0,0},
{"slaveof",slaveofCommand,3,"aws",0,NULL,0,0,0,0,0},
{"debug",debugCommand,-2,"aw",0,NULL,0,0,0,0,0},
......
......@@ -211,6 +211,10 @@
/* Scripting */
#define REDIS_LUA_TIME_LIMIT 5000 /* milliseconds */
/* Units */
#define UNIT_SECONDS 0
#define UNIT_MILLISECONDS 1
/* We can print the stacktrace, so our assert is defined this way: */
#define redisAssertWithInfo(_c,_o,_e) ((_e)?(void)0 : (_redisAssertWithInfo(_c,_o,#_e,__FILE__,__LINE__),_exit(1)))
#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
......@@ -988,6 +992,7 @@ void echoCommand(redisClient *c);
void setCommand(redisClient *c);
void setnxCommand(redisClient *c);
void setexCommand(redisClient *c);
void psetexCommand(redisClient *c);
void getCommand(redisClient *c);
void delCommand(redisClient *c);
void existsCommand(redisClient *c);
......@@ -1048,8 +1053,11 @@ void mgetCommand(redisClient *c);
void monitorCommand(redisClient *c);
void expireCommand(redisClient *c);
void expireatCommand(redisClient *c);
void pexpireCommand(redisClient *c);
void pexpireatCommand(redisClient *c);
void getsetCommand(redisClient *c);
void ttlCommand(redisClient *c);
void pttlCommand(redisClient *c);
void persistCommand(redisClient *c);
void slaveofCommand(redisClient *c);
void debugCommand(redisClient *c);
......
......@@ -12,16 +12,17 @@ static int checkStringLength(redisClient *c, long long size) {
return REDIS_OK;
}
void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
long seconds = 0; /* initialized to avoid an harmness warning */
void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire, int unit) {
long long milliseconds = 0; /* initialized to avoid an harmness warning */
if (expire) {
if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
return;
if (seconds <= 0) {
if (milliseconds <= 0) {
addReplyError(c,"invalid expire time in SETEX");
return;
}
if (unit == UNIT_SECONDS) milliseconds *= 1000;
}
if (lookupKeyWrite(c->db,key) != NULL && nx) {
......@@ -30,23 +31,28 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
setKey(c->db,key,val);
server.dirty++;
if (expire) setExpire(c->db,key,(time(NULL)+seconds)*1000);
if (expire) setExpire(c->db,key,mstime()+milliseconds);
addReply(c, nx ? shared.cone : shared.ok);
}
void setCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
setGenericCommand(c,0,c->argv[1],c->argv[2],NULL,0);
}
void setnxCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
setGenericCommand(c,1,c->argv[1],c->argv[2],NULL,0);
}
void setexCommand(redisClient *c) {
c->argv[3] = tryObjectEncoding(c->argv[3]);
setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2],UNIT_SECONDS);
}
void psetexCommand(redisClient *c) {
c->argv[3] = tryObjectEncoding(c->argv[3]);
setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2],UNIT_MILLISECONDS);
}
int getGenericCommand(redisClient *c) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册