]> git.saurik.com Git - redis.git/commitdiff
Merge git://github.com/dierbro/redis
authorantirez <antirez@gmail.com>
Sat, 6 Jun 2009 21:40:48 +0000 (23:40 +0200)
committerantirez <antirez@gmail.com>
Sat, 6 Jun 2009 21:40:48 +0000 (23:40 +0200)
1  2 
Makefile
redis.c

diff --combined Makefile
index f7c546470bca60c39e5e658a072801f63140ee6a,9fc0caf0054b2da475da8feb68d8d7bcb2547b6c..fda703e1e2d74ae40c438ab13897761961d22572
+++ b/Makefile
@@@ -2,8 -2,8 +2,8 @@@
  # Copyright (C) 2009 Salvatore Sanfilippo <antirez at gmail dot com>
  # This file is released under the BSD license, see the COPYING file
  
- DEBUG?= -g
- CFLAGS?= -std=c99 -pedantic -O2 -Wall -W -DSDS_ABORT_ON_OOM
+ DEBUG?= -g -rdynamic -ggdb 
+ CFLAGS?= -std=c99 -pedantic -O0 -Wall -W -DSDS_ABORT_ON_OOM
  CCOPT= $(CFLAGS)
  
  OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o
@@@ -17,18 -17,16 +17,18 @@@ CLIPRGNAME = redis-cl
  all: redis-server redis-benchmark redis-cli
  
  # Deps (use make dep to generate this)
 -adlist.o: adlist.c adlist.h
 -ae.o: ae.c ae.h
 -anet.o: anet.c anet.h
 -benchmark.o: benchmark.c ae.h anet.h sds.h adlist.h
 -dict.o: dict.c dict.h
 -redis-cli.o: redis-cli.c anet.h sds.h adlist.h
 -redis.o: redis.c ae.h sds.h anet.h dict.h adlist.h zmalloc.c zmalloc.h
 -sds.o: sds.c sds.h
 -sha1.o: sha1.c sha1.h
 -zmalloc.o: zmalloc.c
 +adlist.o: adlist.c adlist.h zmalloc.h
 +ae.o: ae.c ae.h zmalloc.h
 +anet.o: anet.c fmacros.h anet.h
 +benchmark.o: benchmark.c fmacros.h ae.h anet.h sds.h adlist.h zmalloc.h
 +dict.o: dict.c fmacros.h dict.h zmalloc.h
 +lzf_c.o: lzf_c.c lzfP.h
 +lzf_d.o: lzf_d.c lzfP.h
 +pqsort.o: pqsort.c
 +redis-cli.o: redis-cli.c fmacros.h anet.h sds.h adlist.h zmalloc.h
 +redis.o: redis.c fmacros.h ae.h sds.h anet.h dict.h adlist.h zmalloc.h lzf.h pqsort.h config.h
 +sds.o: sds.c sds.h zmalloc.h
 +zmalloc.o: zmalloc.c config.h
  
  redis-server: $(OBJ)
        $(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ)
diff --combined redis.c
index f9fb368231cff6c732e0292d71334cf97087fc2a,57c7ed1fc1d2242a30a5606dea80b053c1f50509..56ddee9e130a5d3eae3dff8d2cd778f77f98d963
+++ b/redis.c
  #include <string.h>
  #include <time.h>
  #include <unistd.h>
+ #define __USE_POSIX199309
  #include <signal.h>
+ #include <execinfo.h>
+ #include <ucontext.h>
  #include <sys/wait.h>
  #include <errno.h>
  #include <assert.h>
@@@ -51,6 -54,7 +54,7 @@@
  #include <limits.h>
  #include <execinfo.h>
  
+ #include "redis.h"
  #include "ae.h"     /* Event driven programming library */
  #include "sds.h"    /* Dynamic safe strings */
  #include "anet.h"   /* Networking the easy way */
