1#include "mod_magnet_cache.h" 2#include "stat_cache.h" 3 4#include <stdlib.h> 5#include <time.h> 6#include <assert.h> 7 8#ifdef HAVE_LUA_H 9#include <lualib.h> 10#include <lauxlib.h> 11 12static script *script_init() { 13 script *sc; 14 15 sc = calloc(1, sizeof(*sc)); 16 sc->name = buffer_init(); 17 sc->etag = buffer_init(); 18 19 return sc; 20} 21 22static void script_free(script *sc) { 23 if (!sc) return; 24 25 lua_pop(sc->L, 1); /* the function copy */ 26 27 buffer_free(sc->name); 28 buffer_free(sc->etag); 29 30 lua_close(sc->L); 31 32 free(sc); 33} 34 35script_cache *script_cache_init() { 36 script_cache *p; 37 38 p = calloc(1, sizeof(*p)); 39 40 return p; 41} 42 43void script_cache_free(script_cache *p) { 44 size_t i; 45 46 if (!p) return; 47 48 for (i = 0; i < p->used; i++) { 49 script_free(p->ptr[i]); 50 } 51 52 free(p->ptr); 53 54 free(p); 55} 56 57lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) { 58 size_t i; 59 script *sc = NULL; 60 stat_cache_entry *sce; 61 62 for (i = 0; i < cache->used; i++) { 63 sc = cache->ptr[i]; 64 65 if (buffer_is_equal(name, sc->name)) { 66 sc->last_used = time(NULL); 67 68 /* oops, the script failed last time */ 69 70 if (lua_gettop(sc->L) == 0) break; 71 72 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) { 73 lua_pop(sc->L, 1); /* pop the old function */ 74 break; 75 } 76 77 if (!buffer_is_equal(sce->etag, sc->etag)) { 78 /* the etag is outdated, reload the function */ 79 lua_pop(sc->L, 1); 80 break; 81 } 82 83 force_assert(lua_isfunction(sc->L, -1)); 84 lua_pushvalue(sc->L, -1); /* copy the function-reference */ 85 86 return sc->L; 87 } 88 89 sc = NULL; 90 } 91 92 /* if the script was script already loaded but either got changed or 93 * failed to load last time */ 94 if (sc == NULL) { 95 sc = script_init(); 96 97 if (cache->size == 0) { 98 cache->size = 16; 99 cache->ptr = malloc(cache->size * sizeof(*(cache->ptr))); 100 } else if (cache->used == cache->size) { 101 cache->size += 16; 102 cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr))); 103 } 104 105 cache->ptr[cache->used++] = sc; 106 107 buffer_copy_buffer(sc->name, name); 108 109 sc->L = luaL_newstate(); 110 luaL_openlibs(sc->L); 111 } 112 113 sc->last_used = time(NULL); 114 115 if (0 != luaL_loadfile(sc->L, name->ptr)) { 116 /* oops, an error, return it */ 117 118 return sc->L; 119 } 120 121 if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) { 122 buffer_copy_buffer(sc->etag, sce->etag); 123 } 124 125 /** 126 * pcall() needs the function on the stack 127 * 128 * as pcall() will pop the script from the stack when done, we have to 129 * duplicate it here 130 */ 131 force_assert(lua_isfunction(sc->L, -1)); 132 lua_pushvalue(sc->L, -1); /* copy the function-reference */ 133 134 return sc->L; 135} 136 137#endif 138