support for write operations against expiring keys, by master-controlled expiring in replication and AOF synthesizing DEL operations

This commit is contained in:
antirez
2010-08-02 18:13:39 +02:00
parent 0c7a9dec65
commit bcf2995c98
4 changed files with 86 additions and 49 deletions

View File

@ -45,7 +45,7 @@ robj *lookupKeyRead(redisDb *db, robj *key) {
}
robj *lookupKeyWrite(redisDb *db, robj *key) {
deleteIfVolatile(db,key);
expireIfNeeded(db,key);
return lookupKey(db,key);
}
@ -321,7 +321,6 @@ void renameGenericCommand(redisClient *c, int nx) {
return;
incrRefCount(o);
deleteIfVolatile(c->db,c->argv[2]);
if (dbAdd(c->db,c->argv[2],o) == REDIS_ERR) {
if (nx) {
decrRefCount(o);
@ -375,7 +374,6 @@ void moveCommand(redisClient *c) {
}
/* Try to add the element to the target DB */
deleteIfVolatile(dst,c->argv[1]);
if (dbAdd(dst,c->argv[1],o) == REDIS_ERR) {
addReply(c,shared.czero);
return;
@ -430,8 +428,45 @@ time_t getExpire(redisDb *db, robj *key) {
return (time_t) dictGetEntryVal(de);
}
/* Propagate expires into slaves and the AOF file.
* When a key expires in the master, a DEL operation for this key is sent
* to all the slaves and the AOF file if enabled.
*
* This way the key expiry is centralized in one place, and since both
* AOF and the master->slave link guarantee operation ordering, everything
* will be consistent even if we allow write operations against expiring
* keys. */
void propagateExpire(redisDb *db, robj *key) {
struct redisCommand *cmd;
robj *argv[2];
cmd = lookupCommand("del");
argv[0] = createStringObject("DEL",3);
argv[1] = key;
incrRefCount(key);
if (server.appendonly)
feedAppendOnlyFile(cmd,db->id,argv,2);
if (listLength(server.slaves))
replicationFeedSlaves(server.slaves,db->id,argv,2);
decrRefCount(key);
}
int expireIfNeeded(redisDb *db, robj *key) {
time_t when = getExpire(db,key);
/* If we are running in the context of a slave, return ASAP:
* the slave key expiration is controlled by the master that will
* send us synthesized DEL operations for expired keys.
*
* Still we try to return the right information to the caller,
* that is, 0 if we think the key should be still valid, 1 if
* we think the key is expired at this time. */
if (server.masterhost != NULL) {
return time(NULL) > when;
}
if (when < 0) return 0;
/* Return when this key has not expired */
@ -440,15 +475,7 @@ int expireIfNeeded(redisDb *db, robj *key) {
/* Delete the key */
server.stat_expiredkeys++;
server.dirty++;
return dbDelete(db,key);
}
int deleteIfVolatile(redisDb *db, robj *key) {
if (getExpire(db,key) < 0) return 0;
/* Delete the key */
server.stat_expiredkeys++;
server.dirty++;
propagateExpire(db,key);
return dbDelete(db,key);
}