diff --git a/src/rdb.c b/src/rdb.c index 00106cac..d1495e79 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -943,6 +943,27 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) { } di = NULL; /* So that we don't release it again on error. */ + /* If we are storing the replication information on disk, persist + * the script cache as well: on successful PSYNC after a restart, we need + * to be able to process any EVALSHA inside the replication backlog the + * master will send us. */ + 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) + goto werr; + sdsfree(combo); + } + dictReleaseIterator(di); + } + /* EOF opcode */ if (rdbSaveType(rdb,RDB_OPCODE_EOF) == -1) goto werr; @@ -1589,6 +1610,32 @@ 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) { + rdbExitReportCorruptRDB( + "Can't load Lua script from RDB file! " + "Script SHA1: %.42s BODY: %s", + combo, combo+42); + } + decrRefCount(body); } else { /* We ignore fields we don't understand, as by AUX field * contract. */ diff --git a/src/server.h b/src/server.h index 9b7da1d3..11eb36f3 100644 --- a/src/server.h +++ b/src/server.h @@ -1781,6 +1781,7 @@ void scriptingInit(int setup); int ldbRemoveChild(pid_t pid); void ldbKillForkedSessions(void); int ldbPendingChildren(void); +int luaCreateFunction(client *c, lua_State *lua, char *funcname, robj *body); /* Blocked clients */ void processUnblockedClients(void);