summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--TODO1
-rw-r--r--redis.c322
-rw-r--r--staticsymbols.h189
-rw-r--r--utils/build-static-symbols.tcl22
5 files changed, 322 insertions, 215 deletions
diff --git a/Makefile b/Makefile
index 49d0cb380..9e687d25a 100644
--- a/Makefile
+++ b/Makefile
@@ -60,6 +60,9 @@ clean:
dep:
$(CC) -MM *.c
+staticsymbols:
+ tclsh utils/build-static-symbols.tcl > staticsymbols.h
+
test:
tclsh test-redis.tcl
diff --git a/TODO b/TODO
index 1df6be8bf..b63a4a439 100644
--- a/TODO
+++ b/TODO
@@ -10,7 +10,6 @@ VERSION 1.1 TODO
* Write docs for the "STORE" operaiton of SORT, and GET "#" option.
* Append only mode: testing and a command to rebuild the log from scratch.
* Profiling and optimizations. For instance the commands lookup is probably starting to eat too CPU being a simple list. To implement binary search or an hash table lookup can be a win probably.
-* Expiring algorithm should be adaptive. Use the following algorithm. Start testing REDIS_EXPIRELOOKUPS_PER_CRON in the first iteration, and continue with the same amount of keys until the percentage of expired keys > 25%.
VERSION 1.2 TODO
diff --git a/redis.c b/redis.c
index 2d196674f..12bd85676 100644
--- a/redis.c
+++ b/redis.c
@@ -544,6 +544,7 @@ static struct redisCommand cmdTable[] = {
{"debug",debugCommand,-2,REDIS_CMD_INLINE},
{NULL,NULL,0,0}
};
+
/*============================ Utility functions ============================ */
/* Glob-style pattern matching. */
@@ -1025,7 +1026,7 @@ static void appendServerSaveParams(time_t seconds, int changes) {
server.saveparamslen++;
}
-static void ResetServerSaveParams() {
+static void resetServerSaveParams() {
zfree(server.saveparams);
server.saveparams = NULL;
server.saveparamslen = 0;
@@ -1054,7 +1055,7 @@ static void initServerConfig() {
server.sharingpoolsize = 1024;
server.maxclients = 0;
server.maxmemory = 0;
- ResetServerSaveParams();
+ resetServerSaveParams();
appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
@@ -5534,150 +5535,91 @@ static void debugCommand(redisClient *c) {
}
}
-#ifdef HAVE_BACKTRACE
-static struct redisFunctionSym symsTable[] = {
-{"compareStringObjects", (unsigned long)compareStringObjects},
-{"isStringRepresentableAsLong", (unsigned long)isStringRepresentableAsLong},
-{"dictEncObjKeyCompare", (unsigned long)dictEncObjKeyCompare},
-{"dictEncObjHash", (unsigned long)dictEncObjHash},
-{"incrDecrCommand", (unsigned long)incrDecrCommand},
-{"freeStringObject", (unsigned long)freeStringObject},
-{"freeListObject", (unsigned long)freeListObject},
-{"freeSetObject", (unsigned long)freeSetObject},
-{"decrRefCount", (unsigned long)decrRefCount},
-{"createObject", (unsigned long)createObject},
-{"freeClient", (unsigned long)freeClient},
-{"rdbLoad", (unsigned long)rdbLoad},
-{"rdbSaveStringObject", (unsigned long)rdbSaveStringObject},
-{"rdbSaveStringObjectRaw", (unsigned long)rdbSaveStringObjectRaw},
-{"addReply", (unsigned long)addReply},
-{"addReplySds", (unsigned long)addReplySds},
-{"incrRefCount", (unsigned long)incrRefCount},
-{"rdbSaveBackground", (unsigned long)rdbSaveBackground},
-{"createStringObject", (unsigned long)createStringObject},
-{"replicationFeedSlaves", (unsigned long)replicationFeedSlaves},
-{"syncWithMaster", (unsigned long)syncWithMaster},
-{"tryObjectSharing", (unsigned long)tryObjectSharing},
-{"tryObjectEncoding", (unsigned long)tryObjectEncoding},
-{"getDecodedObject", (unsigned long)getDecodedObject},
-{"removeExpire", (unsigned long)removeExpire},
-{"expireIfNeeded", (unsigned long)expireIfNeeded},
-{"deleteIfVolatile", (unsigned long)deleteIfVolatile},
-{"deleteKey", (unsigned long)deleteKey},
-{"getExpire", (unsigned long)getExpire},
-{"setExpire", (unsigned long)setExpire},
-{"updateSlavesWaitingBgsave", (unsigned long)updateSlavesWaitingBgsave},
-{"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded},
-{"authCommand", (unsigned long)authCommand},
-{"pingCommand", (unsigned long)pingCommand},
-{"echoCommand", (unsigned long)echoCommand},
-{"setCommand", (unsigned long)setCommand},
-{"setnxCommand", (unsigned long)setnxCommand},
-{"getCommand", (unsigned long)getCommand},
-{"delCommand", (unsigned long)delCommand},
-{"existsCommand", (unsigned long)existsCommand},
-{"incrCommand", (unsigned long)incrCommand},
-{"decrCommand", (unsigned long)decrCommand},
-{"incrbyCommand", (unsigned long)incrbyCommand},
-{"decrbyCommand", (unsigned long)decrbyCommand},
-{"selectCommand", (unsigned long)selectCommand},
-{"randomkeyCommand", (unsigned long)randomkeyCommand},
-{"keysCommand", (unsigned long)keysCommand},
-{"dbsizeCommand", (unsigned long)dbsizeCommand},
-{"lastsaveCommand", (unsigned long)lastsaveCommand},
-{"saveCommand", (unsigned long)saveCommand},
-{"bgsaveCommand", (unsigned long)bgsaveCommand},
-{"shutdownCommand", (unsigned long)shutdownCommand},
-{"moveCommand", (unsigned long)moveCommand},
-{"renameCommand", (unsigned long)renameCommand},
-{"renamenxCommand", (unsigned long)renamenxCommand},
-{"lpushCommand", (unsigned long)lpushCommand},
-{"rpushCommand", (unsigned long)rpushCommand},
-{"lpopCommand", (unsigned long)lpopCommand},
-{"rpopCommand", (unsigned long)rpopCommand},
-{"llenCommand", (unsigned long)llenCommand},
-{"lindexCommand", (unsigned long)lindexCommand},
-{"lrangeCommand", (unsigned long)lrangeCommand},
-{"ltrimCommand", (unsigned long)ltrimCommand},
-{"typeCommand", (unsigned long)typeCommand},
-{"lsetCommand", (unsigned long)lsetCommand},
-{"saddCommand", (unsigned long)saddCommand},
-{"sremCommand", (unsigned long)sremCommand},
-{"smoveCommand", (unsigned long)smoveCommand},
-{"sismemberCommand", (unsigned long)sismemberCommand},
-{"scardCommand", (unsigned long)scardCommand},
-{"spopCommand", (unsigned long)spopCommand},
-{"srandmemberCommand", (unsigned long)srandmemberCommand},
-{"sinterCommand", (unsigned long)sinterCommand},
-{"sinterstoreCommand", (unsigned long)sinterstoreCommand},
-{"sunionCommand", (unsigned long)sunionCommand},
-{"sunionstoreCommand", (unsigned long)sunionstoreCommand},
-{"sdiffCommand", (unsigned long)sdiffCommand},
-{"sdiffstoreCommand", (unsigned long)sdiffstoreCommand},
-{"syncCommand", (unsigned long)syncCommand},
-{"flushdbCommand", (unsigned long)flushdbCommand},
-{"flushallCommand", (unsigned long)flushallCommand},
-{"sortCommand", (unsigned long)sortCommand},
-{"lremCommand", (unsigned long)lremCommand},
-{"infoCommand", (unsigned long)infoCommand},
-{"mgetCommand", (unsigned long)mgetCommand},
-{"monitorCommand", (unsigned long)monitorCommand},
-{"expireCommand", (unsigned long)expireCommand},
-{"expireatCommand", (unsigned long)expireatCommand},
-{"getsetCommand", (unsigned long)getsetCommand},
-{"ttlCommand", (unsigned long)ttlCommand},
-{"slaveofCommand", (unsigned long)slaveofCommand},
-{"debugCommand", (unsigned long)debugCommand},
-{"processCommand", (unsigned long)processCommand},
-{"setupSigSegvAction", (unsigned long)setupSigSegvAction},
-{"readQueryFromClient", (unsigned long)readQueryFromClient},
-{"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile},
-{"msetGenericCommand", (unsigned long)msetGenericCommand},
-{"msetCommand", (unsigned long)msetCommand},
-{"msetnxCommand", (unsigned long)msetnxCommand},
-{"zslCreateNode", (unsigned long)zslCreateNode},
-{"zslCreate", (unsigned long)zslCreate},
-{"zslFreeNode",(unsigned long)zslFreeNode},
-{"zslFree",(unsigned long)zslFree},
-{"zslRandomLevel",(unsigned long)zslRandomLevel},
-{"zslInsert",(unsigned long)zslInsert},
-{"zslDelete",(unsigned long)zslDelete},
-{"createZsetObject",(unsigned long)createZsetObject},
-{"zaddCommand",(unsigned long)zaddCommand},
-{"zrangeGenericCommand",(unsigned long)zrangeGenericCommand},
-{"zrangeCommand",(unsigned long)zrangeCommand},
-{"zrevrangeCommand",(unsigned long)zrevrangeCommand},
-{"zremCommand",(unsigned long)zremCommand},
-{"rdbSaveDoubleValue",(unsigned long)rdbSaveDoubleValue},
-{"rdbLoadDoubleValue",(unsigned long)rdbLoadDoubleValue},
-{"feedAppendOnlyFile",(unsigned long)feedAppendOnlyFile},
-{NULL,0}
-};
+/* =================================== Main! ================================ */
-/* This function try to convert a pointer into a function name. It's used in
- * oreder to provide a backtrace under segmentation fault that's able to
- * display functions declared as static (otherwise the backtrace is useless). */
-static char *findFuncName(void *pointer, unsigned long *offset){
- int i, ret = -1;
- unsigned long off, minoff = 0;
+#ifdef __linux__
+int linuxOvercommitMemoryValue(void) {
+ FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
+ char buf[64];
- /* Try to match against the Symbol with the smallest offset */
- for (i=0; symsTable[i].pointer; i++) {
- unsigned long lp = (unsigned long) pointer;
+ if (!fp) return -1;
+ if (fgets(buf,64,fp) == NULL) {
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
- if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
- off=lp-symsTable[i].pointer;
- if (ret < 0 || off < minoff) {
- minoff=off;
- ret=i;
- }
- }
+ return atoi(buf);
+}
+
+void linuxOvercommitMemoryWarning(void) {
+ if (linuxOvercommitMemoryValue() == 0) {
+ redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
+ }
+}
+#endif /* __linux__ */
+
+static void daemonize(void) {
+ int fd;
+ FILE *fp;
+
+ if (fork() != 0) exit(0); /* parent exits */
+ setsid(); /* create a new session */
+
+ /* Every output goes to /dev/null. If Redis is daemonized but
+ * the 'logfile' is set to 'stdout' in the configuration file
+ * it will not log at all. */
+ if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO) close(fd);
+ }
+ /* Try to write the pid file */
+ fp = fopen(server.pidfile,"w");
+ if (fp) {
+ fprintf(fp,"%d\n",getpid());
+ fclose(fp);
}
- if (ret == -1) return NULL;
- *offset = minoff;
- return symsTable[ret].name;
}
+int main(int argc, char **argv) {
+ initServerConfig();
+ if (argc == 2) {
+ resetServerSaveParams();
+ loadServerConfig(argv[1]);
+ } else if (argc > 2) {
+ fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
+ exit(1);
+ } else {
+ redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'");
+ }
+ initServer();
+ if (server.daemonize) daemonize();
+ redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
+#ifdef __linux__
+ linuxOvercommitMemoryWarning();
+#endif
+ if (server.appendonly) {
+ if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
+ redisLog(REDIS_NOTICE,"DB loaded from append only file");
+ } else {
+ if (rdbLoad(server.dbfilename) == REDIS_OK)
+ redisLog(REDIS_NOTICE,"DB loaded from disk");
+ }
+ if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
+ acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
+ redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
+ aeMain(server.el);
+ aeDeleteEventLoop(server.el);
+ return 0;
+}
+
+/* ============================= Backtrace support ========================= */
+
+#ifdef HAVE_BACKTRACE
+static char *findFuncName(void *pointer, unsigned long *offset);
+
static void *getMcontextEip(ucontext_t *uc) {
#if defined(__FreeBSD__)
return (void*) uc->uc_mcontext.mc_eip;
@@ -5772,87 +5714,39 @@ static void setupSigSegvAction(void) {
sigaction (SIGBUS, &act, NULL);
return;
}
-#else /* HAVE_BACKTRACE */
-static void setupSigSegvAction(void) {
-}
-#endif /* HAVE_BACKTRACE */
-/* =================================== Main! ================================ */
+#include "staticsymbols.h"
+/* This function try to convert a pointer into a function name. It's used in
+ * oreder to provide a backtrace under segmentation fault that's able to
+ * display functions declared as static (otherwise the backtrace is useless). */
+static char *findFuncName(void *pointer, unsigned long *offset){
+ int i, ret = -1;
+ unsigned long off, minoff = 0;
-#ifdef __linux__
-int linuxOvercommitMemoryValue(void) {
- FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
- char buf[64];
+ /* Try to match against the Symbol with the smallest offset */
+ for (i=0; symsTable[i].pointer; i++) {
+ unsigned long lp = (unsigned long) pointer;
- if (!fp) return -1;
- if (fgets(buf,64,fp) == NULL) {
- fclose(fp);
- return -1;
+ if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
+ off=lp-symsTable[i].pointer;
+ if (ret < 0 || off < minoff) {
+ minoff=off;
+ ret=i;
+ }
+ }
}
- fclose(fp);
-
- return atoi(buf);
+ if (ret == -1) return NULL;
+ *offset = minoff;
+ return symsTable[ret].name;
}
-
-void linuxOvercommitMemoryWarning(void) {
- if (linuxOvercommitMemoryValue() == 0) {
- redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
- }
+#else /* HAVE_BACKTRACE */
+static void setupSigSegvAction(void) {
}
-#endif /* __linux__ */
+#endif /* HAVE_BACKTRACE */
-static void daemonize(void) {
- int fd;
- FILE *fp;
- if (fork() != 0) exit(0); /* parent exits */
- setsid(); /* create a new session */
- /* Every output goes to /dev/null. If Redis is daemonized but
- * the 'logfile' is set to 'stdout' in the configuration file
- * it will not log at all. */
- if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO) close(fd);
- }
- /* Try to write the pid file */
- fp = fopen(server.pidfile,"w");
- if (fp) {
- fprintf(fp,"%d\n",getpid());
- fclose(fp);
- }
-}
+/* The End */
+
+
-int main(int argc, char **argv) {
- initServerConfig();
- if (argc == 2) {
- ResetServerSaveParams();
- loadServerConfig(argv[1]);
- } else if (argc > 2) {
- fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
- exit(1);
- } else {
- redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'");
- }
- initServer();
- if (server.daemonize) daemonize();
- redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
-#ifdef __linux__
- linuxOvercommitMemoryWarning();
-#endif
- if (server.appendonly) {
- if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
- redisLog(REDIS_NOTICE,"DB loaded from append only file");
- } else {
- if (rdbLoad(server.dbfilename) == REDIS_OK)
- redisLog(REDIS_NOTICE,"DB loaded from disk");
- }
- if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
- acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
- redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
- aeMain(server.el);
- aeDeleteEventLoop(server.el);
- return 0;
-}
diff --git a/staticsymbols.h b/staticsymbols.h
new file mode 100644
index 000000000..b1fc36f42
--- /dev/null
+++ b/staticsymbols.h
@@ -0,0 +1,189 @@
+static struct redisFunctionSym symsTable[] = {
+{"acceptHandler",(unsigned long)acceptHandler},
+{"addReply",(unsigned long)addReply},
+{"addReplyBulkLen",(unsigned long)addReplyBulkLen},
+{"addReplySds",(unsigned long)addReplySds},
+{"appendServerSaveParams",(unsigned long)appendServerSaveParams},
+{"authCommand",(unsigned long)authCommand},
+{"bgsaveCommand",(unsigned long)bgsaveCommand},
+{"closeTimedoutClients",(unsigned long)closeTimedoutClients},
+{"compareStringObjects",(unsigned long)compareStringObjects},
+{"createClient",(unsigned long)createClient},
+{"createListObject",(unsigned long)createListObject},
+{"createObject",(unsigned long)createObject},
+{"createSetObject",(unsigned long)createSetObject},
+{"createSharedObjects",(unsigned long)createSharedObjects},
+{"createSortOperation",(unsigned long)createSortOperation},
+{"createStringObject",(unsigned long)createStringObject},
+{"createZsetObject",(unsigned long)createZsetObject},
+{"daemonize",(unsigned long)daemonize},
+{"dbsizeCommand",(unsigned long)dbsizeCommand},
+{"debugCommand",(unsigned long)debugCommand},
+{"decrCommand",(unsigned long)decrCommand},
+{"decrRefCount",(unsigned long)decrRefCount},
+{"decrbyCommand",(unsigned long)decrbyCommand},
+{"delCommand",(unsigned long)delCommand},
+{"deleteIfVolatile",(unsigned long)deleteIfVolatile},
+{"deleteKey",(unsigned long)deleteKey},
+{"dictEncObjKeyCompare",(unsigned long)dictEncObjKeyCompare},
+{"dictObjKeyCompare",(unsigned long)dictObjKeyCompare},
+{"dictRedisObjectDestructor",(unsigned long)dictRedisObjectDestructor},
+{"dictVanillaFree",(unsigned long)dictVanillaFree},
+{"dupClientReplyValue",(unsigned long)dupClientReplyValue},
+{"echoCommand",(unsigned long)echoCommand},
+{"existsCommand",(unsigned long)existsCommand},
+{"expireCommand",(unsigned long)expireCommand},
+{"expireGenericCommand",(unsigned long)expireGenericCommand},
+{"expireIfNeeded",(unsigned long)expireIfNeeded},
+{"expireatCommand",(unsigned long)expireatCommand},
+{"feedAppendOnlyFile",(unsigned long)feedAppendOnlyFile},
+{"findFuncName",(unsigned long)findFuncName},
+{"flushallCommand",(unsigned long)flushallCommand},
+{"flushdbCommand",(unsigned long)flushdbCommand},
+{"freeClient",(unsigned long)freeClient},
+{"freeClientArgv",(unsigned long)freeClientArgv},
+{"freeFakeClient",(unsigned long)freeFakeClient},
+{"freeHashObject",(unsigned long)freeHashObject},
+{"freeListObject",(unsigned long)freeListObject},
+{"freeMemoryIfNeeded",(unsigned long)freeMemoryIfNeeded},
+{"freeSetObject",(unsigned long)freeSetObject},
+{"freeStringObject",(unsigned long)freeStringObject},
+{"freeZsetObject",(unsigned long)freeZsetObject},
+{"getCommand",(unsigned long)getCommand},
+{"getDecodedObject",(unsigned long)getDecodedObject},
+{"getExpire",(unsigned long)getExpire},
+{"getMcontextEip",(unsigned long)getMcontextEip},
+{"getsetCommand",(unsigned long)getsetCommand},
+{"glueReplyBuffersIfNeeded",(unsigned long)glueReplyBuffersIfNeeded},
+{"htNeedsResize",(unsigned long)htNeedsResize},
+{"incrCommand",(unsigned long)incrCommand},
+{"incrDecrCommand",(unsigned long)incrDecrCommand},
+{"incrRefCount",(unsigned long)incrRefCount},
+{"incrbyCommand",(unsigned long)incrbyCommand},
+{"infoCommand",(unsigned long)infoCommand},
+{"initServer",(unsigned long)initServer},
+{"initServerConfig",(unsigned long)initServerConfig},
+{"isStringRepresentableAsLong",(unsigned long)isStringRepresentableAsLong},
+{"keysCommand",(unsigned long)keysCommand},
+{"lastsaveCommand",(unsigned long)lastsaveCommand},
+{"lindexCommand",(unsigned long)lindexCommand},
+{"llenCommand",(unsigned long)llenCommand},
+{"loadServerConfig",(unsigned long)loadServerConfig},
+{"lookupKey",(unsigned long)lookupKey},
+{"lookupKeyByPattern",(unsigned long)lookupKeyByPattern},
+{"lookupKeyRead",(unsigned long)lookupKeyRead},
+{"lookupKeyWrite",(unsigned long)lookupKeyWrite},
+{"lpopCommand",(unsigned long)lpopCommand},
+{"lpushCommand",(unsigned long)lpushCommand},
+{"lrangeCommand",(unsigned long)lrangeCommand},
+{"lremCommand",(unsigned long)lremCommand},
+{"lsetCommand",(unsigned long)lsetCommand},
+{"ltrimCommand",(unsigned long)ltrimCommand},
+{"mgetCommand",(unsigned long)mgetCommand},
+{"monitorCommand",(unsigned long)monitorCommand},
+{"moveCommand",(unsigned long)moveCommand},
+{"msetCommand",(unsigned long)msetCommand},
+{"msetGenericCommand",(unsigned long)msetGenericCommand},
+{"msetnxCommand",(unsigned long)msetnxCommand},
+{"oom",(unsigned long)oom},
+{"pingCommand",(unsigned long)pingCommand},
+{"popGenericCommand",(unsigned long)popGenericCommand},
+{"processCommand",(unsigned long)processCommand},
+{"processInputBuffer",(unsigned long)processInputBuffer},
+{"pushGenericCommand",(unsigned long)pushGenericCommand},
+{"qsortCompareSetsByCardinality",(unsigned long)qsortCompareSetsByCardinality},
+{"randomkeyCommand",(unsigned long)randomkeyCommand},
+{"rdbLoad",(unsigned long)rdbLoad},
+{"rdbLoadDoubleValue",(unsigned long)rdbLoadDoubleValue},
+{"rdbLoadIntegerObject",(unsigned long)rdbLoadIntegerObject},
+{"rdbLoadLen",(unsigned long)rdbLoadLen},
+{"rdbLoadLzfStringObject",(unsigned long)rdbLoadLzfStringObject},
+{"rdbLoadStringObject",(unsigned long)rdbLoadStringObject},
+{"rdbLoadTime",(unsigned long)rdbLoadTime},
+{"rdbLoadType",(unsigned long)rdbLoadType},
+{"rdbRemoveTempFile",(unsigned long)rdbRemoveTempFile},
+{"rdbSave",(unsigned long)rdbSave},
+{"rdbSaveBackground",(unsigned long)rdbSaveBackground},
+{"rdbSaveDoubleValue",(unsigned long)rdbSaveDoubleValue},
+{"rdbSaveLen",(unsigned long)rdbSaveLen},
+{"rdbSaveLzfStringObject",(unsigned long)rdbSaveLzfStringObject},
+{"rdbSaveStringObject",(unsigned long)rdbSaveStringObject},
+{"rdbSaveStringObjectRaw",(unsigned long)rdbSaveStringObjectRaw},
+{"rdbSaveTime",(unsigned long)rdbSaveTime},
+{"rdbSaveType",(unsigned long)rdbSaveType},
+{"rdbTryIntegerEncoding",(unsigned long)rdbTryIntegerEncoding},
+{"readQueryFromClient",(unsigned long)readQueryFromClient},
+{"redisLog",(unsigned long)redisLog},
+{"removeExpire",(unsigned long)removeExpire},
+{"renameCommand",(unsigned long)renameCommand},
+{"renameGenericCommand",(unsigned long)renameGenericCommand},
+{"renamenxCommand",(unsigned long)renamenxCommand},
+{"replicationFeedSlaves",(unsigned long)replicationFeedSlaves},
+{"resetClient",(unsigned long)resetClient},
+{"resetServerSaveParams",(unsigned long)resetServerSaveParams},
+{"rpopCommand",(unsigned long)rpopCommand},
+{"rpushCommand",(unsigned long)rpushCommand},
+{"saddCommand",(unsigned long)saddCommand},
+{"saveCommand",(unsigned long)saveCommand},
+{"scardCommand",(unsigned long)scardCommand},
+{"sdiffCommand",(unsigned long)sdiffCommand},
+{"sdiffstoreCommand",(unsigned long)sdiffstoreCommand},
+{"sdsDictKeyCompare",(unsigned long)sdsDictKeyCompare},
+{"segvHandler",(unsigned long)segvHandler},
+{"selectCommand",(unsigned long)selectCommand},
+{"selectDb",(unsigned long)selectDb},
+{"sendBulkToSlave",(unsigned long)sendBulkToSlave},
+{"sendReplyToClient",(unsigned long)sendReplyToClient},
+{"serverCron",(unsigned long)serverCron},
+{"setCommand",(unsigned long)setCommand},
+{"setExpire",(unsigned long)setExpire},
+{"setGenericCommand",(unsigned long)setGenericCommand},
+{"setnxCommand",(unsigned long)setnxCommand},
+{"setupSigSegvAction",(unsigned long)setupSigSegvAction},
+{"shutdownCommand",(unsigned long)shutdownCommand},
+{"sinterCommand",(unsigned long)sinterCommand},
+{"sinterGenericCommand",(unsigned long)sinterGenericCommand},
+{"sinterstoreCommand",(unsigned long)sinterstoreCommand},
+{"sismemberCommand",(unsigned long)sismemberCommand},
+{"slaveofCommand",(unsigned long)slaveofCommand},
+{"smoveCommand",(unsigned long)smoveCommand},
+{"sortCommand",(unsigned long)sortCommand},
+{"sortCompare",(unsigned long)sortCompare},
+{"spopCommand",(unsigned long)spopCommand},
+{"srandmemberCommand",(unsigned long)srandmemberCommand},
+{"sremCommand",(unsigned long)sremCommand},
+{"stringObjectLen",(unsigned long)stringObjectLen},
+{"sunionCommand",(unsigned long)sunionCommand},
+{"sunionDiffGenericCommand",(unsigned long)sunionDiffGenericCommand},
+{"sunionstoreCommand",(unsigned long)sunionstoreCommand},
+{"syncCommand",(unsigned long)syncCommand},
+{"syncRead",(unsigned long)syncRead},
+{"syncReadLine",(unsigned long)syncReadLine},
+{"syncWithMaster",(unsigned long)syncWithMaster},
+{"syncWrite",(unsigned long)syncWrite},
+{"tryObjectEncoding",(unsigned long)tryObjectEncoding},
+{"tryObjectSharing",(unsigned long)tryObjectSharing},
+{"tryResizeHashTables",(unsigned long)tryResizeHashTables},
+{"ttlCommand",(unsigned long)ttlCommand},
+{"typeCommand",(unsigned long)typeCommand},
+{"updateSlavesWaitingBgsave",(unsigned long)updateSlavesWaitingBgsave},
+{"yesnotoi",(unsigned long)yesnotoi},
+{"zaddCommand",(unsigned long)zaddCommand},
+{"zcardCommand",(unsigned long)zcardCommand},
+{"zrangeCommand",(unsigned long)zrangeCommand},
+{"zrangeGenericCommand",(unsigned long)zrangeGenericCommand},
+{"zrangebyscoreCommand",(unsigned long)zrangebyscoreCommand},
+{"zremCommand",(unsigned long)zremCommand},
+{"zremrangebyscoreCommand",(unsigned long)zremrangebyscoreCommand},
+{"zrevrangeCommand",(unsigned long)zrevrangeCommand},
+{"zscoreCommand",(unsigned long)zscoreCommand},
+{"zslCreate",(unsigned long)zslCreate},
+{"zslCreateNode",(unsigned long)zslCreateNode},
+{"zslDelete",(unsigned long)zslDelete},
+{"zslFirstWithScore",(unsigned long)zslFirstWithScore},
+{"zslFree",(unsigned long)zslFree},
+{"zslFreeNode",(unsigned long)zslFreeNode},
+{"zslInsert",(unsigned long)zslInsert},
+{"zslRandomLevel",(unsigned long)zslRandomLevel},
+{NULL,0}
+};
diff --git a/utils/build-static-symbols.tcl b/utils/build-static-symbols.tcl
new file mode 100644
index 000000000..e634cbe0f
--- /dev/null
+++ b/utils/build-static-symbols.tcl
@@ -0,0 +1,22 @@
+# Build a symbol table for static symbols of redis.c
+# Useful to get stack traces on segfault without a debugger. See redis.c
+# for more information.
+#
+# Copyright(C) 2009 Salvatore Sanfilippo, under the BSD license.
+
+set fd [open redis.c]
+set symlist {}
+while {[gets $fd line] != -1} {
+ if {[regexp {^static +[A-z0-9]+[ *]+([A-z0-9]*)\(} $line - sym]} {
+ lappend symlist $sym
+ }
+}
+set symlist [lsort -unique $symlist]
+puts "static struct redisFunctionSym symsTable\[\] = {"
+foreach sym $symlist {
+ puts "{\"$sym\",(unsigned long)$sym},"
+}
+puts "{NULL,0}"
+puts "};"
+
+close $fd