diff --git a/src/aof.c b/src/aof.c index a587fb863..80b951200 100644 --- a/src/aof.c +++ b/src/aof.c @@ -2102,6 +2102,35 @@ int rewriteModuleObject(rio *r, robj *key, robj *o, int dbid) { return io.error ? 0 : 1; } +static int rewriteFunctions(rio *aof) { + dict *functions = functionsLibGet(); + dictIterator *iter = dictGetIterator(functions); + dictEntry *entry = NULL; + while ((entry = dictNext(iter))) { + functionLibInfo *li = dictGetVal(entry); + if (li->desc) { + if (rioWrite(aof, "*7\r\n", 4) == 0) goto werr; + } else { + if (rioWrite(aof, "*5\r\n", 4) == 0) goto werr; + } + char fucntion_load[] = "$8\r\nFUNCTION\r\n$4\r\nLOAD\r\n"; + if (rioWrite(aof, fucntion_load, sizeof(fucntion_load) - 1) == 0) goto werr; + if (rioWriteBulkString(aof, li->ei->name, sdslen(li->ei->name)) == 0) goto werr; + if (rioWriteBulkString(aof, li->name, sdslen(li->name)) == 0) goto werr; + if (li->desc) { + if (rioWriteBulkString(aof, "description", 11) == 0) goto werr; + if (rioWriteBulkString(aof, li->desc, sdslen(li->desc)) == 0) goto werr; + } + if (rioWriteBulkString(aof, li->code, sdslen(li->code)) == 0) goto werr; + } + dictReleaseIterator(iter); + return 1; + +werr: + dictReleaseIterator(iter); + return 0; +} + int rewriteAppendOnlyFileRio(rio *aof) { dictIterator *di = NULL; dictEntry *de; @@ -2116,6 +2145,8 @@ int rewriteAppendOnlyFileRio(rio *aof) { sdsfree(ts); } + if (rewriteFunctions(aof) == 0) goto werr; + for (j = 0; j < server.dbnum; j++) { char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n"; redisDb *db = server.db+j; diff --git a/tests/unit/aofrw.tcl b/tests/unit/aofrw.tcl index 426f11d8e..ac861a653 100644 --- a/tests/unit/aofrw.tcl +++ b/tests/unit/aofrw.tcl @@ -74,6 +74,7 @@ start_server {tags {"aofrw external:skip"} overrides {aof-use-rdb-preamble no}} } else { fail "Can't find 'Killing AOF child' into recent logs" } + r config set rdb-key-save-delay 0 } foreach d {string int} { @@ -182,6 +183,19 @@ start_server {tags {"aofrw external:skip"} overrides {aof-use-rdb-preamble no}} } } + test "AOF rewrite functions" { + r flushall + r FUNCTION LOAD LUA test DESCRIPTION {desc} { + redis.register_function('test', function() return 1 end) + } + r bgrewriteaof + waitForBgrewriteaof r + r function flush + r debug loadaof + assert_equal [r fcall test 0] 1 + r FUNCTION LIST + } {{library_name test engine LUA description desc functions {{name test description {} flags {}}}}} + test {BGREWRITEAOF is delayed if BGSAVE is in progress} { r flushall r set k v