@@@ -60,8 -64,6 +64,8 @@@
  #include "lzf.h"    /* LZF compression library */
  #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
  
 +#include "config.h"
 +
  /* Error codes */
  #define REDIS_OK                0
  #define REDIS_ERR               -1
@@@ -77,7 -79,6 +81,7 @@@
  #define REDIS_OBJFREELIST_MAX   1000000 /* Max number of objects to cache */
  #define REDIS_MAX_SYNC_TIME     60      /* Slave can't take more to sync */
  #define REDIS_EXPIRELOOKUPS_PER_CRON    100 /* try to expire 100 keys/second */
 +#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
  
  /* Hash table parameters */
  #define REDIS_HT_MINFILL        10      /* Minimal hash table fill 10% */
  /* Anti-warning macro... */
  #define REDIS_NOTUSED(V) ((void) V)
  
  /*================================= Data types ============================== */
  
  /* A redis object, that is a type able to hold a string / list / set */
@@@ -241,7 -243,6 +246,7 @@@ struct redisServer 
      int daemonize;
      char *pidfile;
      int bgsaveinprogress;
 +    pid_t bgsavechildpid;
      struct saveparam *saveparams;
      int saveparamslen;
      char *logfile;
@@@ -272,6 -273,11 +277,11 @@@ struct redisCommand 
      int flags;
  };
  
