X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/42c571864e38016d5711e4cd55fb87dd411a064e..d10a01bb6d8645f66b66e1fb3d1c52a0dd7bd8fe:/src/redis.c diff --git a/src/redis.c b/src/redis.c index e636aa9b..024403fd 100644 --- a/src/redis.c +++ b/src/redis.c @@ -152,7 +152,7 @@ struct redisCommand redisCommandTable[] = { {"sismember",sismemberCommand,3,"r",0,NULL,1,1,1,0,0}, {"scard",scardCommand,2,"r",0,NULL,1,1,1,0,0}, {"spop",spopCommand,2,"wRs",0,NULL,1,1,1,0,0}, - {"srandmember",srandmemberCommand,2,"rR",0,NULL,1,1,1,0,0}, + {"srandmember",srandmemberCommand,-2,"rR",0,NULL,1,1,1,0,0}, {"sinter",sinterCommand,-2,"rS",0,NULL,1,-1,1,0,0}, {"sinterstore",sinterstoreCommand,-3,"wm",0,NULL,1,-1,1,0,0}, {"sunion",sunionCommand,-2,"rS",0,NULL,1,-1,1,0,0}, @@ -222,7 +222,7 @@ struct redisCommand redisCommandTable[] = { {"replconf",replconfCommand,-1,"ars",0,NULL,0,0,0,0,0}, {"flushdb",flushdbCommand,1,"w",0,NULL,0,0,0,0,0}, {"flushall",flushallCommand,1,"w",0,NULL,0,0,0,0,0}, - {"sort",sortCommand,-2,"wmS",0,NULL,1,1,1,0,0}, + {"sort",sortCommand,-2,"wm",0,NULL,1,1,1,0,0}, {"info",infoCommand,-1,"rlt",0,NULL,0,0,0,0,0}, {"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0}, {"ttl",ttlCommand,2,"r",0,NULL,1,1,1,0,0}, @@ -334,17 +334,6 @@ err: if (server.logfile) close(fd); } -/* Redis generally does not try to recover from out of memory conditions - * when allocating objects or strings, it is not clear if it will be possible - * to report this condition to the client since the networking layer itself - * is based on heap allocation for send buffers, so we simply abort. - * At least the code will be simpler to read... */ -void oom(const char *msg) { - redisLog(REDIS_WARNING, "%s: Out of memory\n",msg); - sleep(1); - abort(); -} - /* Return the UNIX time in microseconds */ long long ustime(void) { struct timeval tv; @@ -1078,6 +1067,7 @@ void createSharedObjects(void) { shared.del = createStringObject("DEL",3); shared.rpop = createStringObject("RPOP",4); shared.lpop = createStringObject("LPOP",4); + shared.lpush = createStringObject("LPUSH",5); for (j = 0; j < REDIS_SHARED_INTEGERS; j++) { shared.integers[j] = createObject(REDIS_STRING,(void*)(long)j); shared.integers[j]->encoding = REDIS_ENCODING_INT; @@ -1121,6 +1111,7 @@ void initServerConfig() { server.aof_last_fsync = time(NULL); server.aof_rewrite_time_last = -1; server.aof_rewrite_time_start = -1; + server.aof_lastbgrewrite_status = REDIS_OK; server.aof_delayed_fsync = 0; server.aof_fd = -1; server.aof_selected_db = -1; /* Make sure the first time will not match */ @@ -1170,6 +1161,7 @@ void initServerConfig() { server.repl_serve_stale_data = 1; server.repl_slave_ro = 1; server.repl_down_since = time(NULL); + server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY; /* Client output buffer limits */ server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_NORMAL].hard_limit_bytes = 0; @@ -1196,6 +1188,8 @@ void initServerConfig() { server.delCommand = lookupCommandByCString("del"); server.multiCommand = lookupCommandByCString("multi"); server.lpushCommand = lookupCommandByCString("lpush"); + server.lpopCommand = lookupCommandByCString("lpop"); + server.rpopCommand = lookupCommandByCString("rpop"); /* Slow log */ server.slowlog_log_slower_than = REDIS_SLOWLOG_LOG_SLOWER_THAN; @@ -1271,6 +1265,7 @@ void initServer() { server.slaves = listCreate(); server.monitors = listCreate(); server.unblocked_clients = listCreate(); + server.ready_keys = listCreate(); createSharedObjects(); adjustOpenFilesLimit(); @@ -1301,6 +1296,7 @@ void initServer() { server.db[j].dict = dictCreate(&dbDictType,NULL); server.db[j].expires = dictCreate(&keyptrDictType,NULL); server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL); + server.db[j].ready_keys = dictCreate(&setDictType,NULL); server.db[j].watched_keys = dictCreate(&keylistDictType,NULL); server.db[j].id = j; } @@ -1336,9 +1332,9 @@ void initServer() { server.stop_writes_on_bgsave_err = 1; aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL); if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, - acceptTcpHandler,NULL) == AE_ERR) oom("creating file event"); + acceptTcpHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.ipfd file event."); if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, - acceptUnixHandler,NULL) == AE_ERR) oom("creating file event"); + acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event."); if (server.aof_state == REDIS_AOF_ON) { server.aof_fd = open(server.aof_filename, @@ -1691,6 +1687,8 @@ int processCommand(redisClient *c) { addReply(c,shared.queued); } else { call(c,REDIS_CALL_FULL); + if (listLength(server.ready_keys)) + handleClientsBlockedOnLists(); } return REDIS_OK; } @@ -1858,7 +1856,7 @@ sds genRedisInfoString(char *section) { unsigned long lol, bib; int allsections = 0, defsections = 0; int sections = 0; - + if (section) { allsections = strcasecmp(section,"all") == 0; defsections = strcasecmp(section,"default") == 0; @@ -1871,7 +1869,12 @@ sds genRedisInfoString(char *section) { /* Server */ if (allsections || defsections || !strcasecmp(section,"server")) { struct utsname name; + char *mode; + if (server.cluster_enabled) mode = "cluster"; + else if (server.sentinel_mode) mode = "sentinel"; + else mode = "standalone"; + if (sections++) info = sdscat(info,"\r\n"); uname(&name); info = sdscatprintf(info, @@ -1879,6 +1882,7 @@ sds genRedisInfoString(char *section) { "redis_version:%s\r\n" "redis_git_sha1:%s\r\n" "redis_git_dirty:%d\r\n" + "redis_mode:%s\r\n" "os:%s %s %s\r\n" "arch_bits:%d\r\n" "multiplexing_api:%s\r\n" @@ -1892,6 +1896,7 @@ sds genRedisInfoString(char *section) { REDIS_VERSION, redisGitSHA1(), strtol(redisGitDirty(),NULL,10) > 0, + mode, name.sysname, name.release, name.machine, server.arch_bits, aeGetApiName(), @@ -1967,12 +1972,13 @@ sds genRedisInfoString(char *section) { "aof_rewrite_in_progress:%d\r\n" "aof_rewrite_scheduled:%d\r\n" "aof_last_rewrite_time_sec:%ld\r\n" - "aof_current_rewrite_time_sec:%ld\r\n", + "aof_current_rewrite_time_sec:%ld\r\n" + "aof_last_bgrewrite_status:%s\r\n", server.loading, server.dirty, server.rdb_child_pid != -1, server.lastsave, - server.lastbgsave_status == REDIS_OK ? "ok" : "err", + (server.lastbgsave_status == REDIS_OK) ? "ok" : "err", server.rdb_save_time_last, (server.rdb_child_pid == -1) ? -1 : time(NULL)-server.rdb_save_time_start, @@ -1981,7 +1987,8 @@ sds genRedisInfoString(char *section) { server.aof_rewrite_scheduled, server.aof_rewrite_time_last, (server.aof_child_pid == -1) ? - -1 : time(NULL)-server.aof_rewrite_time_start); + -1 : time(NULL)-server.aof_rewrite_time_start, + (server.aof_lastbgrewrite_status == REDIS_OK) ? "ok" : "err"); if (server.aof_state != REDIS_AOF_OFF) { info = sdscatprintf(info, @@ -1989,7 +1996,7 @@ sds genRedisInfoString(char *section) { "aof_base_size:%lld\r\n" "aof_pending_rewrite:%d\r\n" "aof_buffer_length:%zu\r\n" - "aof_rewrite_buffer_length:%zu\r\n" + "aof_rewrite_buffer_length:%lu\r\n" "aof_pending_bio_fsync:%llu\r\n" "aof_delayed_fsync:%lu\r\n", (long long) server.aof_current_size, @@ -2087,9 +2094,10 @@ sds genRedisInfoString(char *section) { if (server.repl_state == REDIS_REPL_TRANSFER) { info = sdscatprintf(info, - "master_sync_left_bytes:%ld\r\n" + "master_sync_left_bytes:%lld\r\n" "master_sync_last_io_seconds_ago:%d\r\n" - ,(long)server.repl_transfer_left, + , (long long) + (server.repl_transfer_size - server.repl_transfer_read), (int)(server.unixtime-server.repl_transfer_lastio) ); } @@ -2099,6 +2107,8 @@ sds genRedisInfoString(char *section) { "master_link_down_since_seconds:%ld\r\n", (long)server.unixtime-server.repl_down_since); } + info = sdscatprintf(info, + "slave_priority:%d\r\n", server.slave_priority); } info = sdscatprintf(info, "connected_slaves:%lu\r\n", @@ -2532,11 +2542,18 @@ void loadDataFromDisk(void) { } } +void redisOutOfMemoryHandler(size_t allocation_size) { + redisLog(REDIS_WARNING,"Out Of Memory allocating %zu bytes!", + allocation_size); + redisPanic("OOM"); +} + int main(int argc, char **argv) { struct timeval tv; /* We need to initialize our libraries, and the server configuration. */ zmalloc_enable_thread_safeness(); + zmalloc_set_oom_handler(redisOutOfMemoryHandler); srand(time(NULL)^getpid()); gettimeofday(&tv,NULL); dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid()); @@ -2616,6 +2633,11 @@ int main(int argc, char **argv) { redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket); } + /* Warning the user about suspicious maxmemory setting. */ + if (server.maxmemory > 0 && server.maxmemory < 1024*1024) { + redisLog(REDIS_WARNING,"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory); + } + aeSetBeforeSleepProc(server.el,beforeSleep); aeMain(server.el); aeDeleteEventLoop(server.el);