DB API refactoring. The changes were designed together with Pieter Noordhuis.

This commit is contained in:
antirez 2011-06-14 15:34:27 +02:00
parent 3e2a0bf44a
commit f85cd526c1
7 changed files with 75 additions and 81 deletions

View File

@ -1390,7 +1390,7 @@ void restoreCommand(redisClient *c) {
long ttl; long ttl;
/* Make sure this key does not already exist here... */ /* Make sure this key does not already exist here... */
if (dbExists(c->db,c->argv[1])) { if (lookupKeyWrite(c->db,c->argv[1]) != NULL) {
addReplyError(c,"Target key name is busy."); addReplyError(c,"Target key name is busy.");
return; return;
} }

View File

@ -86,8 +86,7 @@ robj *lookupKey(redisDb *db, robj *key) {
redisLog(REDIS_DEBUG,"Force loading key %s via lookup", key->ptr); redisLog(REDIS_DEBUG,"Force loading key %s via lookup", key->ptr);
val = dsGet(db,key,&expire); val = dsGet(db,key,&expire);
if (val) { if (val) {
int retval = dbAdd(db,key,val); dbAdd(db,key,val);
redisAssert(retval == REDIS_OK);
if (expire != -1) setExpire(db,key,expire); if (expire != -1) setExpire(db,key,expire);
server.stat_keyspace_hits++; server.stat_keyspace_hits++;
return val; return val;
@ -122,42 +121,47 @@ robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {
return o; return o;
} }
/* Add the key to the DB. If the key already exists REDIS_ERR is returned, /* Add the key to the DB. It's up to the caller to increment the reference
* otherwise REDIS_OK is returned, and the caller should increment the * counte of the value if needed.
* refcount of 'val'. */ *
int dbAdd(redisDb *db, robj *key, robj *val) { * The program is aborted if the key already exists. */
/* Perform a lookup before adding the key, as we need to copy the void dbAdd(redisDb *db, robj *key, robj *val) {
* key value. */ sds copy = sdsdup(key->ptr);
if (dictFind(db->dict, key->ptr) != NULL) { int retval = dictAdd(db->dict, copy, val);
return REDIS_ERR;
} else { redisAssert(retval == REDIS_OK);
sds copy = sdsdup(key->ptr); if (server.ds_enabled) cacheSetKeyMayExist(db,key);
dictAdd(db->dict, copy, val); if (server.cluster_enabled) SlotToKeyAdd(key);
if (server.ds_enabled) cacheSetKeyMayExist(db,key); }
if (server.cluster_enabled) SlotToKeyAdd(key);
return REDIS_OK; /* Overwrite an existing key with a new value. Incrementing the reference
} * count of the new value is up to the caller.
* This function does not modify the expire time of the existing key.
*
* The program is aborted if the key was not already present. */
void dbOverwrite(redisDb *db, robj *key, robj *val) {
struct dictEntry *de = dictFind(db->dict,key->ptr);
redisAssert(de != NULL);
dictReplace(db->dict, key->ptr, val);
if (server.ds_enabled) cacheSetKeyMayExist(db,key);
} }
/* If the key does not exist, this is just like dbAdd(). Otherwise /* High level Set operation. This function can be used in order to set
* the value associated to the key is replaced with the new one. * a key, whatever it was existing or not, to a new object.
* *
* On update (key already existed) 0 is returned. Otherwise 1. */ * 1) The ref count of the value object is incremented.
int dbReplace(redisDb *db, robj *key, robj *val) { * 2) clients WATCHing for the destination key notified.
robj *oldval; * 3) The expire time of the key is reset (the key is made persistent). */
int retval; void setKey(redisDb *db, robj *key, robj *val) {
if (lookupKeyWrite(db,key) == NULL) {
if ((oldval = dictFetchValue(db->dict,key->ptr)) == NULL) { dbAdd(db,key,val);
sds copy = sdsdup(key->ptr);
dictAdd(db->dict, copy, val);
if (server.cluster_enabled) SlotToKeyAdd(key);
retval = 1;
} else { } else {
dictReplace(db->dict, key->ptr, val); dbOverwrite(db,key,val);
retval = 0;
} }
if (server.ds_enabled) cacheSetKeyMayExist(db,key); incrRefCount(val);
return retval; removeExpire(db,key);
touchWatchedKey(db,key);
} }
int dbExists(redisDb *db, robj *key) { int dbExists(redisDb *db, robj *key) {
@ -414,13 +418,15 @@ void renameGenericCommand(redisClient *c, int nx) {
return; return;
incrRefCount(o); incrRefCount(o);
if (dbAdd(c->db,c->argv[2],o) == REDIS_ERR) { if (lookupKeyWrite(c->db,c->argv[2]) != NULL) {
if (nx) { if (nx) {
decrRefCount(o); decrRefCount(o);
addReply(c,shared.czero); addReply(c,shared.czero);
return; return;
} }
dbReplace(c->db,c->argv[2],o); dbOverwrite(c->db,c->argv[2],o);
} else {
dbAdd(c->db,c->argv[2],o);
} }
dbDelete(c->db,c->argv[1]); dbDelete(c->db,c->argv[1]);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
@ -471,11 +477,12 @@ void moveCommand(redisClient *c) {
return; return;
} }
/* Try to add the element to the target DB */ /* Return zero if the key already exists in the target DB */
if (dbAdd(dst,c->argv[1],o) == REDIS_ERR) { if (lookupKeyWrite(dst,c->argv[1]) != NULL) {
addReply(c,shared.czero); addReply(c,shared.czero);
return; return;
} }
dbAdd(dst,c->argv[1],o);
incrRefCount(o); incrRefCount(o);
/* OK! key moved, free the entry in the source DB */ /* OK! key moved, free the entry in the source DB */

View File

@ -362,7 +362,8 @@ void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
if (j->val != NULL) { if (j->val != NULL) {
/* Note: it's possible that the key is already in memory /* Note: it's possible that the key is already in memory
* due to a blocking load operation. */ * due to a blocking load operation. */
if (dbAdd(j->db,j->key,j->val) == REDIS_OK) { if (dictFind(j->db->dict,j->key->ptr) == NULL) {
dbAdd(j->db,j->key,j->val);
incrRefCount(j->val); incrRefCount(j->val);
if (j->expire != -1) setExpire(j->db,j->key,j->expire); if (j->expire != -1) setExpire(j->db,j->key,j->expire);
} }

View File

@ -918,7 +918,7 @@ void stopLoading(void) {
int rdbLoad(char *filename) { int rdbLoad(char *filename) {
FILE *fp; FILE *fp;
uint32_t dbid; uint32_t dbid;
int type, retval, rdbver; int type, rdbver;
redisDb *db = server.db+0; redisDb *db = server.db+0;
char buf[1024]; char buf[1024];
time_t expiretime, now = time(NULL); time_t expiretime, now = time(NULL);
@ -981,11 +981,8 @@ int rdbLoad(char *filename) {
continue; continue;
} }
/* Add the new object in the hash table */ /* Add the new object in the hash table */
retval = dbAdd(db,key,val); dbAdd(db,key,val);
if (retval == REDIS_ERR) {
redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", key->ptr);
exit(1);
}
/* Set the expire time if needed */ /* Set the expire time if needed */
if (expiretime != -1) setExpire(db,key,expiretime); if (expiretime != -1) setExpire(db,key,expiretime);

View File

@ -1058,8 +1058,9 @@ robj *lookupKeyRead(redisDb *db, robj *key);
robj *lookupKeyWrite(redisDb *db, robj *key); robj *lookupKeyWrite(redisDb *db, robj *key);
robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply); robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply);
robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply); robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply);
int dbAdd(redisDb *db, robj *key, robj *val); void dbAdd(redisDb *db, robj *key, robj *val);
int dbReplace(redisDb *db, robj *key, robj *val); void dbOverwrite(redisDb *db, robj *key, robj *val);
void setKey(redisDb *db, robj *key, robj *val);
int dbExists(redisDb *db, robj *key); int dbExists(redisDb *db, robj *key);
robj *dbRandomKey(redisDb *db); robj *dbRandomKey(redisDb *db);
int dbDelete(redisDb *db, robj *key); int dbDelete(redisDb *db, robj *key);

View File

@ -366,12 +366,12 @@ void sortCommand(redisClient *c) {
} }
} }
} }
dbReplace(c->db,storekey,sobj); setKey(c->db,storekey,sobj);
decrRefCount(sobj);
/* Note: we add 1 because the DB is dirty anyway since even if the /* Note: we add 1 because the DB is dirty anyway since even if the
* SORT result is empty a new key is set and maybe the old content * SORT result is empty a new key is set and maybe the old content
* replaced. */ * replaced. */
server.dirty += 1+outputlen; server.dirty += 1+outputlen;
signalModifiedKey(c->db,storekey);
addReplyLongLong(c,outputlen); addReplyLongLong(c,outputlen);
} }

