/* Initialize the scripting environment. * It is possible to call this function to reset the scripting environment * assuming that we call scriptingRelease() before. * See scriptingReset() for more information. */ void scriptingInit(void) { lua_State *lua = lua_open(); // 加载常用的 lua 库 luaLoadLibraries(lua); luaRemoveUnsupportedFunctions(lua); // SHAs -> lus_scrpit 哈希表 /* Initialize a dictionary we use to map SHAs to scripts. * This is useful for replication, as we need to replicate EVALSHA * as EVAL, so we need to remember the associated script. */ server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL); // 向 lua 解释器注册 redis 的数据或者变量 /* Register the redis commands table and fields */ lua_newtable(lua); // 注册 redis.call 函数,命令处理函数 /* redis.call */ lua_pushstring(lua,"call"); lua_pushcfunction(lua,luaRedisCallCommand); lua_settable(lua,-3); // 注册 redis.pall 函数,命令处理函数 /* redis.pcall */ lua_pushstring(lua,"pcall"); lua_pushcfunction(lua,luaRedisPCallCommand); lua_settable(lua,-3); // 注册 redis.log 函数和 redis 日志级别 /* redis.log and log levels. */ lua_pushstring(lua,"log"); lua_pushcfunction(lua,luaLogCommand); lua_settable(lua,-3); lua_pushstring(lua,"LOG_DEBUG"); lua_pushnumber(lua,REDIS_DEBUG); lua_settable(lua,-3); lua_pushstring(lua,"LOG_VERBOSE"); lua_pushnumber(lua,REDIS_VERBOSE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_NOTICE"); lua_pushnumber(lua,REDIS_NOTICE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_WARNING"); lua_pushnumber(lua,REDIS_WARNING); lua_settable(lua,-3); // 注册 redis.sha1hex 函数 /* redis.sha1hex */ lua_pushstring(lua, "sha1hex"); lua_pushcfunction(lua, luaRedisSha1hexCommand); lua_settable(lua, -3); // 注册 redis 错误处理函数 /* redis.error_reply and redis.status_reply */ lua_pushstring(lua, "error_reply"); lua_pushcfunction(lua, luaRedisErrorReplyCommand); lua_settable(lua, -3); lua_pushstring(lua, "status_reply"); lua_pushcfunction(lua, luaRedisStatusReplyCommand); lua_settable(lua, -3); // 将上面注册的内容作为 redis 的变量,在 lua 中变为可访问 /* Finally set the table as 'redis' global var. */ lua_setglobal(lua,"redis"); // 将 lua 原有 math.random 函数替换为 redis 自己的实现 /* Replace math.random and math.randomseed with our implementations. */ lua_getglobal(lua,"math"); lua_pushstring(lua,"random"); lua_pushcfunction(lua,redis_math_random); lua_settable(lua,-3); lua_pushstring(lua,"randomseed"); lua_pushcfunction(lua,redis_math_randomseed); lua_settable(lua,-3); lua_setglobal(lua,"math"); // 以下是辅助函数 /* Add a helper function that we use to sort the multi bulk output of non * deterministic commands, when containing 'false' elements. */ { char *compare_func = "function __redis__compare_helper(a,b)\n" " if a == false then a = '' end\n" " if b == false then b = '' end\n" " return a<b\n" "end\n"; luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def"); lua_pcall(lua,0,0,0); } /* Add a helper function we use for pcall error reporting. * Note that when the error is in the C function we want to report the * information about the caller, that's what makes sense from the point * of view of the user debugging a script. */ { char *errh_func = "function __redis__err__handler(err)\n" " local i = debug.getinfo(2,'nSl')\n" " if i and i.what == 'C' then\n" " i = debug.getinfo(3,'nSl')\n" " end\n" " if i then\n" " return i.source .. ':' .. i.currentline .. ': ' .. err\n" " else\n" " return err\n" " end\n" "end\n"; luaL_loadbuffer(lua,errh_func,strlen(errh_func),"@err_handler_def"); lua_pcall(lua,0,0,0); } // 创建虚拟客户端,以便在 lua 内部执行 redis 命令 /* Create the (non connected) client that we use to execute Redis commands * inside the Lua interpreter. * Note: there is no need to create it again when this function is called * by scriptingReset(). */ if (server.lua_client == NULL) { server.lua_client = createClient(-1); server.lua_client->flags |= REDIS_LUA_CLIENT; } /* Lua beginners ofter don't use "local", this is likely to introduce * subtle bugs in their code. To prevent problems we protect accesses * to global variables. */ scriptingEnableGlobalsProtection(lua); server.lua = lua; }
/* Initialize the scripting environment. * It is possible to call this function to reset the scripting environment * assuming that we call scriptingRelease() before. * See scriptingReset() for more information. */ void scriptingInit(void) { if (lua) { return; } lua = lua_open(); luaLoadLibraries(lua); luaRemoveUnsupportedFunctions(lua); /* Initialize a dictionary we use to map SHAs to scripts. * This is useful for replication, as we need to replicate EVALSHA * as EVAL, so we need to remember the associated script. */ /* Register the rlite commands table and fields */ lua_newtable(lua); /* rlite.call */ lua_pushstring(lua,"call"); lua_pushcfunction(lua,luaRedisCallCommand); lua_settable(lua,-3); /* rlite.pcall */ lua_pushstring(lua,"pcall"); lua_pushcfunction(lua,luaRedisPCallCommand); lua_settable(lua,-3); /* rlite.log and log levels. */ lua_pushstring(lua,"log"); lua_pushcfunction(lua,luaLogCommand); lua_settable(lua,-3); lua_pushstring(lua,"LOG_DEBUG"); lua_pushnumber(lua,RLITE_DEBUG); lua_settable(lua,-3); lua_pushstring(lua,"LOG_VERBOSE"); lua_pushnumber(lua,RLITE_VERBOSE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_NOTICE"); lua_pushnumber(lua,RLITE_NOTICE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_WARNING"); lua_pushnumber(lua,RLITE_WARNING); lua_settable(lua,-3); /* rlite.sha1hex */ lua_pushstring(lua, "sha1hex"); lua_pushcfunction(lua, luaRedisSha1hexCommand); lua_settable(lua, -3); /* rlite.error_reply and rlite.status_reply */ lua_pushstring(lua, "error_reply"); lua_pushcfunction(lua, luaRedisErrorReplyCommand); lua_settable(lua, -3); lua_pushstring(lua, "status_reply"); lua_pushcfunction(lua, luaRedisStatusReplyCommand); lua_settable(lua, -3); /* Finally set the table as 'redis' global var. */ lua_setglobal(lua,"redis"); /* Replace math.random and math.randomseed with our implementations. */ lua_getglobal(lua,"math"); lua_pushstring(lua,"random"); lua_pushcfunction(lua,rlite_math_random); lua_settable(lua,-3); lua_pushstring(lua,"randomseed"); lua_pushcfunction(lua,rlite_math_randomseed); lua_settable(lua,-3); lua_setglobal(lua,"math"); /* Add a helper function that we use to sort the multi bulk output of non * deterministic commands, when containing 'false' elements. */ { char *compare_func = "function __rlite__compare_helper(a,b)\n" " if a == false then a = '' end\n" " if b == false then b = '' end\n" " return a<b\n" "end\n"; luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def"); lua_pcall(lua,0,0,0); } /* Add a helper function we use for pcall error reporting. * Note that when the error is in the C function we want to report the * information about the caller, that's what makes sense from the point * of view of the user debugging a script. */ { char *errh_func = "function __rlite__err__handler(err)\n" " local i = debug.getinfo(2,'nSl')\n" " if i and i.what == 'C' then\n" " i = debug.getinfo(3,'nSl')\n" " end\n" " if i then\n" " return i.source .. ':' .. i.currentline .. ': ' .. err\n" " else\n" " return err\n" " end\n" "end\n"; luaL_loadbuffer(lua,errh_func,strlen(errh_func),"@err_handler_def"); lua_pcall(lua,0,0,0); } /* Create the (non connected) client that we use to execute Redis commands * inside the Lua interpreter. * Note: there is no need to create it again when this function is called * by scriptingReset(). */ if (lua_client == NULL) { lua_client = malloc(sizeof(*lua_client)); lua_client->flags = RLITE_LUA_CLIENT; } /* Lua beginners often don't use "local", this is likely to introduce * subtle bugs in their code. To prevent problems we protect accesses * to global variables. */ scriptingEnableGlobalsProtection(lua); }
/* Initialize the scripting environment. * It is possible to call this function to reset the scripting environment * assuming that we call scriptingRelease() before. * See scriptingReset() for more information. */ void scriptingInit(void) { lua_State *lua = lua_open(); luaLoadLibraries(lua); luaRemoveUnsupportedFunctions(lua); /* Initialize a dictionary we use to map SHAs to scripts. * This is useful for replication, as we need to replicate EVALSHA * as EVAL, so we need to remember the associated script. */ server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL); /* Register the redis commands table and fields */ lua_newtable(lua); /* redis.call */ lua_pushstring(lua,"call"); lua_pushcfunction(lua,luaRedisCallCommand); lua_settable(lua,-3); /* redis.pcall */ lua_pushstring(lua,"pcall"); lua_pushcfunction(lua,luaRedisPCallCommand); lua_settable(lua,-3); /* redis.log and log levels. */ lua_pushstring(lua,"log"); lua_pushcfunction(lua,luaLogCommand); lua_settable(lua,-3); lua_pushstring(lua,"LOG_DEBUG"); lua_pushnumber(lua,REDIS_DEBUG); lua_settable(lua,-3); lua_pushstring(lua,"LOG_VERBOSE"); lua_pushnumber(lua,REDIS_VERBOSE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_NOTICE"); lua_pushnumber(lua,REDIS_NOTICE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_WARNING"); lua_pushnumber(lua,REDIS_WARNING); lua_settable(lua,-3); /* redis.sha1hex */ lua_pushstring(lua, "sha1hex"); lua_pushcfunction(lua, luaRedisSha1hexCommand); lua_settable(lua, -3); /* redis.error_reply and redis.status_reply */ lua_pushstring(lua, "error_reply"); lua_pushcfunction(lua, luaRedisErrorReplyCommand); lua_settable(lua, -3); lua_pushstring(lua, "status_reply"); lua_pushcfunction(lua, luaRedisStatusReplyCommand); lua_settable(lua, -3); /* Finally set the table as 'redis' global var. */ lua_setglobal(lua,"redis"); /* Replace math.random and math.randomseed with our implementations. */ lua_getglobal(lua,"math"); lua_pushstring(lua,"random"); lua_pushcfunction(lua,redis_math_random); lua_settable(lua,-3); lua_pushstring(lua,"randomseed"); lua_pushcfunction(lua,redis_math_randomseed); lua_settable(lua,-3); lua_setglobal(lua,"math"); /* Add a helper function that we use to sort the multi bulk output of non * deterministic commands, when containing 'false' elements. */ { char *compare_func = "function __redis__compare_helper(a,b)\n" " if a == false then a = '' end\n" " if b == false then b = '' end\n" " return a<b\n" "end\n"; luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def"); lua_pcall(lua,0,0,0); } /* Create the (non connected) client that we use to execute Redis commands * inside the Lua interpreter. * Note: there is no need to create it again when this function is called * by scriptingReset(). */ if (server.lua_client == NULL) { server.lua_client = createClient(-1); server.lua_client->flags |= REDIS_LUA_CLIENT; } /* Lua beginners ofter don't use "local", this is likely to introduce * subtle bugs in their code. To prevent problems we protect accesses * to global variables. */ scriptingEnableGlobalsProtection(lua); server.lua = lua; }
/* Initialize the scripting environment. * * 初始化脚本环境。 * * It is possible to call this function to reset the scripting environment * assuming that we call scriptingRelease() before. * * 这个函数也可以在 scriptingRelease() 执行之后使用,用于对脚本环境进行重置。 * * See scriptingReset() for more information. */ void scriptingInit(void) { // 创建一个新的 lua 环境 lua_State *lua = lua_open(); // 载入内置函数库 luaLoadLibraries(lua); // 屏蔽所有不想暴露给脚本环境的函数(目前只有 loadfile) luaRemoveUnsupportedFunctions(lua); /* Initialize a dictionary we use to map SHAs to scripts. * 创建一个字典,用于将 SHA 校验码映射到脚本 * This is useful for replication, as we need to replicate EVALSHA * as EVAL, so we need to remember the associated script. * 因为 Redis 目前复制脚本的方法是将 EVALSHA 转换成 EVAL 来进行的, * 所以程序需要保存和 SHA 校验值相对应的脚本。 */ server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL); /* Register the redis commands table and fields */ // 创建 table ,并以给定名称将 C 函数注册到表格上 lua_newtable(lua); /* 注册 redis.call */ lua_pushstring(lua,"call"); lua_pushcfunction(lua,luaRedisCallCommand); lua_settable(lua,-3); /* 注册 redis.pcall */ lua_pushstring(lua,"pcall"); lua_pushcfunction(lua,luaRedisPCallCommand); lua_settable(lua,-3); /* 注册 redis.log 和 log levels. */ lua_pushstring(lua,"log"); lua_pushcfunction(lua,luaLogCommand); lua_settable(lua,-3); lua_pushstring(lua,"LOG_DEBUG"); lua_pushnumber(lua,REDIS_DEBUG); lua_settable(lua,-3); lua_pushstring(lua,"LOG_VERBOSE"); lua_pushnumber(lua,REDIS_VERBOSE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_NOTICE"); lua_pushnumber(lua,REDIS_NOTICE); lua_settable(lua,-3); lua_pushstring(lua,"LOG_WARNING"); lua_pushnumber(lua,REDIS_WARNING); lua_settable(lua,-3); /* 注册 redis.sha1hex */ lua_pushstring(lua, "sha1hex"); lua_pushcfunction(lua, luaRedisSha1hexCommand); lua_settable(lua, -3); /* 注册 redis.error_reply and redis.status_reply */ lua_pushstring(lua, "error_reply"); lua_pushcfunction(lua, luaRedisErrorReplyCommand); lua_settable(lua, -3); lua_pushstring(lua, "status_reply"); lua_pushcfunction(lua, luaRedisStatusReplyCommand); lua_settable(lua, -3); /* Finally set the table as 'redis' global var. */ // 将 table 设置为 redis 全局变量 lua_setglobal(lua,"redis"); /* Replace math.random and math.randomseed with our implementations. */ // 将 math.random 和 math.randomseed 设置为 Redis 实现 // 用于生成确定性的随机数 // (对于同一个 seed ,生成的随机序列总是相同) lua_getglobal(lua,"math"); lua_pushstring(lua,"random"); lua_pushcfunction(lua,redis_math_random); lua_settable(lua,-3); lua_pushstring(lua,"randomseed"); lua_pushcfunction(lua,redis_math_randomseed); lua_settable(lua,-3); lua_setglobal(lua,"math"); /* Add a helper funciton that we use to sort the multi bulk output of non * deterministic commands, when containing 'false' elements. * 用于对不确定性多个回复的输出进行排序 */ { char *compare_func = "function __redis__compare_helper(a,b)\n" " if a == false then a = '' end\n" " if b == false then b = '' end\n" " return a<b\n" "end\n"; luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def"); lua_pcall(lua,0,0,0); } /* Create the (non connected) client that we use to execute Redis commands * inside the Lua interpreter. * 创建一个无网络连接的伪客户端,用于执行 Lua 脚本中的命令 * Note: there is no need to create it again when this function is called * by scriptingReset(). */ if (server.lua_client == NULL) { server.lua_client = createClient(-1); server.lua_client->flags |= REDIS_LUA_CLIENT; } /* Lua beginners ofter don't use "local", this is likely to introduce * subtle bugs in their code. To prevent problems we protect accesses * to global variables. * * 为了避免全局变量被意外地修改,保护全局变量。 */ scriptingEnableGlobalsProtection(lua); // 将 lua 环境赋值到服务器变量 server.lua = lua; }