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;
}