From 452ad2e928524cfe42856e869effd2d8b37ae280 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 29 Nov 2017 16:38:16 +0100 Subject: [PATCH] PSYNC2: just store script bodies into RDB. Related to #4483. As suggested by @soloestoy, we can retrieve the SHA1 from the body. Given that in the new implementation using AUX fields we ended copying around a lot to create new objects and strings, extremize such concept and trade CPU for space inside the RDB file. --- src/rdb.c | 34 ++++------------------------------ src/scripting.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/rdb.c b/src/rdb.c index d1495e79..19ba59ab 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -950,16 +950,9 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) { if (rsi && dictSize(server.lua_scripts)) { di = dictGetIterator(server.lua_scripts); while((de = dictNext(di)) != NULL) { - sds sha = dictGetKey(de); robj *body = dictGetVal(de); - /* Concatenate the SHA1 and the Lua script together. Because the - * SHA1 is fixed length, we will always be able to load it back - * telling apart the name from the body. */ - sds combo = sdsdup(sha); - combo = sdscatlen(combo,body->ptr,sdslen(body->ptr)); - if (rdbSaveAuxField(rdb,"lua",3,combo,sdslen(combo)) == -1) + if (rdbSaveAuxField(rdb,"lua",3,body->ptr,sdslen(body->ptr)) == -1) goto werr; - sdsfree(combo); } dictReleaseIterator(di); } @@ -1611,31 +1604,12 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi) { } else if (!strcasecmp(auxkey->ptr,"repl-offset")) { if (rsi) rsi->repl_offset = strtoll(auxval->ptr,NULL,10); } else if (!strcasecmp(auxkey->ptr,"lua")) { - /* Load the string combining the function name and body - * back in memory. The format is basically: - * . To load it back we need - * to create the function name as "f_" and load the - * body as a Redis string object. */ - sds combo = auxval->ptr; - if (sdslen(combo) < 40) { - rdbExitReportCorruptRDB( - "Lua script stored into the RDB file has invalid " - "length < 40 bytes: '%s'", combo); - } - char funcname[42]; - funcname[0] = 'f'; - funcname[1] = '_'; - memcpy(funcname+2,combo,40); - robj *body = createRawStringObject(combo+40,sdslen(combo)-40); - - /* Register the function. */ - if (luaCreateFunction(NULL,server.lua,funcname,body) == C_ERR) { + /* Load the script back in memory. */ + if (luaCreateFunction(NULL,server.lua,NULL,auxval) == C_ERR) { rdbExitReportCorruptRDB( "Can't load Lua script from RDB file! " - "Script SHA1: %.42s BODY: %s", - combo, combo+42); + "BODY: %s", auxval->ptr); } - decrRefCount(body); } else { /* We ignore fields we don't understand, as by AUX field * contract. */ diff --git a/src/scripting.c b/src/scripting.c index 64de1edc..1ef91a4d 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -1147,11 +1147,26 @@ int redis_math_randomseed (lua_State *L) { * * f_ * + * If 'funcname' is NULL, the function name is created by the function + * on the fly doing the SHA1 of the body, this means that passing the funcname + * is just an optimization in case it's already at hand. + * + * The function increments the reference count of the 'body' object as a + * side effect of a successful call. + * * On success C_OK is returned, and nothing is left on the Lua stack. * On error C_ERR is returned and an appropriate error is set in the * client context. */ int luaCreateFunction(client *c, lua_State *lua, char *funcname, robj *body) { sds funcdef = sdsempty(); + char fname[42]; + + if (funcname == NULL) { + fname[0] = 'f'; + fname[1] = '_'; + sha1hex(fname+2,body->ptr,sdslen(body->ptr)); + funcname = fname; + } funcdef = sdscat(funcdef,"function "); funcdef = sdscatlen(funcdef,funcname,42);