Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
3305306f
Commit
3305306f
authored
Apr 01, 2009
by
antirez
Browse files
Initial implementation of EXPIRE
parent
300827b6
Changes
5
Show whitespace changes
Inline
Side-by-side
Makefile
View file @
3305306f
...
...
@@ -6,7 +6,7 @@ DEBUG?= -g
CFLAGS
?=
-std
=
c99
-pedantic
-O2
-Wall
-W
-DSDS_ABORT_ON_OOM
CCOPT
=
$(CFLAGS)
OBJ
=
adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o
OBJ
=
adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o
fastlz.o
BENCHOBJ
=
ae.o anet.o benchmark.o sds.o adlist.o zmalloc.o
CLIOBJ
=
anet.o sds.o adlist.o redis-cli.o zmalloc.o
...
...
TODO
View file @
3305306f
- GETSET
- Fix pure-PHP lib for the new protocol
- keys expire
- sunion ssub
- network layer stresser in test in demo
...
...
dict.h
View file @
3305306f
...
...
@@ -107,8 +107,8 @@ typedef struct dictIterator {
#define dictGetEntryKey(he) ((he)->key)
#define dictGetEntryVal(he) ((he)->val)
#define dict
GetHashTableSize
(ht) ((ht)->size)
#define dict
GetHashTableUsed
(ht) ((ht)->used)
#define dict
Slots
(ht) ((ht)->size)
#define dict
Size
(ht) ((ht)->used)
/* API */
dict
*
dictCreate
(
dictType
*
type
,
void
*
privDataPtr
);
...
...
redis-cli.c
View file @
3305306f
...
...
@@ -102,6 +102,7 @@ static struct redisCommand cmdTable[] = {
{
"sort"
,
-
2
,
REDIS_CMD_INLINE
},
{
"info"
,
1
,
REDIS_CMD_INLINE
},
{
"mget"
,
-
2
,
REDIS_CMD_INLINE
},
{
"expire"
,
3
,
REDIS_CMD_INLINE
},
{
NULL
,
0
,
0
}
};
...
...
redis.c
View file @
3305306f
...
...
@@ -158,11 +158,17 @@ typedef struct redisObject {
int refcount;
} robj;
typedef struct redisDb {
dict *dict;
dict *expires;
int id;
} redisDb;
/* With multiplexing we need to take per-clinet state.
* Clients are taken in a liked list. */
typedef struct redisClient {
int fd;
dict *dict
;
redisDb *db
;
int dictid;
sds querybuf;
robj *argv[REDIS_MAX_ARGS];
...
...
@@ -185,7 +191,7 @@ struct saveparam {
struct redisServer {
int port;
int fd;
dict **dict
;
redisDb *db
;
dict *sharingpool;
unsigned int sharingpoolsize;
long long dirty; /* changes to DB from the last save */
...
...
@@ -276,6 +282,9 @@ static robj *createStringObject(char *ptr, size_t len);
static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
static int syncWithMaster(void);
static robj *tryObjectSharing(robj *o);
static int removeExpire(redisDb *db, robj *key);
static int expireIfNeeded(redisDb *db, robj *key);
static int deleteIfVolatile(redisDb *db, robj *key);
static void authCommand(redisClient *c);
static void pingCommand(redisClient *c);
...
...
@@ -324,6 +333,7 @@ static void lremCommand(redisClient *c);
static void infoCommand(redisClient *c);
static void mgetCommand(redisClient *c);
static void monitorCommand(redisClient *c);
static void expireCommand(redisClient *c);
/*================================= Globals ================================= */
...
...
@@ -378,6 +388,7 @@ static struct redisCommand cmdTable[] = {
{"sort",sortCommand,-2,REDIS_CMD_INLINE},
{"info",infoCommand,1,REDIS_CMD_INLINE},
{"monitor",monitorCommand,1,REDIS_CMD_INLINE},
{"expire",expireCommand,3,REDIS_CMD_INLINE},
{NULL,NULL,0,0}
};
...
...
@@ -628,8 +639,8 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
* we resize the hash table to save memory */
for (j = 0; j < server.dbnum; j++) {
size = dict
GetHashTableSize(server.dict[j]
);
used = dict
GetHashTableUsed(server.dict[j]
);
size = dict
Slots(server.db[j].dict
);
used = dict
Size(server.db[j].dict
);
if (!(loops % 5) && used > 0) {
redisLog(REDIS_DEBUG,"DB %d: %d keys in %d slots HT.",j,used,size);
/* dictPrintStats(server.dict); */
...
...
@@ -637,7 +648,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
if (size && used && size > REDIS_HT_MINSLOTS &&
(used*100/size < REDIS_HT_MINFILL)) {
redisLog(REDIS_NOTICE,"The hash table %d is too sparse, resize it...",j);
dictResize(server.dict
[j]
);
dictResize(server.d
b[j].d
ict);
redisLog(REDIS_NOTICE,"Hash table %d resized.",j);
}
}
...
...
@@ -648,7 +659,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
listLength(server.clients)-listLength(server.slaves),
listLength(server.slaves),
server.usedmemory,
dict
GetHashTableUsed
(server.sharingpool));
dict
Size
(server.sharingpool));
}
/* Close connections of timedout clients */
...
...
@@ -787,18 +798,21 @@ static void initServer() {
server.objfreelist = listCreate();
createSharedObjects();
server.el = aeCreateEventLoop();
server.d
ict
= zmalloc(sizeof(
dict*
)*server.dbnum);
server.d
b
= zmalloc(sizeof(
redisDb
)*server.dbnum);
server.sharingpool = dictCreate(&setDictType,NULL);
server.sharingpoolsize = 1024;
if (!server.d
ict
|| !server.clients || !server.slaves || !server.monitors || !server.el || !server.objfreelist)
if (!server.d
b
|| !server.clients || !server.slaves || !server.monitors || !server.el || !server.objfreelist)
oom("server initialization"); /* Fatal OOM */
server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
if (server.fd == -1) {
redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
exit(1);
}
for (j = 0; j < server.dbnum; j++)
server.dict[j] = dictCreate(&hashDictType,NULL);
for (j = 0; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&hashDictType,NULL);
server.db[j].expires = dictCreate(&setDictType,NULL);
server.db[j].id = j;
}
server.cronloops = 0;
server.bgsaveinprogress = 0;
server.lastsave = time(NULL);
...
...
@@ -814,8 +828,10 @@ static void initServer() {
static void emptyDb() {
int j;
for (j = 0; j < server.dbnum; j++)
dictEmpty(server.dict[j]);
for (j = 0; j < server.dbnum; j++) {
dictEmpty(server.db[j].dict);
dictEmpty(server.db[j].expires);
}
}
/* I agree, this is a very rudimental way to load a configuration...
...
...
@@ -1150,9 +1166,9 @@ static int processCommand(redisClient *c) {
dirty = server.dirty;
cmd->proc(c);
if (server.dirty-dirty != 0 && listLength(server.slaves))
replicationFeedSlaves(server.slaves,cmd,c->d
ict
id,c->argv,c->argc);
replicationFeedSlaves(server.slaves,cmd,c->d
b->
id,c->argv,c->argc);
if (listLength(server.monitors))
replicationFeedSlaves(server.monitors,cmd,c->d
ict
id,c->argv,c->argc);
replicationFeedSlaves(server.monitors,cmd,c->d
b->
id,c->argv,c->argc);
server.stat_numcommands++;
/* Prepare the client for the next command */
...
...
@@ -1310,8 +1326,7 @@ again:
static int selectDb(redisClient *c, int id) {
if (id < 0 || id >= server.dbnum)
return REDIS_ERR;
c->dict = server.dict[id];
c->dictid = id;
c->db = &server.db[id];
return REDIS_OK;
}
...
...
@@ -1413,14 +1428,6 @@ static robj *createSetObject(void) {
return createObject(REDIS_SET,d);
}
#if 0
static robj *createHashObject(void) {
dict *d = dictCreate(&hashDictType,NULL);
if (!d) oom("dictCreate");
return createObject(REDIS_SET,d);
}
#endif
static void freeStringObject(robj *o) {
sdsfree(o->ptr);
}
...
...
@@ -1462,7 +1469,7 @@ static robj *tryObjectSharing(robj *o) {
struct dictEntry *de;
unsigned long c;
if (server.shareobjects == 0) return o;
if (
o == NULL ||
server.shareobjects == 0) return o;
assert(o->type == REDIS_STRING);
de = dictFind(server.sharingpool,o);
...
...
@@ -1479,7 +1486,7 @@ static robj *tryObjectSharing(robj *o) {
* shared we increment its count, everytime there is a miss we
* recrement the counter of a random object. If this object reaches
* zero we remove the object and put the current object instead. */
if (dict
GetHashTableUsed
(server.sharingpool) >=
if (dict
Size
(server.sharingpool) >=
server.sharingpoolsize) {
de = dictGetRandomKey(server.sharingpool);
assert(de != NULL);
...
...
@@ -1502,6 +1509,26 @@ static robj *tryObjectSharing(robj *o) {
}
}
static robj *lookupKey(redisDb *db, robj *key) {
dictEntry *de = dictFind(db->dict,key);
return de ? dictGetEntryVal(de) : NULL;
}
static robj *lookupKeyRead(redisDb *db, robj *key) {
expireIfNeeded(db,key);
return lookupKey(db,key);
}
static robj *lookupKeyWrite(redisDb *db, robj *key) {
deleteIfVolatile(db,key);
return lookupKey(db,key);
}
static int deleteKey(redisDb *db, robj *key) {
if (dictSize(db->expires)) dictDelete(db->expires,key);
return dictDelete(db->dict,key) == DICT_OK;
}
/*============================ DB saving/loading ============================ */
static int rdbSaveType(FILE *fp, unsigned char type) {
...
...
@@ -1604,8 +1631,8 @@ static int rdbSave(char *filename) {
}
if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
for (j = 0; j < server.dbnum; j++) {
dict *d = server.dict
[j]
;
if (dict
GetHashTableUsed
(d) == 0) continue;
dict *d = server.d
b[j].d
ict;
if (dict
Size
(d) == 0) continue;
di = dictGetIterator(d);
if (!di) {
fclose(fp);
...
...
@@ -1645,7 +1672,7 @@ static int rdbSave(char *filename) {
dictEntry *de;
if (!set) oom("dictGetIteraotr");
if (rdbSaveLen(fp,dict
GetHashTableUsed
(set)) == -1) goto werr;
if (rdbSaveLen(fp,dict
Size
(set)) == -1) goto werr;
while((de = dictNext(di)) != NULL) {
robj *eleobj = dictGetEntryKey(de);
...
...
@@ -1785,7 +1812,7 @@ static robj *rdbLoadStringObject(FILE*fp, int rdbver) {
case REDIS_RDB_ENC_INT8:
case REDIS_RDB_ENC_INT16:
case REDIS_RDB_ENC_INT32:
return rdbLoadIntegerObject(fp,len);
return
tryObjectSharing(
rdbLoadIntegerObject(fp,len)
)
;
default:
assert(0!=0);
}
...
...
@@ -1806,7 +1833,7 @@ static int rdbLoad(char *filename) {
uint32_t dbid;
int type;
int retval;
dict *d = server.dict
[0]
;
dict *d = server.d
b[0].d
ict;
char buf[1024];
int rdbver;
fp = fopen(filename,"r");
...
...
@@ -1838,7 +1865,7 @@ static int rdbLoad(char *filename) {
redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
exit(1);
}
d = server.d
ict
[dbid];
d = server.d
b
[dbid]
.dict
;
continue;
}
/* Read key */
...
...
@@ -1916,10 +1943,10 @@ static void echoCommand(redisClient *c) {
static void setGenericCommand(redisClient *c, int nx) {
int retval;
retval = dictAdd(c->dict,c->argv[1],c->argv[2]);
retval = dictAdd(c->
db->
dict,c->argv[1],c->argv[2]);
if (retval == DICT_ERR) {
if (!nx) {
dictReplace(c->dict,c->argv[1],c->argv[2]);
dictReplace(c->
db->
dict,c->argv[1],c->argv[2]);
incrRefCount(c->argv[2]);
} else {
addReply(c,shared.czero);
...
...
@@ -1930,6 +1957,7 @@ static void setGenericCommand(redisClient *c, int nx) {
incrRefCount(c->argv[2]);
}
server.dirty++;
removeExpire(c->db,c->argv[1]);
addReply(c, nx ? shared.cone : shared.ok);
}
...
...
@@ -1942,14 +1970,11 @@ static void setnxCommand(redisClient *c) {
}
static void getCommand(redisClient *c) {
dictEntry *de
;
robj *o = lookupKeyRead(c->db,c->argv[1])
;
de = dictFind(c->dict,c->argv[1]);
if (de == NULL) {
if (o == NULL) {
addReply(c,shared.nullbulk);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_STRING) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -1961,17 +1986,14 @@ static void getCommand(redisClient *c) {
}
static void mgetCommand(redisClient *c) {
dictEntry *de;
int j;
addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
for (j = 1; j < c->argc; j++) {
de = dictFin
d(c->d
ict
,c->argv[j]);
if (
de
== NULL) {
robj *o = lookupKeyRea
d(c->d
b
,c->argv[j]);
if (
o
== NULL) {
addReply(c,shared.nullbulk);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_STRING) {
addReply(c,shared.nullbulk);
} else {
...
...
@@ -1984,17 +2006,14 @@ static void mgetCommand(redisClient *c) {
}
static void incrDecrCommand(redisClient *c, int incr) {
dictEntry *de;
long long value;
int retval;
robj *o;
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
value = 0;
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_STRING) {
value = 0;
} else {
...
...
@@ -2006,9 +2025,10 @@ static void incrDecrCommand(redisClient *c, int incr) {
value += incr;
o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
retval = dictAdd(c->dict,c->argv[1],o);
retval = dictAdd(c->
db->
dict,c->argv[1],o);
if (retval == DICT_ERR) {
dictReplace(c->dict,c->argv[1],o);
dictReplace(c->db->dict,c->argv[1],o);
removeExpire(c->db,c->argv[1]);
} else {
incrRefCount(c->argv[1]);
}
...
...
@@ -2039,7 +2059,7 @@ static void decrbyCommand(redisClient *c) {
/* ========================= Type agnostic commands ========================= */
static void delCommand(redisClient *c) {
if (d
ictD
elete(c->d
ict
,c->argv[1])
== DICT_OK
) {
if (delete
Key
(c->d
b
,c->argv[1])) {
server.dirty++;
addReply(c,shared.cone);
} else {
...
...
@@ -2048,13 +2068,7 @@ static void delCommand(redisClient *c) {
}
static void existsCommand(redisClient *c) {
dictEntry *de;
de = dictFind(c->dict,c->argv[1]);
if (de == NULL)
addReply(c,shared.czero);
else
addReply(c,shared.cone);
addReply(c,lookupKeyRead(c->db,c->argv[1]) ? shared.cone : shared.czero);
}
static void selectCommand(redisClient *c) {
...
...
@@ -2070,7 +2084,10 @@ static void selectCommand(redisClient *c) {
static void randomkeyCommand(redisClient *c) {
dictEntry *de;
de = dictGetRandomKey(c->dict);
while(1) {
de = dictGetRandomKey(c->db->dict);
if (expireIfNeeded(c->db,dictGetEntryKey(de)) == 0) break;
}
if (de == NULL) {
addReply(c,shared.crlf);
} else {
...
...
@@ -2088,15 +2105,17 @@ static void keysCommand(redisClient *c) {
int numkeys = 0, keyslen = 0;
robj *lenobj = createObject(REDIS_STRING,NULL);
di = dictGetIterator(c->dict);
di = dictGetIterator(c->
db->
dict);
if (!di) oom("dictGetIterator");
addReply(c,lenobj);
decrRefCount(lenobj);
while((de = dictNext(di)) != NULL) {
robj *keyobj = dictGetEntryKey(de);
sds key = keyobj->ptr;
if ((pattern[0] == '*' && pattern[1] == '\0') ||
stringmatchlen(pattern,plen,key,sdslen(key),0)) {
if (expireIfNeeded(c->db,keyobj) == 0) {
if (numkeys != 0)
addReply(c,shared.space);
addReply(c,keyobj);
...
...
@@ -2104,6 +2123,7 @@ static void keysCommand(redisClient *c) {
keyslen += sdslen(key);
}
}
}
dictReleaseIterator(di);
lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
addReply(c,shared.crlf);
...
...
@@ -2111,7 +2131,7 @@ static void keysCommand(redisClient *c) {
static void dbsizeCommand(redisClient *c) {
addReplySds(c,
sdscatprintf(sdsempty(),":%lu\r\n",dict
GetHashTableUsed(c
->dict)));
sdscatprintf(sdsempty(),":%lu\r\n",dict
Size(c->db
->dict)));
}
static void lastsaveCommand(redisClient *c) {
...
...
@@ -2120,15 +2140,13 @@ static void lastsaveCommand(redisClient *c) {
}
static void typeCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
char *type;
de
=
dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
o
== NULL) {
type = "+none";
} else {
robj *o = dictGetEntryVal(de);
switch(o->type) {
case REDIS_STRING: type = "+string"; break;
case REDIS_LIST: type = "+list"; break;
...
...
@@ -2175,7 +2193,6 @@ static void shutdownCommand(redisClient *c) {
}
static void renameGenericCommand(redisClient *c, int nx) {
dictEntry *de;
robj *o;
/* To use the same key as src and dst is probably an error */
...
...
@@ -2184,24 +2201,24 @@ static void renameGenericCommand(redisClient *c, int nx) {
return;
}
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nokeyerr);
return;
}
o = dictGetEntryVal(de);
incrRefCount(o);
if (dictAdd(c->dict,c->argv[2],o) == DICT_ERR) {
deleteIfVolatile(c->db,c->argv[2]);
if (dictAdd(c->db->dict,c->argv[2],o) == DICT_ERR) {
if (nx) {
decrRefCount(o);
addReply(c,shared.czero);
return;
}
dictReplace(c->dict,c->argv[2],o);
dictReplace(c->
db->
dict,c->argv[2],o);
} else {
incrRefCount(c->argv[2]);
}
d
ictD
elete(c->d
ict
,c->argv[1]);
delete
Key
(c->d
b
,c->argv[1]);
server.dirty++;
addReply(c,nx ? shared.cone : shared.ok);
}
...
...
@@ -2215,21 +2232,19 @@ static void renamenxCommand(redisClient *c) {
}
static void moveCommand(redisClient *c) {
dictEntry *de;
robj *o, *key;
dict *src, *dst;
robj *o;
redisDb *src, *dst;
int srcid;
/* Obtain source and target DB pointers */
src = c->d
ict
;
srcid = c->d
ict
id;
src = c->d
b
;
srcid = c->d
b->
id;
if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
addReply(c,shared.outofrangeerr);
return;
}
dst = c->dict;
c->dict = src;
c->dictid = srcid;
dst = c->db;
selectDb(c,srcid); /* Back to the source DB */
/* If the user is moving using as target the same
* DB as the source DB it is probably an error. */
...
...
@@ -2239,24 +2254,23 @@ static void moveCommand(redisClient *c) {
}
/* Check if the element exists and get a reference */
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (!
de
) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (!
o
) {
addReply(c,shared.czero);
return;
}
/* Try to add the element to the target DB */
key = dictGetEntryKey(de);
o = dictGetEntryVal(de);
if (dictAdd(dst,key,o) == DICT_ERR) {
deleteIfVolatile(dst,c->argv[1]);
if (dictAdd(dst->dict,c->argv[1],o) == DICT_ERR) {
addReply(c,shared.czero);
return;
}
incrRefCount(
key
);
incrRefCount(
c->argv[1]
);
incrRefCount(o);
/* OK! key moved, free the entry in the source DB */
d
ictD
elete(src,c->argv[1]);
delete
Key
(src,c->argv[1]);
server.dirty++;
addReply(c,shared.cone);
}
...
...
@@ -2264,11 +2278,10 @@ static void moveCommand(redisClient *c) {
/* =================================== Lists ================================ */
static void pushGenericCommand(redisClient *c, int where) {
robj *lobj;
dictEntry *de;
list *list;
de = dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
lobj = lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
lobj
== NULL) {
lobj = createListObject();
list = lobj->ptr;
if (where == REDIS_HEAD) {
...
...
@@ -2276,11 +2289,10 @@ static void pushGenericCommand(redisClient *c, int where) {
} else {
if (!listAddNodeTail(list,c->argv[2])) oom("listAddNodeTail");
}
dictAdd(c->dict,c->argv[1],lobj);
dictAdd(c->
db->
dict,c->argv[1],lobj);
incrRefCount(c->argv[1]);
incrRefCount(c->argv[2]);
} else {
lobj = dictGetEntryVal(de);
if (lobj->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
return;
...
...
@@ -2306,15 +2318,14 @@ static void rpushCommand(redisClient *c) {
}
static void llenCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
list *l;
de
=
dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.czero);
return;
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2325,15 +2336,13 @@ static void llenCommand(redisClient *c) {
}
static void lindexCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
int index = atoi(c->argv[2]->ptr);
de
=
dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nullbulk);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2354,15 +2363,13 @@ static void lindexCommand(redisClient *c) {
}
static void lsetCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
int index = atoi(c->argv[2]->ptr);
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nokeyerr);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2386,14 +2393,12 @@ static void lsetCommand(redisClient *c) {
}
static void popGenericCommand(redisClient *c, int where) {
dictEntry *de
;
robj *o
;
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nullbulk);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2428,16 +2433,14 @@ static void rpopCommand(redisClient *c) {
}
static void lrangeCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
int start = atoi(c->argv[2]->ptr);
int end = atoi(c->argv[3]->ptr);
de
=
dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nullmultibulk);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2477,16 +2480,14 @@ static void lrangeCommand(redisClient *c) {
}
static void ltrimCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
int start = atoi(c->argv[2]->ptr);
int end = atoi(c->argv[3]->ptr);
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nokeyerr);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2528,14 +2529,12 @@ static void ltrimCommand(redisClient *c) {
}
static void lremCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
de
=
dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.nokeyerr);
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
} else {
...
...
@@ -2570,16 +2569,14 @@ static void lremCommand(redisClient *c) {
/* ==================================== Sets ================================ */
static void saddCommand(redisClient *c) {
dictEntry *de;
robj *set;
de = dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
set = lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
set
== NULL) {
set = createSetObject();
dictAdd(c->dict,c->argv[1],set);
dictAdd(c->
db->
dict,c->argv[1],set);
incrRefCount(c->argv[1]);
} else {
set = dictGetEntryVal(de);
if (set->type != REDIS_SET) {
addReply(c,shared.wrongtypeerr);
return;
...
...
@@ -2595,15 +2592,12 @@ static void saddCommand(redisClient *c) {
}
static void sremCommand(redisClient *c) {
dictEntry *de
;
robj *set
;
de = dictFind
(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
set = lookupKeyWrite
(c->d
b
,c->argv[1]);
if (
set
== NULL) {
addReply(c,shared.czero);
} else {
robj *set;
set = dictGetEntryVal(de);
if (set->type != REDIS_SET) {
addReply(c,shared.wrongtypeerr);
return;
...
...
@@ -2618,15 +2612,12 @@ static void sremCommand(redisClient *c) {
}
static void sismemberCommand(redisClient *c) {
dictEntry *de
;
robj *set
;
de = dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
set = lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
set
== NULL) {
addReply(c,shared.czero);
} else {
robj *set;
set = dictGetEntryVal(de);
if (set->type != REDIS_SET) {
addReply(c,shared.wrongtypeerr);
return;
...
...
@@ -2639,21 +2630,20 @@ static void sismemberCommand(redisClient *c) {
}
static void scardCommand(redisClient *c) {
dictEntry *de
;
robj *o
;
dict *s;
de
=
dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
o
=
lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
o
== NULL) {
addReply(c,shared.czero);
return;
} else {
robj *o = dictGetEntryVal(de);
if (o->type != REDIS_SET) {
addReply(c,shared.wrongtypeerr);
} else {
s = o->ptr;
addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",
dict
GetHashTableUsed
(s)));
dict
Size
(s)));
}
}
}
...
...
@@ -2661,7 +2651,7 @@ static void scardCommand(redisClient *c) {
static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
dict **d1 = (void*) s1, **d2 = (void*) s2;
return dict
GetHashTableUsed(*d1)-dictGetHashTableUsed
(*d2);
return dict
Size(*d1)-dictSize
(*d2);
}
static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey) {
...
...
@@ -2674,15 +2664,15 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, r
if (!dv) oom("sinterCommand");
for (j = 0; j < setsnum; j++) {
robj *setobj;
dictEntry *de;
de = dictFind(c->dict,setskeys[j]);
if (!de) {
setobj = dstkey ?
lookupKeyWrite(c->db,setskeys[j]) :
lookupKeyRead(c->db,setskeys[j]);
if (!setobj) {
zfree(dv);
addReply(c,shared.nokeyerr);
return;
}
setobj = dictGetEntryVal(de);
if (setobj->type != REDIS_SET) {
zfree(dv);
addReply(c,shared.wrongtypeerr);
...
...
@@ -2707,8 +2697,8 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, r
/* If we have a target key where to store the resulting set
* create this key with an empty set inside */
dstset = createSetObject();
d
ictD
elete(c->d
ict
,dstkey);
dictAdd(c->dict,dstkey,dstset);
delete
Key
(c->d
b
,dstkey);
dictAdd(c->
db->
dict,dstkey,dstset);
incrRefCount(dstkey);
}
...
...
@@ -2754,7 +2744,8 @@ static void sinterstoreCommand(redisClient *c) {
}
static void flushdbCommand(redisClient *c) {
dictEmpty(c->dict);
dictEmpty(c->db->dict);
dictEmpty(c->db->expires);
addReply(c,shared.ok);
rdbSave(server.dbfilename);
}
...
...
@@ -2775,12 +2766,11 @@ redisSortOperation *createSortOperation(int type, robj *pattern) {
/* Return the value associated to the key with a name obtained
* substituting the first occurence of '*' in 'pattern' with 'subst' */
robj *lookupKeyByPattern(
dict *dict
, robj *pattern, robj *subst) {
robj *lookupKeyByPattern(
redisDb *db
, robj *pattern, robj *subst) {
char *p;
sds spat, ssub;
robj keyobj;
int prefixlen, sublen, postfixlen;
dictEntry *de;
/* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
struct {
long len;
...
...
@@ -2788,7 +2778,6 @@ robj *lookupKeyByPattern(dict *dict, robj *pattern, robj *subst) {
char buf[REDIS_SORTKEY_MAX+1];
} keyname;
spat = pattern->ptr;
ssub = subst->ptr;
if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
...
...
@@ -2808,10 +2797,8 @@ robj *lookupKeyByPattern(dict *dict, robj *pattern, robj *subst) {
keyobj.type = REDIS_STRING;
keyobj.ptr = ((char*)&keyname)+(sizeof(long)*2);
de = dictFind(dict,&keyobj);
/* printf("lookup '%s' => %p\n", keyname.buf,de); */
if (!de) return NULL;
return dictGetEntryVal(de);
return lookupKeyRead(db,&keyobj);
}
/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
...
...
@@ -2856,7 +2843,6 @@ static int sortCompare(const void *s1, const void *s2) {
/* The SORT command is the most complex command in Redis. Warning: this code
* is optimized for speed and a bit less for readability */
static void sortCommand(redisClient *c) {
dictEntry *de;
list *operations;
int outputlen = 0;
int desc = 0, alpha = 0;
...
...
@@ -2867,12 +2853,11 @@ static void sortCommand(redisClient *c) {
redisSortObject *vector; /* Resulting vector to sort */
/* Lookup the key to sort. It must be of the right types */
de = dictFin
d(c->d
ict
,c->argv[1]);
if (
de
== NULL) {
sortval = lookupKeyRea
d(c->d
b
,c->argv[1]);
if (
sortval
== NULL) {
addReply(c,shared.nokeyerr);
return;
}
sortval = dictGetEntryVal(de);
if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
return;
...
...
@@ -2937,7 +2922,7 @@ static void sortCommand(redisClient *c) {
/* Load the sorting vector with all the objects to sort */
vectorlen = (sortval->type == REDIS_LIST) ?
listLength((list*)sortval->ptr) :
dict
GetHashTableUsed
((dict*)sortval->ptr);
dict
Size
((dict*)sortval->ptr);
vector = zmalloc(sizeof(redisSortObject)*vectorlen);
if (!vector) oom("allocating objects vector for SORT");
j = 0;
...
...
@@ -2975,7 +2960,7 @@ static void sortCommand(redisClient *c) {
if (sortby) {
robj *byval;
byval = lookupKeyByPattern(c->d
ict
,sortby,vector[j].obj);
byval = lookupKeyByPattern(c->d
b
,sortby,vector[j].obj);
if (!byval || byval->type != REDIS_STRING) continue;
if (alpha) {
vector[j].u.cmpobj = byval;
...
...
@@ -3020,7 +3005,7 @@ static void sortCommand(redisClient *c) {
}
while(ln) {
redisSortOperation *sop = ln->value;
robj *val = lookupKeyByPattern(c->d
ict
,sop->pattern,
robj *val = lookupKeyByPattern(c->d
b
,sop->pattern,
vector[j].obj);
if (sop->type == REDIS_SORT_GET) {
...
...
@@ -3080,6 +3065,85 @@ static void infoCommand(redisClient *c) {
addReply(c,shared.crlf);
}
static void monitorCommand(redisClient *c) {
/* ignore MONITOR if aleady slave or in monitor mode */
if (c->flags & REDIS_SLAVE) return;
c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
c->slaveseldb = 0;
if (!listAddNodeTail(server.monitors,c)) oom("listAddNodeTail");
addReply(c,shared.ok);
}
/* ================================= Expire ================================= */
static int removeExpire(redisDb *db, robj *key) {
if (dictDelete(db->expires,key) == DICT_OK) {
return 1;
} else {
return 0;
}
}
static int setExpire(redisDb *db, robj *key, time_t when) {
if (dictAdd(db->expires,key,(void*)when) == DICT_ERR) {
return 0;
} else {
incrRefCount(key);
return 1;
}
}
static int expireIfNeeded(redisDb *db, robj *key) {
time_t when;
dictEntry *de;
/* No expire? return ASAP */
if (dictSize(db->expires) == 0 ||
(de = dictFind(db->expires,key)) == NULL) return 0;
/* Lookup the expire */
when = (time_t) dictGetEntryVal(de);
if (time(NULL) <= when) return 0;
/* Delete the key */
dictDelete(db->expires,key);
return dictDelete(db->dict,key) == DICT_OK;
}
static int deleteIfVolatile(redisDb *db, robj *key) {
dictEntry *de;
/* No expire? return ASAP */
if (dictSize(db->expires) == 0 ||
(de = dictFind(db->expires,key)) == NULL) return 0;
/* Delete the key */
dictDelete(db->expires,key);
return dictDelete(db->dict,key) == DICT_OK;
}
static void expireCommand(redisClient *c) {
dictEntry *de;
int seconds = atoi(c->argv[2]->ptr);
de = dictFind(c->db->dict,c->argv[1]);
if (de == NULL) {
addReply(c,shared.czero);
return;
}
if (seconds <= 0) {
addReply(c, shared.czero);
return;
} else {
time_t when = time(NULL)+seconds;
if (setExpire(c->db,c->argv[1],when))
addReply(c,shared.cone);
else
addReply(c,shared.czero);
return;
}
}
/* =============================== Replication ============================= */
/* Send the whole output buffer syncronously to the slave. This a general operation in theory, but it is actually useful only for replication. */
...
...
@@ -3280,16 +3344,6 @@ static int syncWithMaster(void) {
return REDIS_OK;
}
static void monitorCommand(redisClient *c) {
/* ignore MONITOR if aleady slave or in monitor mode */
if (c->flags & REDIS_SLAVE) return;
c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
c->slaveseldb = 0;
if (!listAddNodeTail(server.monitors,c)) oom("listAddNodeTail");
addReply(c,shared.ok);
}
/* =================================== Main! ================================ */
static void daemonize(void) {
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment