hiredis中lua脚本调用

来源:互联网 发布:数据库的数据模型包含 编辑:程序博客网 时间:2024/06/07 17:45

想要直接用hiredis调用lua脚本,研究了好久发现hiredis源码好像不支持调用eval,因为hiredis中是用空格来分割各个参数的,但是lua的return和结果之间一定会有空格。

改了一下hiredis的源码,int redisvFormatCommand(char **target, const char *format, va_list ap) 这个接口,

int redisvFormatCommand(char **target, const char *format, va_list ap) {    const char *c = format;    char *cmd = NULL; /* final command */    int pos; /* position in final command */    sds curarg, newarg; /* current argument */    int touched = 0; /* was the current argument touched? */    char **curargv = NULL, **newargv = NULL;    int argc = 0;    int totlen = 0;    int j;BOOL quote = 0;//用来判断是否是lua脚本    /* Abort if there is not target to set */    if (target == NULL)        return -1;    /* Build the command string accordingly to protocol */    curarg = sdsempty();    if (curarg == NULL)        return -1;    while(*c != '\0') {        if (*c != '%' || c[1] == '\0') {            if (*c == ' ') {if (quote){newarg = sdscatlen(curarg, c, 1);if (newarg == NULL) goto err;curarg = newarg;touched = 1;}                else if (touched) {                    newargv = realloc(curargv,sizeof(char*)*(argc+1));                    if (newargv == NULL) goto err;                    curargv = newargv;                    curargv[argc++] = curarg;                    totlen += (int)bulklen(sdslen(curarg));                    /* curarg is put in argv so it can be overwritten. */                    curarg = sdsempty();                    if (curarg == NULL) goto err;                    touched = 0;                }            } else {                                touched = 1;if (*c == '"'){if (!quote){quote = 1;}else{quote = 0;}}else{newarg = sdscatlen(curarg, c, 1);if (newarg == NULL) goto err;curarg = newarg;}            }        } else {            char *arg;            size_t size;            /* Set newarg so it can be checked even if it is not touched. */            newarg = curarg;            switch(c[1]) {            case 's':                arg = va_arg(ap,char*);                size = strlen(arg);                if (size > 0)                    newarg = sdscatlen(curarg,arg,size);                break;            case 'b':                arg = va_arg(ap,char*);                size = va_arg(ap,size_t);                if (size > 0)                    newarg = sdscatlen(curarg,arg,size);                break;            case '%':                newarg = sdscat(curarg,"%");                break;            default:                /* Try to detect printf format */                {                    static const char intfmts[] = "diouxX";                    char _format[16];                    const char *_p = c+1;                    size_t _l = 0;                    va_list _cpy;                    /* Flags */                    if (*_p != '\0' && *_p == '#') _p++;                    if (*_p != '\0' && *_p == '0') _p++;                    if (*_p != '\0' && *_p == '-') _p++;                    if (*_p != '\0' && *_p == ' ') _p++;                    if (*_p != '\0' && *_p == '+') _p++;                    /* Field width */                    while (*_p != '\0' && isdigit(*_p)) _p++;                    /* Precision */                    if (*_p == '.') {                        _p++;                        while (*_p != '\0' && isdigit(*_p)) _p++;                    }                    /* Copy va_list before consuming with va_arg */                    va_copy(_cpy,ap);                    /* Integer conversion (without modifiers) */                    if (strchr(intfmts,*_p) != NULL) {                        va_arg(ap,int);                        goto fmt_valid;                    }                    /* Double conversion (without modifiers) */                    if (strchr("eEfFgGaA",*_p) != NULL) {                        va_arg(ap,double);                        goto fmt_valid;                    }                    /* Size: char */                    if (_p[0] == 'h' && _p[1] == 'h') {                        _p += 2;                        if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {                            va_arg(ap,int); /* char gets promoted to int */                            goto fmt_valid;                        }                        goto fmt_invalid;                    }                    /* Size: short */                    if (_p[0] == 'h') {                        _p += 1;                        if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {                            va_arg(ap,int); /* short gets promoted to int */                            goto fmt_valid;                        }                        goto fmt_invalid;                    }                    /* Size: long long */                    if (_p[0] == 'l' && _p[1] == 'l') {                        _p += 2;                        if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {                            va_arg(ap,long long);                            goto fmt_valid;                        }                        goto fmt_invalid;                    }                    /* Size: long */                    if (_p[0] == 'l') {                        _p += 1;                        if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {                            va_arg(ap,long);                            goto fmt_valid;                        }                        goto fmt_invalid;                    }                fmt_invalid:                    va_end(_cpy);                    goto err;                fmt_valid:                    _l = (_p+1)-c;                    if (_l < sizeof(_format)-2) {                        memcpy(_format,c,_l);                        _format[_l] = '\0';                        newarg = sdscatvprintf(curarg,_format,_cpy);                        /* Update current position (note: outer blocks                         * increment c twice so compensate here) */                        c = _p-1;                    }                    va_end(_cpy);                    break;                }            }            if (newarg == NULL) goto err;            curarg = newarg;            touched = 1;            c++;        }        c++;    }    /* Add the last argument if needed */    if (touched) {        newargv = realloc(curargv,sizeof(char*)*(argc+1));        if (newargv == NULL) goto err;        curargv = newargv;        curargv[argc++] = curarg;        totlen += (int)bulklen(sdslen(curarg));    } else {        sdsfree(curarg);    }    /* Clear curarg because it was put in curargv or was free'd. */    curarg = NULL;    /* Add bytes needed to hold multi bulk count */    totlen += 1+intlen(argc)+2;    /* Build the command at protocol level */    cmd = (char *)malloc(totlen+1);    if (cmd == NULL) goto err;    pos = sprintf(cmd,"*%d\r\n",argc);    for (j = 0; j < argc; j++) {#ifdef _WIN32        pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)sdslen(curargv[j]));#else        pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));#endif        memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));        pos += (int)sdslen(curargv[j]);        sdsfree(curargv[j]);        cmd[pos++] = '\r';        cmd[pos++] = '\n';    }    assert(pos == totlen);    cmd[pos] = '\0';    free(curargv);    *target = cmd;    return totlen;err:    while(argc--)        sdsfree(curargv[argc]);    free(curargv);    if (curarg != NULL)        sdsfree(curarg);    /* No need to check cmd since it is the last statement that can fail,     * but do it anyway to be as defensive as possible. */    if (cmd != NULL)        free(cmd);    return -1;}


主要是加了quote来判断是否是脚本,脚本内容是用""括起来的。具体应用:

redisAppendCommand(c, "EVAL \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get',KEYS[1]) return result\" 1 foo1 bar1");if (redisGetReply(c, (void**)&r) != REDIS_OK)return;


可以这样使用:
redisAppendCommand(c, "script load \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get', KEYS[1]) return result\"");if (redisGetReply(c, (void**)&r) != REDIS_OK)return;

获得SHA1 校验结果,下次执行只需要执行:evalsha 53d14bf87fe54b95654989afb59c43b1c70d2afb 1 foo1 bar1即可。

redisAppendCommand(c, "script load \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get', KEYS[1]) return result\"");if (redisGetReply(c, (void**)&r) != REDIS_OK)return;printf("------%s\n", r->str);//freeReplyObject(r);std::string tmpstr = "evalsha ";tmpstr += r->str;tmpstr += " 1 foo3 bar3";redisAppendCommand(c, tmpstr.c_str());if (redisGetReply(c, (void**)&r) != REDIS_OK)return;printf("------%s\n", r->str);freeReplyObject(r);


性能如何还没测试。。。


0 0