mirror of https://github.com/redis/redis.git
				
				
				
			Lua function creation on EVAL, basic Lua return type to Redis protocol convertion done.
This commit is contained in:
		
							parent
							
								
									21d3294c70
								
							
						
					
					
						commit
						7585836e6e
					
				| 
						 | 
					@ -39,7 +39,6 @@ PREFIX= /usr/local
 | 
				
			||||||
INSTALL_BIN= $(PREFIX)/bin
 | 
					INSTALL_BIN= $(PREFIX)/bin
 | 
				
			||||||
INSTALL= cp -p
 | 
					INSTALL= cp -p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
CCCOLOR="\033[34m"
 | 
					CCCOLOR="\033[34m"
 | 
				
			||||||
LINKCOLOR="\033[34;1m"
 | 
					LINKCOLOR="\033[34;1m"
 | 
				
			||||||
SRCCOLOR="\033[33m"
 | 
					SRCCOLOR="\033[33m"
 | 
				
			||||||
| 
						 | 
					@ -47,7 +46,7 @@ BINCOLOR="\033[37;1m"
 | 
				
			||||||
MAKECOLOR="\033[32;1m"
 | 
					MAKECOLOR="\033[32;1m"
 | 
				
			||||||
ENDCOLOR="\033[0m"
 | 
					ENDCOLOR="\033[0m"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o dscache.o pubsub.o multi.o debug.o sort.o intset.o syncio.o diskstore.o cluster.o crc16.o endian.o
 | 
					OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o dscache.o pubsub.o multi.o debug.o sort.o intset.o syncio.o diskstore.o cluster.o crc16.o endian.o scripting.o
 | 
				
			||||||
BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
 | 
					BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
 | 
				
			||||||
CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o
 | 
					CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o
 | 
				
			||||||
CHECKDUMPOBJ = redis-check-dump.o lzf_c.o lzf_d.o
 | 
					CHECKDUMPOBJ = redis-check-dump.o lzf_c.o lzf_d.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +193,8 @@ struct redisCommand redisCommandTable[] = {
 | 
				
			||||||
    {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0},
 | 
					    {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0},
 | 
				
			||||||
    {"dump",dumpCommand,2,0,NULL,0,0,0,0,0},
 | 
					    {"dump",dumpCommand,2,0,NULL,0,0,0,0,0},
 | 
				
			||||||
    {"object",objectCommand,-2,0,NULL,0,0,0,0,0},
 | 
					    {"object",objectCommand,-2,0,NULL,0,0,0,0,0},
 | 
				
			||||||
    {"client",clientCommand,-2,0,NULL,0,0,0,0,0}
 | 
					    {"client",clientCommand,-2,0,NULL,0,0,0,0,0},
 | 
				
			||||||
 | 
					    {"eval",evalCommand,-3,0,NULL,0,0,0,0,0}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*============================ Utility functions ============================ */
 | 
					/*============================ Utility functions ============================ */
 | 
				
			||||||
| 
						 | 
					@ -981,6 +982,7 @@ void initServer() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (server.ds_enabled) dsInit();
 | 
					    if (server.ds_enabled) dsInit();
 | 
				
			||||||
    if (server.cluster_enabled) clusterInit();
 | 
					    if (server.cluster_enabled) clusterInit();
 | 
				
			||||||
 | 
					    scriptingInit();
 | 
				
			||||||
    srand(time(NULL)^getpid());
 | 
					    srand(time(NULL)^getpid());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
#include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
#include <syslog.h>
 | 
					#include <syslog.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <lua.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ae.h"     /* Event driven programming library */
 | 
					#include "ae.h"     /* Event driven programming library */
 | 
				
			||||||
#include "sds.h"    /* Dynamic safe strings */
 | 
					#include "sds.h"    /* Dynamic safe strings */
 | 
				
			||||||
| 
						 | 
					@ -654,6 +655,8 @@ struct redisServer {
 | 
				
			||||||
    /* Cluster */
 | 
					    /* Cluster */
 | 
				
			||||||
    int cluster_enabled;
 | 
					    int cluster_enabled;
 | 
				
			||||||
    clusterState cluster;
 | 
					    clusterState cluster;
 | 
				
			||||||
 | 
					    /* Scripting */
 | 
				
			||||||
 | 
					    lua_State *lua;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct pubsubPattern {
 | 
					typedef struct pubsubPattern {
 | 
				
			||||||
| 
						 | 
					@ -1075,6 +1078,9 @@ int clusterAddNode(clusterNode *node);
 | 
				
			||||||
void clusterCron(void);
 | 
					void clusterCron(void);
 | 
				
			||||||
clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *ask);
 | 
					clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *ask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Scripting */
 | 
				
			||||||
 | 
					void scriptingInit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Git SHA1 */
 | 
					/* Git SHA1 */
 | 
				
			||||||
char *redisGitSHA1(void);
 | 
					char *redisGitSHA1(void);
 | 
				
			||||||
char *redisGitDirty(void);
 | 
					char *redisGitDirty(void);
 | 
				
			||||||
| 
						 | 
					@ -1203,6 +1209,7 @@ void migrateCommand(redisClient *c);
 | 
				
			||||||
void dumpCommand(redisClient *c);
 | 
					void dumpCommand(redisClient *c);
 | 
				
			||||||
void objectCommand(redisClient *c);
 | 
					void objectCommand(redisClient *c);
 | 
				
			||||||
void clientCommand(redisClient *c);
 | 
					void clientCommand(redisClient *c);
 | 
				
			||||||
 | 
					void evalCommand(redisClient *c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__GNUC__)
 | 
					#if defined(__GNUC__)
 | 
				
			||||||
void *calloc(size_t count, size_t size) __attribute__ ((deprecated));
 | 
					void *calloc(size_t count, size_t size) __attribute__ ((deprecated));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					#include "redis.h"
 | 
				
			||||||
 | 
					#include "sha1.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <lua.h>
 | 
				
			||||||
 | 
					#include <lauxlib.h>
 | 
				
			||||||
 | 
					#include <lualib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scriptingInit(void) {
 | 
				
			||||||
 | 
					    lua_State *lua = lua_open();
 | 
				
			||||||
 | 
					    luaL_openlibs(lua);
 | 
				
			||||||
 | 
					    server.lua = lua;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Hash the scripit into a SHA1 digest. We use this as Lua function name.
 | 
				
			||||||
 | 
					 * Digest should point to a 41 bytes buffer: 40 for SHA1 converted into an
 | 
				
			||||||
 | 
					 * hexadecimal number, plus 1 byte for null term. */
 | 
				
			||||||
 | 
					void hashScript(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';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void luaReplyToRedisReply(redisClient *c, lua_State *lua) {
 | 
				
			||||||
 | 
					    int t = lua_type(lua,1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(t) {
 | 
				
			||||||
 | 
					    case LUA_TSTRING:
 | 
				
			||||||
 | 
					        addReplyBulkCBuffer(c,(char*)lua_tostring(lua,1),lua_strlen(lua,1));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case LUA_TBOOLEAN:
 | 
				
			||||||
 | 
					        addReply(c,lua_toboolean(lua,1) ? shared.cone : shared.czero);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case LUA_TNUMBER:
 | 
				
			||||||
 | 
					        addReplyLongLong(c,(long long)lua_tonumber(lua,1));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        addReply(c,shared.nullbulk);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    lua_pop(lua,1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void evalCommand(redisClient *c) {
 | 
				
			||||||
 | 
					    lua_State *lua = server.lua;
 | 
				
			||||||
 | 
					    char funcname[43];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* We obtain the script SHA1, then check if this function is already
 | 
				
			||||||
 | 
					     * defined into the Lua state */
 | 
				
			||||||
 | 
					    funcname[0] = 'f';
 | 
				
			||||||
 | 
					    funcname[1] = '_';
 | 
				
			||||||
 | 
					    hashScript(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
 | 
				
			||||||
 | 
					    lua_getglobal(lua, funcname);
 | 
				
			||||||
 | 
					    if (lua_isnil(lua,1)) {
 | 
				
			||||||
 | 
					        /* Function not defined... let's define it. */
 | 
				
			||||||
 | 
					        sds funcdef = sdsempty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lua_pop(lua,1); /* remove the nil from the stack */
 | 
				
			||||||
 | 
					        funcdef = sdscat(funcdef,"function ");
 | 
				
			||||||
 | 
					        funcdef = sdscatlen(funcdef,funcname,42);
 | 
				
			||||||
 | 
					        funcdef = sdscatlen(funcdef," ()\n",4);
 | 
				
			||||||
 | 
					        funcdef = sdscatlen(funcdef,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
 | 
				
			||||||
 | 
					        funcdef = sdscatlen(funcdef,"\nend\n",5);
 | 
				
			||||||
 | 
					        printf("Defining:\n%s\n",funcdef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"func definition")) {
 | 
				
			||||||
 | 
					            addReplyErrorFormat(c,"Error compiling script (new function): %s\n",
 | 
				
			||||||
 | 
					                lua_tostring(lua,-1));
 | 
				
			||||||
 | 
					            lua_pop(lua,1);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (lua_pcall(lua,0,0,0)) {
 | 
				
			||||||
 | 
					            addReplyErrorFormat(c,"Error running script (new function): %s\n",
 | 
				
			||||||
 | 
					                lua_tostring(lua,-1));
 | 
				
			||||||
 | 
					            lua_pop(lua,1);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        lua_getglobal(lua, funcname);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* At this point whatever this script was never seen before or if it was
 | 
				
			||||||
 | 
					     * already defined, we can call it. We have zero arguments and expect
 | 
				
			||||||
 | 
					     * a single return value. */
 | 
				
			||||||
 | 
					    if (lua_pcall(lua,0,1,0)) {
 | 
				
			||||||
 | 
					        addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
 | 
				
			||||||
 | 
					            funcname, lua_tostring(lua,-1));
 | 
				
			||||||
 | 
					        lua_pop(lua,1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    luaReplyToRedisReply(c,lua);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue