command lookup process turned into a much more flexible and probably faster hash table
This commit is contained in:
parent
c58bcfd350
commit
5d33a8862a
4
src/db.c
4
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
|
* will be consistent even if we allow write operations against expiring
|
||||||
* keys. */
|
* keys. */
|
||||||
void propagateExpire(redisDb *db, robj *key) {
|
void propagateExpire(redisDb *db, robj *key) {
|
||||||
struct redisCommand *cmd;
|
|
||||||
robj *argv[2];
|
robj *argv[2];
|
||||||
|
|
||||||
cmd = lookupCommand("del");
|
|
||||||
argv[0] = createStringObject("DEL",3);
|
argv[0] = createStringObject("DEL",3);
|
||||||
argv[1] = key;
|
argv[1] = key;
|
||||||
incrRefCount(key);
|
incrRefCount(key);
|
||||||
|
|
||||||
if (server.appendonly)
|
if (server.appendonly)
|
||||||
feedAppendOnlyFile(cmd,db->id,argv,2);
|
feedAppendOnlyFile(server.delCommand,db->id,argv,2);
|
||||||
if (listLength(server.slaves))
|
if (listLength(server.slaves))
|
||||||
replicationFeedSlaves(server.slaves,db->id,argv,2);
|
replicationFeedSlaves(server.slaves,db->id,argv,2);
|
||||||
|
|
||||||
|
10
src/dict.c
10
src/dict.c
@ -42,6 +42,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "dict.h"
|
#include "dict.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
@ -94,6 +95,15 @@ unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
|
|||||||
return hash;
|
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 ------------------------- */
|
/* ----------------------------- API implementation ------------------------- */
|
||||||
|
|
||||||
/* Reset an hashtable already initialized with ht_init().
|
/* Reset an hashtable already initialized with ht_init().
|
||||||
|
@ -137,6 +137,7 @@ void dictReleaseIterator(dictIterator *iter);
|
|||||||
dictEntry *dictGetRandomKey(dict *d);
|
dictEntry *dictGetRandomKey(dict *d);
|
||||||
void dictPrintStats(dict *d);
|
void dictPrintStats(dict *d);
|
||||||
unsigned int dictGenHashFunction(const unsigned char *buf, int len);
|
unsigned int dictGenHashFunction(const unsigned char *buf, int len);
|
||||||
|
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);
|
||||||
void dictEmpty(dict *d);
|
void dictEmpty(dict *d);
|
||||||
void dictEnableResize(void);
|
void dictEnableResize(void);
|
||||||
void dictDisableResize(void);
|
void dictDisableResize(void);
|
||||||
|
@ -65,12 +65,10 @@ void discardCommand(redisClient *c) {
|
|||||||
/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
|
/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
|
||||||
* implememntation for more information. */
|
* implememntation for more information. */
|
||||||
void execCommandReplicateMulti(redisClient *c) {
|
void execCommandReplicateMulti(redisClient *c) {
|
||||||
struct redisCommand *cmd;
|
|
||||||
robj *multistring = createStringObject("MULTI",5);
|
robj *multistring = createStringObject("MULTI",5);
|
||||||
|
|
||||||
cmd = lookupCommand("multi");
|
|
||||||
if (server.appendonly)
|
if (server.appendonly)
|
||||||
feedAppendOnlyFile(cmd,c->db->id,&multistring,1);
|
feedAppendOnlyFile(server.multiCommand,c->db->id,&multistring,1);
|
||||||
if (listLength(server.slaves))
|
if (listLength(server.slaves))
|
||||||
replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
|
replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
|
||||||
decrRefCount(multistring);
|
decrRefCount(multistring);
|
||||||
|
73
src/redis.c
73
src/redis.c
@ -252,6 +252,15 @@ int dictSdsKeyCompare(void *privdata, const void *key1,
|
|||||||
return memcmp(key1, key2, l1) == 0;
|
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)
|
void dictRedisObjectDestructor(void *privdata, void *val)
|
||||||
{
|
{
|
||||||
DICT_NOTUSED(privdata);
|
DICT_NOTUSED(privdata);
|
||||||
@ -283,6 +292,10 @@ unsigned int dictSdsHash(const void *key) {
|
|||||||
return dictGenHashFunction((unsigned char*)key, sdslen((char*)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,
|
int dictEncObjKeyCompare(void *privdata, const void *key1,
|
||||||
const void *key2)
|
const void *key2)
|
||||||
{
|
{
|
||||||
@ -364,6 +377,16 @@ dictType keyptrDictType = {
|
|||||||
NULL /* val destructor */
|
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) */
|
/* Hash type hash table (note that small hashes are represented with zimpaps) */
|
||||||
dictType hashDictType = {
|
dictType hashDictType = {
|
||||||
dictEncObjHash, /* hash function */
|
dictEncObjHash, /* hash function */
|
||||||
@ -791,6 +814,12 @@ void initServer() {
|
|||||||
redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
|
redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.commands = dictCreate(&commandTableDictType,NULL);
|
||||||
|
populateCommandTable();
|
||||||
|
server.delCommand = lookupCommandByCString("del");
|
||||||
|
server.multiCommand = lookupCommandByCString("multi");
|
||||||
|
|
||||||
server.clients = listCreate();
|
server.clients = listCreate();
|
||||||
server.slaves = listCreate();
|
server.slaves = listCreate();
|
||||||
server.monitors = listCreate();
|
server.monitors = listCreate();
|
||||||
@ -860,31 +889,34 @@ void initServer() {
|
|||||||
if (server.vm_enabled) vmInit();
|
if (server.vm_enabled) vmInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
int qsortRedisCommands(const void *r1, const void *r2) {
|
/* Populates the Redis Command Table starting from the hard coded list
|
||||||
return strcasecmp(
|
* we have on top of redis.c file. */
|
||||||
((struct redisCommand*)r1)->name,
|
void populateCommandTable(void) {
|
||||||
((struct redisCommand*)r2)->name);
|
int j;
|
||||||
}
|
int numcommands = sizeof(readonlyCommandTable)/sizeof(struct redisCommand);
|
||||||
|
|
||||||
void sortCommandTable() {
|
for (j = 0; j < numcommands; j++) {
|
||||||
/* Copy and sort the read-only version of the command table */
|
struct redisCommand *c = readonlyCommandTable+j;
|
||||||
commandTable = (struct redisCommand*)zmalloc(sizeof(readonlyCommandTable));
|
int retval;
|
||||||
memcpy(commandTable,readonlyCommandTable,sizeof(readonlyCommandTable));
|
|
||||||
qsort(commandTable,
|
retval = dictAdd(server.commands, sdsnew(c->name), c);
|
||||||
sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
|
assert(retval == DICT_OK);
|
||||||
sizeof(struct redisCommand),qsortRedisCommands);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ====================== Commands lookup and execution ===================== */
|
/* ====================== Commands lookup and execution ===================== */
|
||||||
|
|
||||||
struct redisCommand *lookupCommand(char *name) {
|
struct redisCommand *lookupCommand(sds name) {
|
||||||
struct redisCommand tmp = {name,NULL,0,0,NULL,0,0,0};
|
return dictFetchValue(server.commands, name);
|
||||||
return bsearch(
|
}
|
||||||
&tmp,
|
|
||||||
commandTable,
|
struct redisCommand *lookupCommandByCString(char *s) {
|
||||||
sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
|
struct redisCommand *cmd;
|
||||||
sizeof(struct redisCommand),
|
sds name = sdsnew(s);
|
||||||
qsortRedisCommands);
|
|
||||||
|
cmd = dictFetchValue(server.commands, name);
|
||||||
|
sdsfree(name);
|
||||||
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call() is the core of Redis execution of a command */
|
/* Call() is the core of Redis execution of a command */
|
||||||
@ -1443,7 +1475,6 @@ int main(int argc, char **argv) {
|
|||||||
time_t start;
|
time_t start;
|
||||||
|
|
||||||
initServerConfig();
|
initServerConfig();
|
||||||
sortCommandTable();
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
if (strcmp(argv[1], "-v") == 0 ||
|
if (strcmp(argv[1], "-v") == 0 ||
|
||||||
strcmp(argv[1], "--version") == 0) version();
|
strcmp(argv[1], "--version") == 0) version();
|
||||||
|
@ -360,6 +360,8 @@ struct redisServer {
|
|||||||
long long dirty; /* changes to DB from the last save */
|
long long dirty; /* changes to DB from the last save */
|
||||||
long long dirty_before_bgsave; /* used to restore dirty on failed BGSAVE */
|
long long dirty_before_bgsave; /* used to restore dirty on failed BGSAVE */
|
||||||
list *clients;
|
list *clients;
|
||||||
|
dict *commands; /* Command table hahs table */
|
||||||
|
struct redisCommand *delCommand, *multiCommand; /* often lookedup cmds */
|
||||||
list *slaves, *monitors;
|
list *slaves, *monitors;
|
||||||
char neterr[ANET_ERR_LEN];
|
char neterr[ANET_ERR_LEN];
|
||||||
aeEventLoop *el;
|
aeEventLoop *el;
|
||||||
@ -746,7 +748,8 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
|
|||||||
void freeMemoryIfNeeded(void);
|
void freeMemoryIfNeeded(void);
|
||||||
int processCommand(redisClient *c);
|
int processCommand(redisClient *c);
|
||||||
void setupSigSegvAction(void);
|
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);
|
void call(redisClient *c, struct redisCommand *cmd);
|
||||||
int prepareForShutdown();
|
int prepareForShutdown();
|
||||||
void redisLog(int level, const char *fmt, ...);
|
void redisLog(int level, const char *fmt, ...);
|
||||||
@ -754,6 +757,7 @@ void usage();
|
|||||||
void updateDictResizePolicy(void);
|
void updateDictResizePolicy(void);
|
||||||
int htNeedsResize(dict *dict);
|
int htNeedsResize(dict *dict);
|
||||||
void oom(const char *msg);
|
void oom(const char *msg);
|
||||||
|
void populateCommandTable(void);
|
||||||
|
|
||||||
/* Virtual Memory */
|
/* Virtual Memory */
|
||||||
void vmInit(void);
|
void vmInit(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user