]> git.saurik.com Git - redis.git/commitdiff
command lookup process turned into a much more flexible and probably faster hash...
authorantirez <antirez@gmail.com>
Wed, 3 Nov 2010 10:23:59 +0000 (11:23 +0100)
committerantirez <antirez@gmail.com>
Wed, 3 Nov 2010 10:23:59 +0000 (11:23 +0100)
src/db.c
src/dict.c
src/dict.h
src/multi.c
src/redis.c
src/redis.h

index f2a0c09ee09658823ad783ca4446b6c85e787c99..aa1c14ad451af1c95f63063e87dc56ba54ddaecd 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -435,16 +435,14 @@ time_t getExpire(redisDb *db, robj *key) {
  * 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);
+        feedAppendOnlyFile(server.delCommand,db->id,argv,2);
     if (listLength(server.slaves))
         replicationFeedSlaves(server.slaves,db->id,argv,2);
 
index a1060d456ae7669246deeacdb05a6941d8a58853..9be7fb168ed00b8b633e06a47b0b74c87e6a70fd 100644 (file)
@@ -42,6 +42,7 @@
 #include <assert.h>
 #include <limits.h>
 #include <sys/time.h>
+#include <ctype.h>
 
 #include "dict.h"
 #include "zmalloc.h"
@@ -94,6 +95,15 @@ unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
     return hash;
 }
 
