mirror of
https://github.com/fluencelabs/redis
synced 2025-06-25 23:11:33 +00:00
support for write operations against expiring keys, by master-controlled expiring in replication and AOF synthesizing DEL operations
This commit is contained in:
51
src/db.c
51
src/db.c
@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user