From 8e031c1b214b4adcd1c419c2b52cdb94e8d7ef8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E9=A3=8E?= Date: Tue, 17 Dec 2013 18:26:08 +0800 Subject: [PATCH] cache lua code load --- Makefile | 2 +- service-src/luacode_cache.c | 298 ++++++++++++++++++++++++++++++++++++ service-src/luacode_cache.h | 12 ++ service-src/service_lua.c | 56 +++---- skynet-src/skynet_logger.c | 1 + 5 files changed, 340 insertions(+), 29 deletions(-) create mode 100644 service-src/luacode_cache.c create mode 100644 service-src/luacode_cache.h diff --git a/Makefile b/Makefile index f8ae90d5..3f83e0aa 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ service/harbor.so : service-src/service_harbor.c service/logger.so : skynet-src/skynet_logger.c gcc $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -service/snlua.so : service-src/service_lua.c +service/snlua.so : service-src/service_lua.c service-src/luacode_cache.c gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src service/gate.so : service-src/service_gate.c diff --git a/service-src/luacode_cache.c b/service-src/luacode_cache.c new file mode 100644 index 00000000..801cd80a --- /dev/null +++ b/service-src/luacode_cache.c @@ -0,0 +1,298 @@ +#include "luacode_cache.h" + +#include +#include +#include +#include +#include + +#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} +#define UNLOCK(q) __sync_lock_release(&(q)->lock); + +struct codecache { + int lock; + lua_State *L; +}; + +static struct codecache CC = { 0 , NULL }; + +static void +_init() { + CC.lock = 0; + CC.L = luaL_newstate(); +} + +static const char * +_load(const char *key, size_t *sz) { + if (CC.L == NULL) + return NULL; + LOCK(&CC) + lua_State *L = CC.L; + lua_getglobal(L, key); + const char * result = NULL; + if (lua_isstring(L,-1)) { + result = lua_tolstring(L, -1, sz); + } + lua_pop(L, 1); + UNLOCK(&CC) + + return result; +} + +static const char * +_save(const char *key, const char * code, size_t *sz) { + lua_State *L; + const char * result = NULL; + + LOCK(&CC) + if (CC.L == NULL) { + _init(); + L = CC.L; + } else { + L = CC.L; + lua_getglobal(L, key); + if (lua_isstring(L,-1)) { + size_t code_sz = *sz; + result = lua_tolstring(L, -1, sz); + assert(code_sz == *sz); + lua_pop(L, 1); + goto _ret; + } + lua_pop(L, 1); + } + lua_pushlstring(L, code, *sz); + result = lua_tostring(L, -1); + lua_setglobal(L, key); +_ret: + UNLOCK(&CC) + return result; +} + +const char * +luacode_load(const char * key, const char * code, size_t *sz) { + if (code == NULL) { + return _load(key, sz); + } + const char * result = _load(key,sz); + if (result) { + return result; + } + return _save(key, code, sz); +} + +/* +static int +cache_load(lua_State *L) { + return 0; +} +*/ + +// copy from lbaselib.c +static int +load_aux (lua_State *L, int status, int envidx) { + if (status == LUA_OK) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else { /* error (message is on top of the stack) */ + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + +static int +writer (lua_State *L, const void* b, size_t size, void* B) { + (void)L; + luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); + return 0; +} + +static void +str_dump (lua_State *L) { + luaL_Buffer b; + luaL_buffinit(L,&b); + if (lua_dump(L, writer, &b) != 0) + luaL_error(L, "unable to dump given function"); + luaL_pushresult(&b); +} + + +static int +cache_loadfile(lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status; + if (fname == NULL) { + status = luaL_loadfilex(L, fname, mode); + } else { + // read cache + size_t sz = 0; + const char * bytecode = luacode_load(fname, NULL, &sz); + if (bytecode) { + // load from cache + status = luaL_loadbuffer(L, bytecode, sz, fname); + } else { + status = luaL_loadfilex(L, fname, mode); + if (status == LUA_OK) { + str_dump(L); + const char * bytecode = lua_tolstring(L,-1,&sz); + // update cache + luacode_load(fname, bytecode, &sz); + lua_pop(L,1); + } + } + } + return load_aux(L, status, env); +} + +int +luacode_loadfile(lua_State *L, const char *filename) { + size_t sz = 0; + const char * bytecode = luacode_load(filename, NULL, &sz); + int status; + if (bytecode) { + status = luaL_loadbuffer(L, bytecode, sz, filename); + } else { + status = luaL_loadfile(L, filename); + if (status == LUA_OK) { + str_dump(L); + const char * bytecode = lua_tolstring(L,-1,&sz); + // update cache + luacode_load(filename, bytecode, &sz); + lua_pop(L,1); + } + } + return status; +} + +// require loader, copy and modify from loadlib.c + +#if !defined (LUA_PATH_SEP) +#define LUA_PATH_SEP ";" +#endif +#if !defined (LUA_PATH_MARK) +#define LUA_PATH_MARK "?" +#endif +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + +static int +readable (const char *filename) { + size_t sz = 0; + const char * bytecode = luacode_load(filename, NULL, &sz); + if (bytecode) { + return 1; + } + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + +static const char * +pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char * +searchpath (lua_State *L, const char *name, + const char *path, + const char *sep, + const char *dirsep) { + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + if (*sep != '\0') /* non-empty separator? */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ + } + luaL_pushresult(&msg); /* create error message */ + return NULL; /* not found */ +} + +static const char * +findfile (lua_State *L, const char *name, + const char *pname, + const char *dirsep) { + const char *path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + return searchpath(L, name, path, ".", dirsep); +} + +static int +checkload (lua_State *L, int stat, const char *filename) { + if (stat) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module " LUA_QS + " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + +static int +searcher_cache (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luacode_loadfile(L, filename) == LUA_OK), filename); +} + +static void +replace_searcher_lua(lua_State *L) { + lua_getglobal(L, "package"); + if (!lua_istable(L,-1)) { + luaL_error(L, "Can't find package"); + } + lua_getfield(L, -1, "searchers"); + if (!lua_istable(L,-1)) { + luaL_error(L, "Can't find package.searchers"); + } + lua_pushvalue(L,-2); + lua_pushcclosure(L, searcher_cache, 1); + // package.searcher[2] is searcher_lua, replace it. + lua_rawseti(L, -2, 2); + lua_pop(L,2); +} + +//------------------------- + +int +luacode_lib(lua_State *L) { + replace_searcher_lua(L); + luaL_Reg l[] = { +// { "load", cache_load }, + { "loadfile", cache_loadfile }, + { NULL, NULL }, + }; + luaL_newlib(L,l); + return 1; +} + + diff --git a/service-src/luacode_cache.h b/service-src/luacode_cache.h new file mode 100644 index 00000000..7b01c382 --- /dev/null +++ b/service-src/luacode_cache.h @@ -0,0 +1,12 @@ +#ifndef lua_code_cache_h +#define lua_code_cache_h + +#include +#include + +const char * luacode_load(const char * key, const char * code, size_t *sz); + +int luacode_loadfile(lua_State *L, const char *filename); +int luacode_lib(lua_State *); + +#endif diff --git a/service-src/service_lua.c b/service-src/service_lua.c index 144ca5f5..e8ef4f46 100644 --- a/service-src/service_lua.c +++ b/service-src/service_lua.c @@ -6,6 +6,7 @@ #include #include "luacompat52.h" #include "service_lua.h" +#include "luacode_cache.h" #include #include @@ -66,38 +67,35 @@ _try_load(lua_State *L, const char * path, int pathlen, const char * name) { exit(1); } tmp[namelen+pathlen-1] = '\0'; - FILE *f = fopen(tmp,"rb"); - if (f == NULL) { - return -1; - } else { - fclose(f); - int r = luaL_loadfile(L,tmp); - if (r == LUA_OK) { - int i; - for (i=namelen+pathlen-2;i>=0;i--) { - if (tmp[i] == '/') { - lua_pushlstring(L,tmp,i+1); - lua_setglobal(L,"SERVICE_PATH"); - break; - } + // luacode_loadfile is the same with luaL_loadfile except cache. + int r = luacode_loadfile(L,tmp); + if (r == LUA_OK) { + int i; + for (i=namelen+pathlen-2;i>=0;i--) { + if (tmp[i] == '/') { + lua_pushlstring(L,tmp,i+1); + lua_setglobal(L,"SERVICE_PATH"); + break; } - if (i<0) { - return 0; - } - lua_getglobal(L,"package"); - lua_getfield(L,-1,"path"); - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addlstring(&b, tmp, i+1); - luaL_addstring(&b, "?.lua;"); - luaL_addvalue(&b); - luaL_pushresult(&b); - lua_setfield(L,-2,"path"); - lua_pop(L,1); + } + if (i<0) { return 0; } - return 1; + lua_getglobal(L,"package"); + lua_getfield(L,-1,"path"); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addlstring(&b, tmp, i+1); + luaL_addstring(&b, "?.lua;"); + luaL_addvalue(&b); + luaL_pushresult(&b); + lua_setfield(L,-2,"path"); + lua_pop(L,1); + return 0; + } else if (r == LUA_ERRFILE) { + return -1; } + return 1; } static int @@ -168,6 +166,8 @@ _init(struct snlua *l, struct skynet_context *ctx, const char * args) { luaL_openlibs(L); lua_pushlightuserdata(L, l); lua_setfield(L, LUA_REGISTRYINDEX, "skynet_lua"); + luaL_requiref(L, "skynet.codecache", luacode_lib , 0); + lua_pop(L,1); lua_gc(L, LUA_GCRESTART, 0); char tmp[strlen(args)+1]; diff --git a/skynet-src/skynet_logger.c b/skynet-src/skynet_logger.c index 918b2359..9ec7c5d9 100644 --- a/skynet-src/skynet_logger.c +++ b/skynet-src/skynet_logger.c @@ -31,6 +31,7 @@ _logger(struct skynet_context * context, void *ud, int type, int session, uint32 fprintf(inst->handle, "[:%x] ",source); fwrite(msg, sz , 1, inst->handle); fprintf(inst->handle, "\n"); + fflush(inst->handle); return 0; }