+/* And a case insensitive version */
+unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
+    unsigned int hash = 5381;
+
+    while (len--)
+        hash = ((hash << 5) + hash) + (tolower(*buf++)); /* hash * 33 + c */
+    return hash;
+}
+
 /* ----------------------------- API implementation ------------------------- */
 
 /* Reset an hashtable already initialized with ht_init().
index 30ace4db7cba3df6bae3ac01d4a55d4f43ecc733..25cce4e50ef7f13a756251a6d91b405786e8ac33 100644 (file)
@@ -137,6 +137,7 @@ void dictReleaseIterator(dictIterator *iter);
 dictEntry *dictGetRandomKey(dict *d);
 void dictPrintStats(dict *d);
 unsigned int dictGenHashFunction(const unsigned char *buf, int len);
+unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);
 void dictEmpty(dict *d);
 void dictEnableResize(void);
 void dictDisableResize(void);
index 47615eb04ff18c7872964600365580d6dec59ea1..59fc9d9e8b80f16c649704147af18dcb68f86049 100644 (file)
@@ -65,12 +65,10 @@ void discardCommand(redisClient *c) {
 /* Send a MULTI command to all the slaves and AOF file. Check the execCommand
  * implememntation for more information. */
 void execCommandReplicateMulti(redisClient *c) {
-    struct redisCommand *cmd;
     robj *multistring = createStringObject("MULTI",5);
 
-    cmd = lookupCommand("multi");
     if (server.appendonly)
-        feedAppendOnlyFile(cmd,c->db->id,&multistring,1);
+        feedAppendOnlyFile(server.multiCommand,c->db->id,&multistring,1);
     if (listLength(server.slaves))
         replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
     decrRefCount(multistring);
index f65901c769eb82f9769acbc6a42fa1c9876415a0..d099551e9c67b939d80bf8079f0621784ea1a585 100644 (file)
@@ -252,6 +252,15 @@ int dictSdsKeyCompare(void *privdata, const void *key1,
     return memcmp(key1, key2, l1) == 0;
 }
 
+/* A case insensitive version used for the command lookup table. */
+int dictSdsKeyCaseCompare(void *privdata, const void *key1,
+        const void *key2)
+{
+    DICT_NOTUSED(privdata);
+
+    return strcasecmp(key1, key2) == 0;
+}
+
 void dictRedisObjectDestructor(void *privdata, void *val)
 {
     DICT_NOTUSED(privdata);
@@ -283,6 +292,10 @@ unsigned int dictSdsHash(const void *key) {
     return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
 }
 
+unsigned int dictSdsCaseHash(const void *key) {
+    return dictGenCaseHashFunction((unsigned char*)key, sdslen((char*)key));
+}
+
 int dictEncObjKeyCompare(void *privdata, const void *key1,
         const void *key2)
 {
@@ -364,6 +377,16 @@ dictType keyptrDictType = {
     NULL                       /* val destructor */
 };
 
+/* Command table. sds string -> command struct pointer. */
+dictType commandTableDictType = {
+    dictSdsCaseHash,           /* hash function */
+    NULL,                      /* key dup */
+    NULL,                      /* val dup */
+    dictSdsKeyCaseCompare,     /* key compare */
+    dictSdsDestructor,         /* key destructor */
+    NULL                       /* val destructor */
+};
+
 /* Hash type hash table (note that small hashes are represented with zimpaps) */
 dictType hashDictType = {
     dictEncObjHash,             /* hash function */
@@ -791,6 +814,12 @@ void initServer() {
         redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
         exit(1);
     }
+
+    server.commands = dictCreate(&commandTableDictType,NULL);
+    populateCommandTable();
+    server.delCommand = lookupCommandByCString("del");
+    server.multiCommand = lookupCommandByCString("multi");
+
     server.clients = listCreate();
     server.slaves = listCreate();
     server.monitors = listCreate();
@@ -860,31 +889,34 @@ void initServer() {
     if (server.vm_enabled) vmInit();
 }
 
-int qsortRedisCommands(const void *r1, const void *r2) {
-    return strcasecmp(
-        ((struct redisCommand*)r1)->name,
-        ((struct redisCommand*)r2)->name);
-}
+/* Populates the Redis Command Table starting from the hard coded list
+ * we have on top of redis.c file. */
+void populateCommandTable(void) {
+    int j;
+    int numcommands = sizeof(readonlyCommandTable)/sizeof(struct redisCommand);
+
+    for (j = 0; j < numcommands; j++) {
+        struct redisCommand *c = readonlyCommandTable+j;
+        int retval;
 
-void sortCommandTable() {
-    /* Copy and sort the read-only version of the command table */
-    commandTable = (struct redisCommand*)zmalloc(sizeof(readonlyCommandTable));
-    memcpy(commandTable,readonlyCommandTable,sizeof(readonlyCommandTable));
-    qsort(commandTable,
-        sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
-        sizeof(struct redisCommand),qsortRedisCommands);
+        retval = dictAdd(server.commands, sdsnew(c->name), c);
+        assert(retval == DICT_OK);
+    }
 }
 
 /* ====================== Commands lookup and execution ===================== */
 
-struct redisCommand *lookupCommand(char *name) {
-    struct redisCommand tmp = {name,NULL,0,0,NULL,0,0,0};
-    return bsearch(
-        &tmp,
-        commandTable,
-        sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
-        sizeof(struct redisCommand),
-        qsortRedisCommands);
+struct redisCommand *lookupCommand(sds name) {
+    return dictFetchValue(server.commands, name);
+}
+
+struct redisCommand *lookupCommandByCString(char *s) {
+    struct redisCommand *cmd;
+    sds name = sdsnew(s);
+
+    cmd = dictFetchValue(server.commands, name);
+    sdsfree(name);
+    return cmd;
 }
 
 /* Call() is the core of Redis execution of a command */
@@ -1443,7 +1475,6 @@ int main(int argc, char **argv) {
     time_t start;
 
     initServerConfig();
-    sortCommandTable();
     if (argc == 2) {
         if (strcmp(argv[1], "-v") == 0 ||
             strcmp(argv[1], "--version") == 0) version();
index 6fa3e49fe8d7068403f092ef6a038bdc15bcd6a8..8818fa0544382eb29e69a5d24a7663ba87a3a090 100644 (file)
@@ -360,6 +360,8 @@ struct redisServer {
     long long dirty;            /* changes to DB from the last save */
     long long dirty_before_bgsave; /* used to restore dirty on failed BGSAVE */
     list *clients;
+    dict *commands;             /* Command table hahs table */
+    struct redisCommand *delCommand, *multiCommand; /* often lookedup cmds */
     list *slaves, *monitors;
     char neterr[ANET_ERR_LEN];
     aeEventLoop *el;
@@ -746,7 +748,8 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
 void freeMemoryIfNeeded(void);
 int processCommand(redisClient *c);
 void setupSigSegvAction(void);
-struct redisCommand *lookupCommand(char *name);
+struct redisCommand *lookupCommand(sds name);
+struct redisCommand *lookupCommandByCString(char *s);
 void call(redisClient *c, struct redisCommand *cmd);
 int prepareForShutdown();
 void redisLog(int level, const char *fmt, ...);
@@ -754,6 +757,7 @@ void usage();
 void updateDictResizePolicy(void);
 int htNeedsResize(dict *dict);
 void oom(const char *msg);
+void populateCommandTable(void);
 
 /* Virtual Memory */
 void vmInit(void);