Example #1
0
/* 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;
}
Example #2
0
/* 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);
}
Example #3
0
/* 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;
}
Example #4
0
/* 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;
}