From: antirez Date: Sat, 25 Jun 2011 10:29:24 +0000 (+0200) Subject: unstable merge conflicts resolved X-Git-Url: https://git.saurik.com/redis.git/commitdiff_plain/994ed2bc552f4114b1f0c8dd3fd8aefaec6beeae?ds=sidebyside;hp=-c unstable merge conflicts resolved --- 994ed2bc552f4114b1f0c8dd3fd8aefaec6beeae diff --combined Makefile index 335f8321,7ce9031c..20c4f86e --- a/Makefile +++ b/Makefile @@@ -12,7 -12,7 +12,8 @@@ clean cd src && $(MAKE) $@ cd deps/hiredis && $(MAKE) $@ cd deps/linenoise && $(MAKE) $@ + cd deps/jemalloc && $(MAKE) distclean + cd deps/lua && $(MAKE) $@ $(TARGETS): cd src && $(MAKE) $@ diff --combined redis.conf index 6999dae3,6d18e2f5..098c28da --- a/redis.conf +++ b/redis.conf @@@ -312,39 -312,6 +312,13 @@@ no-appendfsync-on-rewrite n auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# This prevents that a programming error generating an infinite loop will block +# your server forever. Set it to 0 or a negative value for unlimited execution. +lua-time-limit 60000 + - #################################### DISK STORE ############################### - - # When disk store is active Redis works as an on-disk database, where memory - # is only used as a object cache. - # - # This mode is good for datasets that are bigger than memory, and in general - # when you want to trade speed for: - # - # - less memory used - # - immediate server restart - # - per key durability, without need for backgrond savig - # - # On the other hand, with disk store enabled MULTI/EXEC are no longer - # transactional from the point of view of the persistence on disk, that is, - # Redis transactions will still guarantee that commands are either processed - # all or nothing, but there is no guarantee that all the keys are flushed - # on disk in an atomic way. - # - # Of course with disk store enabled Redis is not as fast as it is when - # working with just the memory back end. - - diskstore-enabled no - diskstore-path redis.ds - cache-max-memory 0 - cache-flush-delay 0 - ############################### ADVANCED CONFIG ############################### # Hashes are encoded in a special way (much more memory efficient) when they diff --combined src/Makefile index e23ed038,4a6f27eb..7e4b829d --- a/src/Makefile +++ b/src/Makefile @@@ -5,35 -5,45 +5,45 @@@ release_hdr := $(shell sh -c './mkreleasehdr.sh') uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') OPTIMIZATION?=-O2 + + ifeq ($(uname_S),Linux) + ifneq ($(FORCE_LIBC_MALLOC),yes) + USE_JEMALLOC=yes + endif + endif + ifeq ($(uname_S),SunOS) - CFLAGS?= -std=c99 -pedantic $(OPTIMIZATION) -Wall -W -D__EXTENSIONS__ -D_XPG6 - CCLINK?= -ldl -lnsl -lsocket -lm -lpthread - DEBUG?= -g -ggdb + CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -Wall -W -D__EXTENSIONS__ -D_XPG6 + CCLINK?=-ldl -lnsl -lsocket -lm -lpthread + DEBUG?=-g -ggdb else - CFLAGS?= -std=c99 -pedantic $(OPTIMIZATION) -Wall -W $(ARCH) $(PROF) - CCLINK?= -lm -pthread - DEBUG?= -g -rdynamic -ggdb + CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -Wall -W $(ARCH) $(PROF) + CCLINK?=-lm -pthread + DEBUG?=-g -rdynamic -ggdb endif ifeq ($(USE_TCMALLOC),yes) + ALLOD_DEPS= ALLOC_LINK=-ltcmalloc ALLOC_FLAGS=-DUSE_TCMALLOC endif ifeq ($(USE_TCMALLOC_MINIMAL),yes) + ALLOD_DEPS= ALLOC_LINK=-ltcmalloc_minimal ALLOC_FLAGS=-DUSE_TCMALLOC endif ifeq ($(USE_JEMALLOC),yes) - ALLOC_LINK=-ljemalloc - ALLOC_FLAGS=-DUSE_JEMALLOC + ALLOC_DEP=../deps/jemalloc/lib/libjemalloc.a + ALLOC_LINK=$(ALLOC_DEP) -ldl + ALLOC_FLAGS=-DUSE_JEMALLOC -I../deps/jemalloc/include endif CCLINK+= $(ALLOC_LINK) CFLAGS+= $(ALLOC_FLAGS) - CCOPT= $(CFLAGS) $(CCLINK) $(ARCH) $(PROF) + CCOPT= $(CFLAGS) $(ARCH) $(PROF) PREFIX= /usr/local INSTALL_BIN= $(PREFIX)/bin @@@ -51,7 -61,7 +61,7 @@@ QUIET_CC = @printf ' %b %b\n' $(CCCO QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR); endif - OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o dscache.o pubsub.o multi.o debug.o sort.o intset.o syncio.o diskstore.o cluster.o crc16.o endian.o scripting.o -OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endian.o ++OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endian.o scripting.o BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o CHECKDUMPOBJ = redis-check-dump.o lzf_c.o lzf_d.o @@@ -76,32 -86,38 +86,38 @@@ ae_kqueue.o: ae_kqueue. ae_select.o: ae_select.c anet.o: anet.c fmacros.h anet.h aof.o: aof.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h + cluster.o: cluster.c redis.h fmacros.h config.h ae.h sds.h dict.h \ + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h config.o: config.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h + crc16.o: crc16.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h db.o: db.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h debug.o: debug.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h sha1.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h sha1.h dict.o: dict.c fmacros.h dict.h zmalloc.h diskstore.o: diskstore.c redis.h fmacros.h config.h ae.h sds.h dict.h \ - adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h \ + sha1.h dscache.o: dscache.c redis.h fmacros.h config.h ae.h sds.h dict.h \ - adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h - intset.o: intset.c intset.h zmalloc.h + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h + endian.o: endian.c + intset.o: intset.c intset.h zmalloc.h endian.h lzf_c.o: lzf_c.c lzfP.h lzf_d.o: lzf_d.c lzfP.h multi.o: multi.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h networking.o: networking.c redis.h fmacros.h config.h ae.h sds.h dict.h \ - adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h object.o: object.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h pqsort.o: pqsort.c pubsub.o: pubsub.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h rdb.o: rdb.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h lzf.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h lzf.h redis-benchmark.o: redis-benchmark.c fmacros.h ae.h \ ../deps/hiredis/hiredis.h sds.h adlist.h zmalloc.h redis-check-aof.o: redis-check-aof.c fmacros.h config.h @@@ -109,65 -125,69 +125,71 @@@ redis-check-dump.o: redis-check-dump.c redis-cli.o: redis-cli.c fmacros.h version.h ../deps/hiredis/hiredis.h \ sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h redis.o: redis.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h asciilogo.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h \ + asciilogo.h release.o: release.c release.h replication.o: replication.c redis.h fmacros.h config.h ae.h sds.h dict.h \ - adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h sds.o: sds.c sds.h zmalloc.h - sha1.o: sha1.c sha1.h + sha1.o: sha1.c sha1.h config.h sort.o: sort.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h pqsort.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h pqsort.h syncio.o: syncio.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h t_hash.o: t_hash.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h t_list.o: t_list.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h t_set.o: t_set.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h t_string.o: t_string.c redis.h fmacros.h config.h ae.h sds.h dict.h \ - adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h + adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h t_zset.o: t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h - util.o: util.c util.h - cluster.o: redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \ - zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h - ziplist.o: ziplist.c zmalloc.h ziplist.h - zipmap.o: zipmap.c zmalloc.h - zmalloc.o: zmalloc.c config.h + zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h + util.o: util.c fmacros.h util.h + ziplist.o: ziplist.c zmalloc.h util.h ziplist.h endian.h + zipmap.o: zipmap.c zmalloc.h endian.h + zmalloc.o: zmalloc.c config.h zmalloc.h + + .PHONY: dependencies dependencies: @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)hiredis$(ENDCOLOR) @cd ../deps/hiredis && $(MAKE) static ARCH="$(ARCH)" @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)linenoise$(ENDCOLOR) @cd ../deps/linenoise && $(MAKE) ARCH="$(ARCH)" + @echo $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)Lua ansi$(ENDCOLOR) + @cd ../deps/lua && $(MAKE) ARCH="$(ARCH)" ansi + ../deps/jemalloc/lib/libjemalloc.a: + cd ../deps/jemalloc && ./configure $(JEMALLOC_CFLAGS) --with-jemalloc-prefix=je_ --enable-cc-silence && $(MAKE) lib/libjemalloc.a + redis-server: $(OBJ) - $(QUIET_CC)$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) ../deps/lua/src/liblua.a - $(QUIET_CC)$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) $(CCLINK) $(ALLOC_LINK) ++ $(QUIET_CC)$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) $(CCLINK) $(ALLOC_LINK) ../deps/lua/src/liblua.a redis-benchmark: dependencies $(BENCHOBJ) @cd ../deps/hiredis && $(MAKE) static - $(QUIET_LINK)$(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a + $(QUIET_LINK)$(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a $(CCLINK) $(ALLOC_LINK) redis-benchmark.o: $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis $(DEBUG) $(COMPILE_TIME) $< redis-cli: dependencies $(CLIOBJ) - $(QUIET_LINK)$(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o + $(QUIET_LINK)$(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(CCLINK) $(ALLOC_LINK) redis-cli.o: $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis -I../deps/linenoise $(DEBUG) $(COMPILE_TIME) $< redis-check-dump: $(CHECKDUMPOBJ) - $(QUIET_LINK)$(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ) + $(QUIET_LINK)$(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ) $(CCLINK) $(ALLOC_LINK) redis-check-aof: $(CHECKAOFOBJ) - $(QUIET_LINK)$(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ) + $(QUIET_LINK)$(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ) $(CCLINK) $(ALLOC_LINK) - .c.o: + # Because the jemalloc.h header is generated as a part of the jemalloc build + # process, building it should complete before building any other object. + %.o: %.c $(ALLOC_DEP) - $(QUIET_CC)$(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) $< + $(QUIET_CC)$(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) -I../deps/lua/src $< clean: rm -rf $(PRGNAME) $(BENCHPRGNAME) $(CLIPRGNAME) $(CHECKDUMPPRGNAME) $(CHECKAOFPRGNAME) *.o *.gcda *.gcno *.gcov @@@ -176,7 -196,7 +198,7 @@@ dep $(CC) -MM *.c -I ../deps/hiredis -I ../deps/linenoise test: redis-server - (cd ..; tclsh8.5 tests/test_helper.tcl --tags "${TAGS}" --file "${FILE}") + @(cd ..; (which tclsh >/dev/null && tclsh tests/test_helper.tcl --tags "${TAGS}" --file "${FILE}") || echo "You need to install Tcl in order to run tests.") bench: ./redis-benchmark @@@ -188,7 -208,7 +210,7 @@@ log @echo "" @echo "WARNING: if it fails under Linux you probably need to install libc6-dev-i386" @echo "" - $(MAKE) ARCH="-m32" + $(MAKE) ARCH="-m32" JEMALLOC_CFLAGS='CFLAGS="-std=gnu99 -Wall -pipe -g3 -fvisibility=hidden -O3 -funroll-loops -m32"' gprof: $(MAKE) PROF="-pg" diff --combined src/config.c index 4f4514c8,e82fbde4..88a00d38 --- a/src/config.c +++ b/src/config.c @@@ -251,18 -251,6 +251,6 @@@ void loadServerConfig(char *filename) } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) { zfree(server.dbfilename); server.dbfilename = zstrdup(argv[1]); - } else if (!strcasecmp(argv[0],"diskstore-enabled") && argc == 2) { - if ((server.ds_enabled = yesnotoi(argv[1])) == -1) { - err = "argument must be 'yes' or 'no'"; goto loaderr; - } - } else if (!strcasecmp(argv[0],"diskstore-path") && argc == 2) { - sdsfree(server.ds_path); - server.ds_path = sdsnew(argv[1]); - } else if (!strcasecmp(argv[0],"cache-max-memory") && argc == 2) { - server.cache_max_memory = memtoll(argv[1],NULL); - } else if (!strcasecmp(argv[0],"cache-flush-delay") && argc == 2) { - server.cache_flush_delay = atoi(argv[1]); - if (server.cache_flush_delay < 0) server.cache_flush_delay = 0; } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) { server.hash_max_zipmap_entries = memtoll(argv[1], NULL); } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) { @@@ -308,8 -296,6 +296,8 @@@ } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) { zfree(server.cluster.configfile); server.cluster.configfile = zstrdup(argv[1]); + } else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) { + server.lua_time_limit = strtoll(argv[1],NULL,10); } else { err = "Bad directive or wrong number of arguments"; goto loaderr; } @@@ -480,9 -466,6 +468,9 @@@ void configSetCommand(redisClient *c) } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; server.zset_max_ziplist_value = ll; + } else if (!strcasecmp(c->argv[2]->ptr,"lua-time-limit")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; + server.lua_time_limit = ll; } else { addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s", (char*)c->argv[2]->ptr); @@@ -654,11 -637,6 +642,11 @@@ void configGetCommand(redisClient *c) addReplyBulkLongLong(c,server.zset_max_ziplist_value); matches++; } + if (stringmatch(pattern,"lua-time-limit",0)) { + addReplyBulkCString(c,"lua-time-limit"); + addReplyBulkLongLong(c,server.lua_time_limit); + matches++; + } setDeferredMultiBulkLength(c,replylen,matches*2); } diff --combined src/networking.c index e88e27d1,dbd83505..b95ef946 --- a/src/networking.c +++ b/src/networking.c @@@ -14,20 -14,14 +14,20 @@@ redisClient *createClient(int fd) redisClient *c = zmalloc(sizeof(redisClient)); c->bufpos = 0; - anetNonBlock(NULL,fd); - anetTcpNoDelay(NULL,fd); - if (aeCreateFileEvent(server.el,fd,AE_READABLE, - readQueryFromClient, c) == AE_ERR) - { - close(fd); - zfree(c); - return NULL; + /* passing -1 as fd it is possible to create a non connected client. + * This is useful since all the Redis commands needs to be executed + * in the context of a client. When commands are executed in other + * contexts (for instance a Lua script) we need a non connected client. */ + if (fd != -1) { + anetNonBlock(NULL,fd); + anetTcpNoDelay(NULL,fd); + if (aeCreateFileEvent(server.el,fd,AE_READABLE, + readQueryFromClient, c) == AE_ERR) + { + close(fd); + zfree(c); + return NULL; + } } selectDb(c,0); @@@ -57,7 -51,7 +57,7 @@@ c->pubsub_patterns = listCreate(); listSetFreeMethod(c->pubsub_patterns,decrRefCount); listSetMatchMethod(c->pubsub_patterns,listMatchObjects); - listAddNodeTail(server.clients,c); + if (fd != -1) listAddNodeTail(server.clients,c); initClientMultiState(c); return c; } @@@ -65,7 -59,6 +65,7 @@@ /* Set the event loop to listen for write events on the client's socket. * Typically gets called every time a reply is built. */ int _installWriteEvent(redisClient *c) { + if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK; if (c->fd <= 0) return REDIS_ERR; if (c->bufpos == 0 && listLength(c->reply) == 0 && (c->replstate == REDIS_REPL_NONE || @@@ -246,17 -239,10 +246,17 @@@ void addReplyError(redisClient *c, cha } void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { + size_t l, j; va_list ap; va_start(ap,fmt); sds s = sdscatvprintf(sdsempty(),fmt,ap); va_end(ap); + /* Make sure there are no newlines in the string, otherwise invalid protocol + * is emitted. */ + l = sdslen(s); + for (j = 0; j < l; j++) { + if (s[j] == '\r' || s[j] == '\n') s[j] = ' '; + } _addReplyError(c,s,sdslen(s)); sdsfree(s); } @@@ -501,25 -487,6 +501,6 @@@ void freeClient(redisClient *c) redisAssert(ln != NULL); listDelNode(server.unblocked_clients,ln); } - /* Remove from the list of clients waiting for swapped keys, or ready - * to be restarted, but not yet woken up again. */ - if (c->flags & REDIS_IO_WAIT) { - redisAssert(server.ds_enabled); - if (listLength(c->io_keys) == 0) { - ln = listSearchKey(server.io_ready_clients,c); - - /* When this client is waiting to be woken up (REDIS_IO_WAIT), - * it should be present in the list io_ready_clients */ - redisAssert(ln != NULL); - listDelNode(server.io_ready_clients,ln); - } else { - while (listLength(c->io_keys)) { - ln = listFirst(c->io_keys); - dontWaitForSwappedKey(c,ln->value); - } - } - server.cache_blocked_clients--; - } listRelease(c->io_keys); /* Master/slave cleanup. * Case 1: we lost the connection with a slave. */ @@@ -536,6 -503,7 +517,7 @@@ if (c->flags & REDIS_MASTER) { server.master = NULL; server.replstate = REDIS_REPL_CONNECT; + server.repl_down_since = time(NULL); /* Since we lost the connection with the master, we should also * close the connection with all our slaves if we have any, so * when we'll resync with the master the other slaves will sync again @@@ -809,9 -777,6 +791,6 @@@ int processMultibulkBuffer(redisClient void processInputBuffer(redisClient *c) { /* Keep processing while there is something in the input buffer */ while(sdslen(c->querybuf)) { - /* Immediately abort if the client is in the middle of something. */ - if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return; - /* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is * written to the client. Make sure to not let the reply grow after * this flag has been set (i.e. don't process more commands). */ @@@ -920,7 -885,6 +899,6 @@@ void clientCommand(redisClient *c) if (p == flags) *p++ = 'N'; if (client->flags & REDIS_MULTI) *p++ = 'x'; if (client->flags & REDIS_BLOCKED) *p++ = 'b'; - if (client->flags & REDIS_IO_WAIT) *p++ = 'i'; if (client->flags & REDIS_DIRTY_CAS) *p++ = 'd'; if (client->flags & REDIS_CLOSE_AFTER_REPLY) *p++ = 'c'; if (client->flags & REDIS_UNBLOCKED) *p++ = 'u'; @@@ -960,3 -924,28 +938,28 @@@ addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port)"); } } + + void rewriteClientCommandVector(redisClient *c, int argc, ...) { + va_list ap; + int j; + robj **argv; /* The new argument vector */ + + argv = zmalloc(sizeof(robj*)*argc); + va_start(ap,argc); + for (j = 0; j < argc; j++) { + robj *a; + + a = va_arg(ap, robj*); + argv[j] = a; + incrRefCount(a); + } + /* We free the objects in the original vector at the end, so we are + * sure that if the same objects are reused in the new vector the + * refcount gets incremented before it gets decremented. */ + for (j = 0; j < c->argc; j++) decrRefCount(c->argv[j]); + zfree(c->argv); + /* Replace argv and argc with our new versions. */ + c->argv = argv; + c->argc = argc; + va_end(ap); + } diff --combined src/redis.c index ee5e1a21,89efffba..f4e3f623 --- a/src/redis.c +++ b/src/redis.c @@@ -50,7 -50,6 +50,6 @@@ #include #include #include - #include #include /* Our shared "common" objects */ @@@ -193,9 -192,7 +192,9 @@@ struct redisCommand redisCommandTable[ {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0}, {"dump",dumpCommand,2,0,NULL,0,0,0,0,0}, {"object",objectCommand,-2,0,NULL,0,0,0,0,0}, - {"client",clientCommand,-2,0,NULL,0,0,0,0,0} + {"client",clientCommand,-2,0,NULL,0,0,0,0,0}, + {"eval",evalCommand,-3,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0}, + {"evalsha",evalShaCommand,-3,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0} }; /*============================ Utility functions ============================ */ @@@ -661,22 -658,7 +660,7 @@@ int serverCron(struct aeEventLoop *even } updateDictResizePolicy(); } - } else if (server.bgsavethread != (pthread_t) -1) { - if (server.bgsavethread != (pthread_t) -1) { - int state; - - pthread_mutex_lock(&server.bgsavethread_mutex); - state = server.bgsavethread_state; - pthread_mutex_unlock(&server.bgsavethread_mutex); - - if (state == REDIS_BGSAVE_THREAD_DONE_OK || - state == REDIS_BGSAVE_THREAD_DONE_ERR) - { - backgroundSaveDoneHandler( - (state == REDIS_BGSAVE_THREAD_DONE_OK) ? 0 : 1, 0); - } - } - } else if (!server.ds_enabled) { + } else { time_t now = time(NULL); /* If there is not a background saving/rewrite in progress check if @@@ -714,10 -696,6 +698,6 @@@ * in order to guarantee a strict consistency. */ if (server.masterhost == NULL) activeExpireCycle(); - /* Remove a few cached objects from memory if we are over the - * configured memory limit */ - if (server.ds_enabled) cacheCron(); - /* Replication cron function -- used to reconnect to master and * to detect transfer failures. */ if (!(loops % 10)) replicationCron(); @@@ -737,31 -715,6 +717,6 @@@ void beforeSleep(struct aeEventLoop *ev listNode *ln; redisClient *c; - /* Awake clients that got all the on disk keys they requested */ - if (server.ds_enabled && listLength(server.io_ready_clients)) { - listIter li; - - listRewind(server.io_ready_clients,&li); - while((ln = listNext(&li))) { - c = ln->value; - struct redisCommand *cmd; - - /* Resume the client. */ - listDelNode(server.io_ready_clients,ln); - c->flags &= (~REDIS_IO_WAIT); - server.cache_blocked_clients--; - aeCreateFileEvent(server.el, c->fd, AE_READABLE, - readQueryFromClient, c); - cmd = lookupCommand(c->argv[0]->ptr); - redisAssert(cmd != NULL); - call(c,cmd); - resetClient(c); - /* There may be more data to process in the input buffer. */ - if (c->querybuf && sdslen(c->querybuf) > 0) - processInputBuffer(c); - } - } - /* Try to process pending commands for clients that were just unblocked. */ while (listLength(server.unblocked_clients)) { ln = listFirst(server.unblocked_clients); @@@ -806,8 -759,6 +761,8 @@@ void createSharedObjects(void) "-ERR source and destination objects are the same\r\n")); shared.outofrangeerr = createObject(REDIS_STRING,sdsnew( "-ERR index out of range\r\n")); + shared.noscripterr = createObject(REDIS_STRING,sdsnew( + "-NOSCRIPT No matching script. Please use EVAL.\r\n")); shared.loadingerr = createObject(REDIS_STRING,sdsnew( "-LOADING Redis is loading the dataset in memory\r\n")); shared.space = createObject(REDIS_STRING,sdsnew(" ")); @@@ -874,10 -825,6 +829,6 @@@ void initServerConfig() server.maxmemory = 0; server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; server.maxmemory_samples = 3; - server.ds_enabled = 0; - server.ds_path = sdsnew("/tmp/redis.ds"); - server.cache_max_memory = 64LL*1024*1024; /* 64 MB of RAM */ - server.cache_blocked_clients = 0; server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES; server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE; server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES; @@@ -886,10 -833,8 +837,9 @@@ server.zset_max_ziplist_entries = REDIS_ZSET_MAX_ZIPLIST_ENTRIES; server.zset_max_ziplist_value = REDIS_ZSET_MAX_ZIPLIST_VALUE; server.shutdown_asap = 0; - server.cache_flush_delay = 0; server.cluster_enabled = 0; server.cluster.configfile = zstrdup("nodes.conf"); + server.lua_time_limit = REDIS_LUA_TIME_LIMIT; updateLRUClock(); resetServerSaveParams(); @@@ -906,6 -851,7 +856,7 @@@ server.replstate = REDIS_REPL_NONE; server.repl_syncio_timeout = REDIS_REPL_SYNCIO_TIMEOUT; server.repl_serve_stale_data = 1; + server.repl_down_since = -1; /* Double constants initialization */ R_Zero = 0.0; @@@ -934,12 -880,10 +885,10 @@@ void initServer() server.syslog_facility); } - server.mainthread = pthread_self(); server.clients = listCreate(); server.slaves = listCreate(); server.monitors = listCreate(); server.unblocked_clients = listCreate(); - server.cache_io_queue = listCreate(); createSharedObjects(); server.el = aeCreateEventLoop(); @@@ -969,11 -913,6 +918,6 @@@ server.db[j].expires = dictCreate(&keyptrDictType,NULL); server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL); server.db[j].watched_keys = dictCreate(&keylistDictType,NULL); - if (server.ds_enabled) { - server.db[j].io_keys = dictCreate(&keylistDictType,NULL); - server.db[j].io_negcache = dictCreate(&setDictType,NULL); - server.db[j].io_queued = dictCreate(&setDictType,NULL); - } server.db[j].id = j; } server.pubsub_channels = dictCreate(&keylistDictType,NULL); @@@ -983,8 -922,6 +927,6 @@@ server.cronloops = 0; server.bgsavechildpid = -1; server.bgrewritechildpid = -1; - server.bgsavethread_state = REDIS_BGSAVE_THREAD_UNACTIVE; - server.bgsavethread = (pthread_t) -1; server.bgrewritebuf = sdsempty(); server.aofbuf = sdsempty(); server.lastsave = time(NULL); @@@ -1014,9 -951,7 +956,8 @@@ } } - if (server.ds_enabled) dsInit(); if (server.cluster_enabled) clusterInit(); + scriptingInit(); srand(time(NULL)^getpid()); } @@@ -1193,8 -1128,6 +1134,6 @@@ int processCommand(redisClient *c) queueMultiCommand(c,cmd); addReply(c,shared.queued); } else { - if (server.ds_enabled && blockClientOnSwappedKeys(c,cmd)) - return REDIS_ERR; call(c,cmd); } return REDIS_OK; @@@ -1212,9 -1145,7 +1151,7 @@@ int prepareForShutdown() kill(server.bgsavechildpid,SIGKILL); rdbRemoveTempFile(server.bgsavechildpid); } - if (server.ds_enabled) { - /* FIXME: flush all objects on disk */ - } else if (server.appendonly) { + if (server.appendonly) { /* Append only file: fsync() the AOF and exit */ aof_fsync(server.appendfd); } else if (server.saveparamslen > 0) { @@@ -1354,7 -1285,6 +1291,7 @@@ sds genRedisInfoString(char *section) "used_memory_rss:%zu\r\n" "used_memory_peak:%zu\r\n" "used_memory_peak_human:%s\r\n" + "used_memory_lua:%lld\r\n" "mem_fragmentation_ratio:%.2f\r\n" "mem_allocator:%s\r\n", zmalloc_used_memory(), @@@ -1362,9 -1292,8 +1299,9 @@@ zmalloc_get_rss(), server.stat_peak_memory, peak_hmem, + ((long long)lua_gc(server.lua,LUA_GCCOUNT,0))*1024LL, zmalloc_get_fragmentation_ratio(), - REDIS_MALLOC + ZMALLOC_LIB ); } @@@ -1398,8 -1327,7 +1335,7 @@@ server.loading, server.appendonly, server.dirty, - server.bgsavechildpid != -1 || - server.bgsavethread != (pthread_t) -1, + server.bgsavechildpid != -1, server.lastsave, server.bgrewritechildpid != -1); @@@ -1445,35 -1373,6 +1381,6 @@@ } } - /* Diskstore */ - if (allsections || defsections || !strcasecmp(section,"diskstore")) { - if (sections++) info = sdscat(info,"\r\n"); - info = sdscatprintf(info, - "# Diskstore\r\n" - "ds_enabled:%d\r\n", - server.ds_enabled != 0); - if (server.ds_enabled) { - lockThreadedIO(); - info = sdscatprintf(info, - "cache_max_memory:%llu\r\n" - "cache_blocked_clients:%lu\r\n" - "cache_io_queue_len:%lu\r\n" - "cache_io_jobs_new:%lu\r\n" - "cache_io_jobs_processing:%lu\r\n" - "cache_io_jobs_processed:%lu\r\n" - "cache_io_ready_clients:%lu\r\n" - ,(unsigned long long) server.cache_max_memory, - (unsigned long) server.cache_blocked_clients, - (unsigned long) listLength(server.cache_io_queue), - (unsigned long) listLength(server.io_newjobs), - (unsigned long) listLength(server.io_processing), - (unsigned long) listLength(server.io_processed), - (unsigned long) listLength(server.io_ready_clients) - ); - unlockThreadedIO(); - } - } - /* Stats */ if (allsections || defsections || !strcasecmp(section,"stats")) { if (sections++) info = sdscat(info,"\r\n"); @@@ -1530,6 -1429,12 +1437,12 @@@ (int)(time(NULL)-server.repl_transfer_lastio) ); } + + if (server.replstate != REDIS_REPL_CONNECTED) { + info = sdscatprintf(info, + "master_link_down_since_seconds:%ld\r\n", + (long)time(NULL)-server.repl_down_since); + } } info = sdscatprintf(info, "connected_slaves:%d\r\n", @@@ -1825,9 -1730,7 +1738,7 @@@ int main(int argc, char **argv) linuxOvercommitMemoryWarning(); #endif start = ustime(); - if (server.ds_enabled) { - redisLog(REDIS_NOTICE,"DB not loaded (running with disk back end)"); - } else if (server.appendonly) { + if (server.appendonly) { if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK) redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000); } else { diff --combined src/redis.h index fec7355b,a5cd15ed..9775e298 --- a/src/redis.h +++ b/src/redis.h @@@ -19,7 -19,6 +19,7 @@@ #include #include #include +#include #include "ae.h" /* Event driven programming library */ #include "sds.h" /* Dynamic safe strings */ @@@ -125,31 -124,16 +125,17 @@@ #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */ #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */ - /* Scheduled IO opeations flags. */ - #define REDIS_IO_LOAD 1 - #define REDIS_IO_SAVE 2 - #define REDIS_IO_LOADINPROG 4 - #define REDIS_IO_SAVEINPROG 8 - - /* Generic IO flags */ - #define REDIS_IO_ONLYLOADS 1 - #define REDIS_IO_ASAP 2 - - #define REDIS_MAX_COMPLETED_JOBS_PROCESSED 1 - #define REDIS_THREAD_STACK_SIZE (1024*1024*4) - /* Client flags */ #define REDIS_SLAVE 1 /* This client is a slave server */ #define REDIS_MASTER 2 /* This client is a master server */ #define REDIS_MONITOR 4 /* This client is a slave monitor, see MONITOR */ #define REDIS_MULTI 8 /* This client is in a MULTI context */ #define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */ - #define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */ #define REDIS_DIRTY_CAS 64 /* Watched keys modified. EXEC will fail. */ #define REDIS_CLOSE_AFTER_REPLY 128 /* Close after writing entire reply. */ #define REDIS_UNBLOCKED 256 /* This client was unblocked and is stored in server.unblocked_clients */ +#define REDIS_LUA_CLIENT 512 /* This is a non connected client used by Lua */ /* Client request types */ #define REDIS_REQ_INLINE 1 @@@ -224,15 -208,6 +210,9 @@@ #define REDIS_MAXMEMORY_ALLKEYS_RANDOM 4 #define REDIS_MAXMEMORY_NO_EVICTION 5 - /* Diskstore background saving thread states */ - #define REDIS_BGSAVE_THREAD_UNACTIVE 0 - #define REDIS_BGSAVE_THREAD_ACTIVE 1 - #define REDIS_BGSAVE_THREAD_DONE_OK 2 - #define REDIS_BGSAVE_THREAD_DONE_ERR 3 - +/* Scripting */ +#define REDIS_LUA_TIME_LIMIT 60000 /* milliseconds */ + /* We can print the stacktrace, so our assert is defined this way: */ #define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1))) #define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1) @@@ -297,9 -272,6 +277,6 @@@ typedef struct redisDb dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ - dict *io_keys; /* Keys with clients waiting for DS I/O */ - dict *io_negcache; /* Negative caching for disk store */ - dict *io_queued; /* Queued IO operations hash table */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ int id; } redisDb; @@@ -370,7 -342,7 +347,7 @@@ struct sharedObjectsStruct robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space, *colon, *nullbulk, *nullmultibulk, *queued, *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, - *outofrangeerr, *loadingerr, *plus, + *outofrangeerr, *noscripterr, *loadingerr, *plus, *select0, *select1, *select2, *select3, *select4, *select5, *select6, *select7, *select8, *select9, *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *mbulk3, @@@ -521,7 -493,6 +498,6 @@@ typedef struct struct redisServer { /* General */ - pthread_t mainthread; redisDb *db; dict *commands; /* Command table hahs table */ aeEventLoop *el; @@@ -579,9 -550,6 +555,6 @@@ char *pidfile; pid_t bgsavechildpid; pid_t bgrewritechildpid; - int bgsavethread_state; - pthread_mutex_t bgsavethread_mutex; - pthread_t bgsavethread; sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */ sds aofbuf; /* AOF buffer, written before entering the event loop */ struct saveparam *saveparams; @@@ -609,6 -577,7 +582,7 @@@ char *repl_transfer_tmpfile; /* slave-> master SYNC temp file name */ time_t repl_transfer_lastio; /* unix time of the latest read, for timeout */ int repl_serve_stale_data; /* Serve stale data when link is down? */ + time_t repl_down_since; /* unix time at which link with master went down */ /* Limits */ unsigned int maxclients; unsigned long long maxmemory; @@@ -616,19 -585,12 +590,12 @@@ int maxmemory_samples; /* Blocked clients */ unsigned int bpop_blocked_clients; - unsigned int cache_blocked_clients; list *unblocked_clients; /* list of clients to unblock before next loop */ - list *cache_io_queue; /* IO operations queue */ - int cache_flush_delay; /* seconds to wait before flushing keys */ /* Sort parameters - qsort_r() is only available under BSD so we * have to take this state global, in order to pass it to sortCompare() */ int sort_desc; int sort_alpha; int sort_bypattern; - /* Virtual memory configuration */ - int ds_enabled; /* backend disk in redis.conf */ - char *ds_path; /* location of the disk store on disk */ - unsigned long long cache_max_memory; /* Zip structure config */ size_t hash_max_zipmap_entries; size_t hash_max_zipmap_value; @@@ -671,11 -633,6 +638,11 @@@ /* Cluster */ int cluster_enabled; clusterState cluster; + /* Scripting */ + lua_State *lua; + redisClient *lua_client; + long long lua_time_limit; + long long lua_time_start; }; typedef struct pubsubPattern { @@@ -691,7 -648,7 +658,7 @@@ struct redisCommand int arity; int flags; /* Use a function to determine keys arguments in a command line. - * Used both for diskstore preloading and Redis Cluster. */ + * Used for Redis Cluster redirect. */ redisGetKeysProc *getkeys_proc; /* What keys should be loaded in background when calling this command? */ int firstkey; /* The first argument that's a key (0 = no keys) */ @@@ -718,27 -675,6 +685,6 @@@ typedef struct _redisSortOperation robj *pattern; } redisSortOperation; - /* DIsk store threaded I/O request message */ - #define REDIS_IOJOB_LOAD 0 - #define REDIS_IOJOB_SAVE 1 - - typedef struct iojob { - int type; /* Request type, REDIS_IOJOB_* */ - redisDb *db;/* Redis database */ - robj *key; /* This I/O request is about this key */ - robj *val; /* the value to swap for REDIS_IOJOB_SAVE, otherwise this - * field is populated by the I/O thread for REDIS_IOJOB_LOAD. */ - time_t expire; /* Expire time for this key on REDIS_IOJOB_LOAD */ - } iojob; - - /* IO operations scheduled -- check dscache.c for more info */ - typedef struct ioop { - int type; - redisDb *db; - robj *key; - time_t ctime; /* This is the creation time of the entry. */ - } ioop; - /* Structure to hold list iteration abstraction. */ typedef struct { robj *subject; @@@ -828,6 -764,7 +774,7 @@@ void addReplyMultiBulkLen(redisClient * void *dupClientReplyValue(void *o); void getClientsMaxBuffers(unsigned long *longest_output_list, unsigned long *biggest_input_buffer); + void rewriteClientCommandVector(redisClient *c, int argc, ...); #ifdef __GNUC__ void addReplyErrorFormat(redisClient *c, const char *fmt, ...) @@@ -974,7 -911,6 +921,7 @@@ struct redisCommand *lookupCommandByCSt void call(redisClient *c, struct redisCommand *cmd); int prepareForShutdown(); void redisLog(int level, const char *fmt, ...); +void redisLogRaw(int level, const char *msg); void usage(); void updateDictResizePolicy(void); int htNeedsResize(dict *dict); @@@ -982,40 -918,6 +929,6 @@@ void oom(const char *msg) void populateCommandTable(void); void resetCommandTableStats(void); - /* Disk store */ - int dsOpen(void); - int dsClose(void); - int dsSet(redisDb *db, robj *key, robj *val, time_t expire); - robj *dsGet(redisDb *db, robj *key, time_t *expire); - int dsDel(redisDb *db, robj *key); - int dsExists(redisDb *db, robj *key); - void dsFlushDb(int dbid); - int dsRdbSaveBackground(char *filename); - int dsRdbSave(char *filename); - - /* Disk Store Cache */ - void dsInit(void); - void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask); - void lockThreadedIO(void); - void unlockThreadedIO(void); - void freeIOJob(iojob *j); - void queueIOJob(iojob *j); - void waitEmptyIOJobsQueue(void); - void processAllPendingIOJobs(void); - int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd); - int dontWaitForSwappedKey(redisClient *c, robj *key); - void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key); - int cacheFreeOneEntry(void); - void cacheScheduleIOAddFlag(redisDb *db, robj *key, long flag); - void cacheScheduleIODelFlag(redisDb *db, robj *key, long flag); - int cacheScheduleIOGetFlags(redisDb *db, robj *key); - void cacheScheduleIO(redisDb *db, robj *key, int type); - void cacheCron(void); - int cacheKeyMayExist(redisDb *db, robj *key); - void cacheSetKeyMayExist(redisDb *db, robj *key); - void cacheSetKeyDoesNotExist(redisDb *db, robj *key); - void cacheForcePointInTime(void); - /* Set data type */ robj *setTypeCreate(robj *value); int setTypeAdd(robj *subject, robj *value); @@@ -1068,8 -970,9 +981,9 @@@ robj *lookupKeyRead(redisDb *db, robj * robj *lookupKeyWrite(redisDb *db, robj *key); robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply); robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply); - int dbAdd(redisDb *db, robj *key, robj *val); - int dbReplace(redisDb *db, robj *key, robj *val); + void dbAdd(redisDb *db, robj *key, robj *val); + void dbOverwrite(redisDb *db, robj *key, robj *val); + void setKey(redisDb *db, robj *key, robj *val); int dbExists(redisDb *db, robj *key); robj *dbRandomKey(redisDb *db); int dbDelete(redisDb *db, robj *key); @@@ -1097,9 -1000,6 +1011,9 @@@ int clusterAddNode(clusterNode *node) void clusterCron(void); clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *ask); +/* Scripting */ +void scriptingInit(void); + /* Git SHA1 */ char *redisGitSHA1(void); char *redisGitDirty(void); @@@ -1228,8 -1128,6 +1142,8 @@@ void migrateCommand(redisClient *c) void dumpCommand(redisClient *c); void objectCommand(redisClient *c); void clientCommand(redisClient *c); +void evalCommand(redisClient *c); +void evalShaCommand(redisClient *c); #if defined(__GNUC__) void *calloc(size_t count, size_t size) __attribute__ ((deprecated));