I just implemented a script-cache for MySQL Proxy and had to learn a bit more about lua internals. As a result I wrote two functions which are generic enough for general consumption:
They also show how to write a
#lua channel on
freenode was a great help, as always.
LUA provide several loaders:
and you can create your own if you have to.
Now, why the need for a new loader ?
The proxy we have
- a global scope caches the scripts
- this cache reloads the scripts if they changed on disk
- each thread executes the same script
- each thread has its own script-scope
which looks like:
/* puts the script at the top */ lua_cache_get_script(global_L. scriptname); L = lua_newthread(global_L); lua_xmove(global_L, L, 1); ... lua_pcall(L, ...);
To set the script-scope we use
lua_setfenv(), but we can't run it against the script itself as the script is shared between all threads. Setting the environment of the script would change it for all threads.
The solution is using a function-factory
return function() ... script ... end
to create a function I can assign a unique environment to.
The loader automaticly adds the header and trailer to the scripts are load-time.
Instead of the normal load-procedure:
luaL_loadfile(L, scriptname); lua_newtable(L); ... lua_setfenv(L, -2); lua_pcall(L, 0, 0, 0);
luaL_loadfile_factory(L, scriptname); /* this function can be cached */ lua_pcall(L, 0, 1, 0); /* returns a function with a clean enviroment */ lua_newtable(L); ... lua_setfenv(L, -2); lua_pcall(L, 0, 0, 0);