View File

@ -13,7 +13,6 @@ static int checkStringLength(redisClient *c, long long size) {
} }
void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) { void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
int retval;
long seconds = 0; /* initialized to avoid an harmness warning */ long seconds = 0; /* initialized to avoid an harmness warning */
if (expire) { if (expire) {
@ -25,21 +24,12 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
} }
} }
retval = dbAdd(c->db,key,val); if (lookupKeyWrite(c->db,key) != NULL && nx) {
if (retval == REDIS_ERR) { addReply(c,shared.czero);
if (!nx) { return;
dbReplace(c->db,key,val);
incrRefCount(val);
} else {
addReply(c,shared.czero);
return;
}
} else {
incrRefCount(val);
} }
signalModifiedKey(c->db,key); setKey(c->db,key,val);
server.dirty++; server.dirty++;
removeExpire(c->db,key);
if (expire) setExpire(c->db,key,time(NULL)+seconds); if (expire) setExpire(c->db,key,time(NULL)+seconds);
addReply(c, nx ? shared.cone : shared.ok); addReply(c, nx ? shared.cone : shared.ok);
} }
@ -81,9 +71,7 @@ void getCommand(redisClient *c) {
void getsetCommand(redisClient *c) { void getsetCommand(redisClient *c) {
if (getGenericCommand(c) == REDIS_ERR) return; if (getGenericCommand(c) == REDIS_ERR) return;
c->argv[2] = tryObjectEncoding(c->argv[2]); c->argv[2] = tryObjectEncoding(c->argv[2]);
dbReplace(c->db,c->argv[1],c->argv[2]); setKey(c->db,c->argv[1],c->argv[2]);
incrRefCount(c->argv[2]);
signalModifiedKey(c->db,c->argv[1]);
server.dirty++; server.dirty++;
removeExpire(c->db,c->argv[1]); removeExpire(c->db,c->argv[1]);
} }
@ -138,7 +126,7 @@ void setbitCommand(redisClient *c) {
robj *decoded = getDecodedObject(o); robj *decoded = getDecodedObject(o);
o = createStringObject(decoded->ptr, sdslen(decoded->ptr)); o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded); decrRefCount(decoded);
dbReplace(c->db,c->argv[1],o); dbOverwrite(c->db,c->argv[1],o);
} }
} }
@ -236,7 +224,7 @@ void setrangeCommand(redisClient *c) {
robj *decoded = getDecodedObject(o); robj *decoded = getDecodedObject(o);
o = createStringObject(decoded->ptr, sdslen(decoded->ptr)); o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded); decrRefCount(decoded);
dbReplace(c->db,c->argv[1],o); dbOverwrite(c->db,c->argv[1],o);
} }
} }
@ -319,18 +307,15 @@ void msetGenericCommand(redisClient *c, int nx) {
busykeys++; busykeys++;
} }
} }
} if (busykeys) {
if (busykeys) { addReply(c, shared.czero);
addReply(c, shared.czero); return;
return; }
} }
for (j = 1; j < c->argc; j += 2) { for (j = 1; j < c->argc; j += 2) {
c->argv[j+1] = tryObjectEncoding(c->argv[j+1]); c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
dbReplace(c->db,c->argv[j],c->argv[j+1]); setKey(c->db,c->argv[j],c->argv[j+1]);
incrRefCount(c->argv[j+1]);
removeExpire(c->db,c->argv[j]);
signalModifiedKey(c->db,c->argv[j]);
} }
server.dirty += (c->argc-1)/2; server.dirty += (c->argc-1)/2;
addReply(c, nx ? shared.cone : shared.ok); addReply(c, nx ? shared.cone : shared.ok);
@ -346,7 +331,7 @@ void msetnxCommand(redisClient *c) {
void incrDecrCommand(redisClient *c, long long incr) { void incrDecrCommand(redisClient *c, long long incr) {
long long value, oldvalue; long long value, oldvalue;
robj *o; robj *o, *new;
o = lookupKeyWrite(c->db,c->argv[1]); o = lookupKeyWrite(c->db,c->argv[1]);
if (o != NULL && checkType(c,o,REDIS_STRING)) return; if (o != NULL && checkType(c,o,REDIS_STRING)) return;
@ -358,12 +343,15 @@ void incrDecrCommand(redisClient *c, long long incr) {
addReplyError(c,"increment or decrement would overflow"); addReplyError(c,"increment or decrement would overflow");
return; return;
} }
o = createStringObjectFromLongLong(value); new = createStringObjectFromLongLong(value);
dbReplace(c->db,c->argv[1],o); if (o)
dbOverwrite(c->db,c->argv[1],new);
else
dbAdd(c->db,c->argv[1],new);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
server.dirty++; server.dirty++;
addReply(c,shared.colon); addReply(c,shared.colon);
addReply(c,o); addReply(c,new);
addReply(c,shared.crlf); addReply(c,shared.crlf);
} }
@ -416,7 +404,7 @@ void appendCommand(redisClient *c) {
robj *decoded = getDecodedObject(o); robj *decoded = getDecodedObject(o);
o = createStringObject(decoded->ptr, sdslen(decoded->ptr)); o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded); decrRefCount(decoded);
dbReplace(c->db,c->argv[1],o); dbOverwrite(c->db,c->argv[1],o);
} }
/* Append the value */ /* Append the value */