diff options
author | antirez <antirez@gmail.com> | 2017-11-29 11:39:19 +0100 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2017-11-29 11:39:19 +0100 |
commit | 8ad1eedbf9f180634b31d104bbea114671fc5a87 (patch) | |
tree | 831fe65e9e038fb03e664a5adf4eceb30206f9e0 | |
parent | 565e139a5631a777254e222d1c50ea6d696e1a8e (diff) | |
download | redis-8ad1eedbf9f180634b31d104bbea114671fc5a87.tar.gz |
RDB v9: Save Lua scripts state into RDB file.rdb9
This is currently needed in order to fix #4483, but this can be useful
in other contexts, so maybe later we may want to remove the conditionals
and always save/load scripts.
-rw-r--r-- | src/rdb.c | 44 | ||||
-rw-r--r-- | src/rdb.h | 1 | ||||
-rw-r--r-- | src/scripting.c | 15 | ||||
-rw-r--r-- | src/server.h | 1 |
4 files changed, 56 insertions, 5 deletions
@@ -943,6 +943,23 @@ 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); + if (rdbSaveType(rdb,RDB_OPCODE_SCRIPT) == -1) goto werr; + if (rdbSaveRawString(rdb,(unsigned char*)sha,sdslen(sha)) == -1) goto werr; + if (rdbSaveRawString(rdb,body->ptr,sdslen(body->ptr)) == -1) + goto werr; + } + dictReleaseIterator(di); + } + /* EOF opcode */ if (rdbSaveType(rdb,RDB_OPCODE_EOF) == -1) goto werr; @@ -1563,6 +1580,33 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi) { dictExpand(db->dict,db_size); dictExpand(db->expires,expires_size); continue; /* Read type again. */ + } else if (type == RDB_OPCODE_SCRIPT) { + sds sha; + robj *body; + char funcname[43]; + + if ((sha = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS,NULL)) + == NULL) goto eoferr; + if (sdslen(sha) != 40) { + rdbExitReportCorruptRDB( + "Lua script stored into the RDB file has invalid " + "name length: '%s'", sha); + } + if ((body = rdbLoadStringObject(rdb)) == NULL) goto eoferr; + + /* Compose the Lua function name, and load it. */ + funcname[0] = 'f'; + funcname[1] = '_'; + memcpy(funcname+2,sha,41); + if (luaCreateFunction(NULL,server.lua,funcname,body) == C_ERR) { + rdbExitReportCorruptRDB( + "Can't load Lua script from RDB file! " + "Script SHA1: %s BODY: %d", + sha, body->ptr); + } + sdsfree(sha); + decrRefCount(body); + continue; /* Read type again. */ } else if (type == RDB_OPCODE_AUX) { /* AUX: generic string-string fields. Use to add state to RDB * which is backward compatible. Implementations of RDB loading @@ -95,6 +95,7 @@ #define rdbIsObjectType(t) ((t >= 0 && t <= 7) || (t >= 9 && t <= 14)) /* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */ +#define RDB_OPCODE_SCRIPT 249 #define RDB_OPCODE_AUX 250 #define RDB_OPCODE_RESIZEDB 251 #define RDB_OPCODE_EXPIRETIME_MS 252 diff --git a/src/scripting.c b/src/scripting.c index d9f954068..64de1edcd 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -1160,16 +1160,21 @@ int luaCreateFunction(client *c, lua_State *lua, char *funcname, robj *body) { funcdef = sdscatlen(funcdef,"\nend",4); if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"@user_script")) { - addReplyErrorFormat(c,"Error compiling script (new function): %s\n", - lua_tostring(lua,-1)); + if (c != NULL) { + addReplyErrorFormat(c, + "Error compiling script (new function): %s\n", + lua_tostring(lua,-1)); + } lua_pop(lua,1); sdsfree(funcdef); return C_ERR; } sdsfree(funcdef); if (lua_pcall(lua,0,0,0)) { - addReplyErrorFormat(c,"Error running script (new function): %s\n", - lua_tostring(lua,-1)); + if (c != NULL) { + addReplyErrorFormat(c,"Error running script (new function): %s\n", + lua_tostring(lua,-1)); + } lua_pop(lua,1); return C_ERR; } @@ -1180,7 +1185,7 @@ int luaCreateFunction(client *c, lua_State *lua, char *funcname, robj *body) { { int retval = dictAdd(server.lua_scripts, sdsnewlen(funcname+2,40),body); - serverAssertWithInfo(c,NULL,retval == DICT_OK); + serverAssertWithInfo(c ? c : server.lua_client,NULL,retval == DICT_OK); incrRefCount(body); } return C_OK; diff --git a/src/server.h b/src/server.h index e3b56075a..a0c65355b 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); |