+ struct redisFunctionSym {
+     char *name;
+     long pointer;
+ };
  typedef struct _redisSortObject {
      robj *obj;
      union {
@@@ -319,6 -325,7 +329,7 @@@ static time_t getExpire(redisDb *db, ro
  static int setExpire(redisDb *db, robj *key, time_t when);
  static void updateSalvesWaitingBgsave(int bgsaveerr);
  static void freeMemoryIfNeeded(void);
+ static int processCommand(redisClient *c);
  
  static void authCommand(redisClient *c);
  static void pingCommand(redisClient *c);
@@@ -377,7 -384,7 +388,7 @@@ static void getSetCommand(redisClient *
  static void ttlCommand(redisClient *c);
  static void slaveofCommand(redisClient *c);
  static void debugCommand(redisClient *c);
+ static void setupSigSegvAction();
  /*================================= Globals ================================= */
  
  /* Global vars */
@@@ -443,7 -450,91 +454,91 @@@ static struct redisCommand cmdTable[] 
      {"debug",debugCommand,-2,REDIS_CMD_INLINE},
      {NULL,NULL,0,0}
  };
+ static struct redisFunctionSym symsTable[] = {
+ {"freeStringObject", (long)freeStringObject},
+ {"freeListObject", (long)freeListObject},
+ {"freeSetObject", (long)freeSetObject},
+ {"decrRefCount", (long)decrRefCount},
+ {"createObject", (long)createObject},
+ {"freeClient", (long)freeClient},
+ {"rdbLoad", (long)rdbLoad},
+ {"addReply", (long)addReply},
+ {"addReplySds", (long)addReplySds},
+ {"incrRefCount", (long)incrRefCount},
+ {"rdbSaveBackground", (long)rdbSaveBackground},
+ {"createStringObject", (long)createStringObject},
+ {"replicationFeedSlaves", (long)replicationFeedSlaves},
+ {"syncWithMaster", (long)syncWithMaster},
+ {"tryObjectSharing", (long)tryObjectSharing},
+ {"removeExpire", (long)removeExpire},
+ {"expireIfNeeded", (long)expireIfNeeded},
+ {"deleteIfVolatile", (long)deleteIfVolatile},
+ {"deleteKey", (long)deleteKey},
+ {"getExpire", (long)getExpire},
+ {"setExpire", (long)setExpire},
+ {"updateSalvesWaitingBgsave", (long)updateSalvesWaitingBgsave},
+ {"freeMemoryIfNeeded", (long)freeMemoryIfNeeded},
+ {"authCommand", (long)authCommand},
+ {"pingCommand", (long)pingCommand},
+ {"echoCommand", (long)echoCommand},
+ {"setCommand", (long)setCommand},
+ {"setnxCommand", (long)setnxCommand},
+ {"getCommand", (long)getCommand},
+ {"delCommand", (long)delCommand},
+ {"existsCommand", (long)existsCommand},
+ {"incrCommand", (long)incrCommand},
+ {"decrCommand", (long)decrCommand},
+ {"incrbyCommand", (long)incrbyCommand},
+ {"decrbyCommand", (long)decrbyCommand},
+ {"selectCommand", (long)selectCommand},
+ {"randomkeyCommand", (long)randomkeyCommand},
+ {"keysCommand", (long)keysCommand},
+ {"dbsizeCommand", (long)dbsizeCommand},
+ {"lastsaveCommand", (long)lastsaveCommand},
+ {"saveCommand", (long)saveCommand},
+ {"bgsaveCommand", (long)bgsaveCommand},
+ {"shutdownCommand", (long)shutdownCommand},
+ {"moveCommand", (long)moveCommand},
+ {"renameCommand", (long)renameCommand},
+ {"renamenxCommand", (long)renamenxCommand},
+ {"lpushCommand", (long)lpushCommand},
+ {"rpushCommand", (long)rpushCommand},
+ {"lpopCommand", (long)lpopCommand},
+ {"rpopCommand", (long)rpopCommand},
+ {"llenCommand", (long)llenCommand},
+ {"lindexCommand", (long)lindexCommand},
+ {"lrangeCommand", (long)lrangeCommand},
+ {"ltrimCommand", (long)ltrimCommand},
+ {"typeCommand", (long)typeCommand},
+ {"lsetCommand", (long)lsetCommand},
+ {"saddCommand", (long)saddCommand},
+ {"sremCommand", (long)sremCommand},
+ {"smoveCommand", (long)smoveCommand},
+ {"sismemberCommand", (long)sismemberCommand},
+ {"scardCommand", (long)scardCommand},
+ {"sinterCommand", (long)sinterCommand},
+ {"sinterstoreCommand", (long)sinterstoreCommand},
+ {"sunionCommand", (long)sunionCommand},
+ {"sunionstoreCommand", (long)sunionstoreCommand},
+ {"sdiffCommand", (long)sdiffCommand},
+ {"sdiffstoreCommand", (long)sdiffstoreCommand},
+ {"syncCommand", (long)syncCommand},
+ {"flushdbCommand", (long)flushdbCommand},
+ {"flushallCommand", (long)flushallCommand},
+ {"sortCommand", (long)sortCommand},
+ {"lremCommand", (long)lremCommand},
+ {"infoCommand", (long)infoCommand},
+ {"mgetCommand", (long)mgetCommand},
+ {"monitorCommand", (long)monitorCommand},
+ {"expireCommand", (long)expireCommand},
+ {"getSetCommand", (long)getSetCommand},
+ {"ttlCommand", (long)ttlCommand},
+ {"slaveofCommand", (long)slaveofCommand},
+ {"debugCommand", (long)debugCommand},
+ {"processCommand", (long)processCommand},
+ {"setupSigSegvAction", (long)setupSigSegvAction},
+ {NULL,0}
+ };
  /*============================ Utility functions ============================ */
  
  /* Glob-style pattern matching. */
@@@ -750,21 -841,16 +845,21 @@@ int serverCron(struct aeEventLoop *even
          /* XXX: TODO handle the case of the saving child killed */
          if (wait4(-1,&statloc,WNOHANG,NULL)) {
              int exitcode = WEXITSTATUS(statloc);
 -            if (exitcode == 0) {
 +            int bysignal = WIFSIGNALED(statloc);
 +
 +            if (!bysignal && exitcode == 0) {
                  redisLog(REDIS_NOTICE,
                      "Background saving terminated with success");
                  server.dirty = 0;
                  server.lastsave = time(NULL);
 +            } else if (!bysignal && exitcode != 0) {
 +                redisLog(REDIS_WARNING, "Background saving error");
              } else {
                  redisLog(REDIS_WARNING,
 -                    "Background saving error");
 +                    "Background saving terminated by signal");
              }
              server.bgsaveinprogress = 0;
 +            server.bgsavechildpid = -1;
              updateSalvesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
          }
      } else {
@@@ -902,6 -988,7 +997,7 @@@ static void initServer() 
  
      signal(SIGHUP, SIG_IGN);
      signal(SIGPIPE, SIG_IGN);
+     setupSigSegvAction();
  
      server.clients = listCreate();
      server.slaves = listCreate();
      }
      server.cronloops = 0;
      server.bgsaveinprogress = 0;
 +    server.bgsavechildpid = -1;
      server.lastsave = time(NULL);
      server.dirty = 0;
      server.usedmemory = 0;
@@@ -1178,7 -1264,6 +1274,7 @@@ static void sendReplyToClient(aeEventLo
          }
  
          if (c->flags & REDIS_MASTER) {
 +            /* Don't reply to a master */
              nwritten = objlen - c->sentlen;
          } else {
              nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
              listDelNode(c->reply,listFirst(c->reply));
              c->sentlen = 0;
          }
 +        /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
 +         * bytes, in a single threaded server it's a good idea to server
 +         * other clients as well, even if a very large request comes from
 +         * super fast link that is always able to accept data (in real world
 +         * terms think to 'KEYS *' against the loopback interfae) */
 +        if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
      }
      if (nwritten == -1) {
          if (errno == EAGAIN) {
@@@ -1998,7 -2077,6 +2094,7 @@@ static int rdbSaveBackground(char *file
          }
          redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
          server.bgsaveinprogress = 1;
 +        server.bgsavechildpid = childpid;
          return REDIS_OK;
      }
      return REDIS_OK; /* unreached */
@@@ -2521,19 -2599,15 +2617,19 @@@ static void bgsaveCommand(redisClient *
  
  static void shutdownCommand(redisClient *c) {
      redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
 -    /* XXX: TODO kill the child if there is a bgsave in progress */
 +    if (server.bgsaveinprogress) {
 +        redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
 +        signal(SIGCHLD, SIG_IGN);
 +        kill(server.bgsavechildpid,SIGKILL);
 +    }
      if (rdbSave(server.dbfilename) == REDIS_OK) {
 -        if (server.daemonize) {
 +        if (server.daemonize)
              unlink(server.pidfile);
 -        }
          redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
          redisLog(REDIS_WARNING,"Server exit now, bye bye...");
          exit(1);
      } else {
 +        signal(SIGCHLD, SIG_DFL);
          redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit"); 
          addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
      }
@@@ -2880,7 -2954,7 +2976,7 @@@ static void lremCommand(redisClient *c
      
      o = lookupKeyWrite(c->db,c->argv[1]);
      if (o == NULL) {
 -        addReply(c,shared.nokeyerr);
 +        addReply(c,shared.czero);
      } else {
          if (o->type != REDIS_LIST) {
              addReply(c,shared.wrongtypeerr);
@@@ -3888,7 -3962,7 +3984,7 @@@ static void updateSalvesWaitingBgsave(i
              startbgsave = 1;
              slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
          } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
 -            struct stat buf;
 +            struct redis_stat buf;
             
              if (bgsaveerr != REDIS_OK) {
                  freeClient(slave);
                  continue;
              }
              if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
 -                fstat(slave->repldbfd,&buf) == -1) {
 +                redis_fstat(slave->repldbfd,&buf) == -1) {
                  freeClient(slave);
                  redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
                  continue;
@@@ -4096,7 -4170,94 +4192,94 @@@ static void debugCommand(redisClient *c
              "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
      }
  }
+ char *findFuncName(void *pointer, long *offset){
+       int i, ret=-1;
+       long val, off;
+       for(i=0; symsTable[i].pointer!=0; i++){
+               val=(long)pointer-symsTable[i].pointer;
+               if(val>=0 && (off<0 || val <= off)){
+                       off=val;
+                       ret=i;
+               }
+       }
+       if(ret<0)
+               *offset=0;
+       else
+               *offset=off;
+       return ret>=0?symsTable[ret].name:"unknown";
+ }
+ static void segvHandler (int sig, siginfo_t *info, void *secret) {
+   void *trace[100];
+   char **messages = (char **)NULL;
+   char *tmp;
+   int i, trace_size = 0;
+   long offset=0;
+   ucontext_t *uc = (ucontext_t *)secret;
+   time_t uptime = time(NULL)-server.stat_starttime;
+   redisLog(REDIS_WARNING, "application: redis,  signal: segmentation fault -%d-",REDIS_VERSION, sig);
+   redisLog(REDIS_WARNING, "%s", sdscatprintf(sdsempty(),
+         "redis_version:%s; "
+         "uptime_in_days:%d; "
+         "connected_clients:%d; "
+         "connected_slaves:%d; "
+         "used_memory:%zu; "
+         "changes_since_last_save:%lld; "
+         "bgsave_in_progress:%d; "
+         "last_save_time:%d; "
+         "total_connections_received:%lld; "
+         "total_commands_processed:%lld; "
+         "role:%s;"
+         ,REDIS_VERSION,
+         uptime,
+         listLength(server.clients)-listLength(server.slaves),
+         listLength(server.slaves),
+         server.usedmemory,
+         server.dirty,
+         server.bgsaveinprogress,
+         server.lastsave,
+         server.stat_numconnections,
+         server.stat_numcommands,
+         server.masterhost == NULL ? "master" : "slave"
+     ));
+   redisLog(REDIS_WARNING,"EIP %p",  (void *)uc->uc_mcontext.gregs[REG_EIP]);
+   redisLog(REDIS_WARNING,"EAX %p, EBX %p,  ECX %p, EDX %p", (void *)uc->uc_mcontext.gregs[REG_EAX], (void *)uc->uc_mcontext.gregs[REG_EBX],  (void *)uc->uc_mcontext.gregs[REG_ECX], (void *)uc->uc_mcontext.gregs[REG_EDX]);
+  
+       
+   trace_size = backtrace(trace, 100);
+   char pointer[trace_size][11];
+     /* overwrite sigaction with caller's address */
+   trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
+  for (i=1; i<trace_size; ++i)
+       snprintf(pointer[i],11,"[%p]", trace[i]);
+   messages = backtrace_symbols(trace, trace_size);
+   
+   for (i=1; i<trace_size; ++i){
+       tmp=strstr(messages[i],pointer[i]);
+       if((tmp-2)[0]!=')'){
+               char *a=findFuncName(trace[i], &offset);
+               redisLog(REDIS_WARNING,"#%d (%s+0x%x) %s", i, a, (unsigned int)offset, tmp);
+               }
+       else
+               redisLog(REDIS_WARNING,"#%d %s", i, messages[i]);
+       }
+   free(messages);
+   exit(0);
+ }
+ void setupSigSegvAction(){
+   struct sigaction act;
+   sigemptyset (&act.sa_mask);
+   /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction  is used. Otherwise, sa_handler is used */
+   act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
+   act.sa_sigaction = segvHandler;
+   sigaction (SIGSEGV, &act, NULL);
+ }
  /* =================================== Main! ================================ */
  
  #ifdef __linux__
@@@ -4149,7 -4310,7 +4332,7 @@@ int main(int argc, char **argv) 
  #ifdef __linux__
      linuxOvercommitMemoryWarning();
  #endif
+     
      initServerConfig();
      if (argc == 2) {
          ResetServerSaveParams();