redisProtocolToLuaType是一个转换寒山湖,跟lua相关:
- /* Debugger shared state is stored inside this global structure. */
- #define LDB_BREAKPOINTS_MAX 64 /* Max number of breakpoints. */
- #define LDB_MAX_LEN_DEFAULT 256 /* Default len limit for replies / var dumps. */
- struct ldbState {
- connection *conn; /* Connection of the debugging client. */
- int active; /* Are we debugging EVAL right now? */
- int forked; /* Is this a fork()ed debugging session? */
- list *logs; /* List of messages to send to the client. */
- list *traces; /* Messages about Redis commands executed since last stop.*/
- list *children; /* All forked debugging sessions pids. */
- int bp[LDB_BREAKPOINTS_MAX]; /* An array of breakpoints line numbers. */
- int bpcount; /* Number of valid entries inside bp. */
- int step; /* Stop at next line regardless of breakpoints. */
- int luabp; /* Stop at next line because redis.breakpoint() was called. */
- sds *src; /* Lua script source code split by line. */
- int lines; /* Number of lines in 'src'. */
- int currentline; /* Current line number. */
- sds cbuf; /* Debugger client command buffer. */
- size_t maxlen; /* Max var dump / reply length. */
- int maxlen_hint_sent; /* Did we already hint about "set maxlen"? */
- } ldb;
-
- /* ---------------------------------------------------------------------------
- * Utility functions.
- * ------------------------------------------------------------------------- */
-
- /* Perform the SHA1 of the input string. We use this both for hashing script
- * bodies in order to obtain the Lua function name, and in the implementation
- * of redis.sha1().
- *
- * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an
- * hexadecimal number, plus 1 byte for null term. */
- void sha1hex(char *digest, char *script, size_t len) {
- SHA1_CTX ctx;
- unsigned char hash[20];
- char *cset = "0123456789abcdef";
- int j;
-
- SHA1Init(&ctx);
- SHA1Update(&ctx,(unsigned char*)script,len);
- SHA1Final(hash,&ctx);
-
- for (j = 0; j < 20; j++) {
- digest[j*2] = cset[((hash[j]&0xF0)>>4)];
- digest[j*2+1] = cset[(hash[j]&0xF)];
- }
- digest[40] = '\0';
- }
-
- /* ---------------------------------------------------------------------------
- * Redis reply to Lua type conversion functions.
- * ------------------------------------------------------------------------- */
-
- /* Take a Redis reply in the Redis protocol format and convert it into a
- * Lua type. Thanks to this function, and the introduction of not connected
- * clients, it is trivial to implement the redis() lua function.
- *
- * Basically we take the arguments, execute the Redis command in the context
- * of a non connected client, then take the generated reply and convert it
- * into a suitable Lua type. With this trick the scripting feature does not
- * need the introduction of a full Redis internals API. The script
- * is like a normal client that bypasses all the slow I/O paths.
- *
- * Note: in this function we do not do any sanity check as the reply is
- * generated by Redis directly. This allows us to go faster.
- *
- * Errors are returned as a table with a single 'err' field set to the
- * error string.
- */
-
- char *redisProtocolToLuaType(lua_State *lua, char* reply) {
-
- if (!lua_checkstack(lua, 5)) {
- /*
- * Increase the Lua stack if needed, to make sure there is enough room
- * to push 5 elements to the stack. On failure, exit with panic.
- * Notice that we need, in the worst case, 5 elements because redisProtocolToLuaType_Aggregate
- * might push 5 elements to the Lua stack.*/
- serverPanic("lua stack limit reach when parsing redis.call reply");
- }
-
- char *p = reply;
-
- switch(*p) {
- case ':': p = redisProtocolToLuaType_Int(lua,reply); break;
- case '$': p = redisProtocolToLuaType_Bulk(lua,reply); break;
- case '+': p = redisProtocolToLuaType_Status(lua,reply); break;
- case '-': p = redisProtocolToLuaType_Error(lua,reply); break;
- case '*': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break;
- case '%': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break;
- case '~': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break;
- case '_': p = redisProtocolToLuaType_Null(lua,reply); break;
- case '#': p = redisProtocolToLuaType_Bool(lua,reply,p[1]); break;
- case ',': p = redisProtocolToLuaType_Double(lua,reply); break;
- }
- return p;
- }
-
- char *redisProtocolToLuaType_Int(lua_State *lua, char *reply) {
- char *p = strchr(reply+1,'\r');
- long long value;
-
- string2ll(reply+1,p-reply-1,&value);
- lua_pushnumber(lua,(lua_Number)value);
- return p+2;
- }
-
- char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply) {
- char *p = strchr(reply+1,'\r');
- long long bulklen;
-
- string2ll(reply+1,p-reply-1,&bulklen);
- if (bulklen == -1) {
- lua_pushboolean(lua,0);
- return p+2;
- } else {
- lua_pushlstring(lua,p+2,bulklen);
- return p+2+bulklen+2;
- }
- }
-
- char *redisProtocolToLuaType_Status(lua_State *lua, char *reply) {
- char *p = strchr(reply+1,'\r');
-
- lua_newtable(lua);
- lua_pushstring(lua,"ok");
- lua_pushlstring(lua,reply+1,p-reply-1);
- lua_settable(lua,-3);
- return p+2;
- }
-
- char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) {
- char *p = strchr(reply+1,'\r');
-
- lua_newtable(lua);
- lua_pushstring(lua,"err");
- lua_pushlstring(lua,reply+1,p-reply-1);
- lua_settable(lua,-3);
- return p+2;
- }
-
- char *redisProtocolToLuaType_Aggregate(lua_State *lua, char *reply, int atype) {
- char *p = strchr(reply+1,'\r');
- long long mbulklen;
- int j = 0;
-
- string2ll(reply+1,p-reply-1,&mbulklen);
- if (server.lua_client->resp == 2 || atype == '*') {
- p += 2;
- if (mbulklen == -1) {
- lua_pushboolean(lua,0);
- return p;
- }
- lua_newtable(lua);
- for (j = 0; j < mbulklen; j++) {
- lua_pushnumber(lua,j+1);
- p = redisProtocolToLuaType(lua,p);
- lua_settable(lua,-3);
- }
- } else if (server.lua_client->resp == 3) {
- /* Here we handle only Set and Map replies in RESP3 mode, since arrays
- * follow the above RESP2 code path. Note that those are represented
- * as a table with the "map" or "set" field populated with the actual
- * table representing the set or the map type. */
- p += 2;
- lua_newtable(lua);
- lua_pushstring(lua,atype == '%' ? "map" : "set");
- lua_newtable(lua);
- for (j = 0; j < mbulklen; j++) {
- p = redisProtocolToLuaType(lua,p);
- if (atype == '%') {
- p = redisProtocolToLuaType(lua,p);
- } else {
- if (!lua_checkstack(lua, 1)) {
- /* Notice that here we need to check the stack again because the recursive
- * call to redisProtocolToLuaType might have use the room allocated in the stack */
- serverPanic("lua stack limit reach when parsing redis.call reply");
- }
- lua_pushboolean(lua,1);
- }
- lua_settable(lua,-3);
- }
- lua_settable(lua,-3);
- }
- return p;
- }