|
|
|
#include "first.h"
|
|
|
|
|
|
|
|
#include "mod_magnet_cache.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "stat_cache.h"
|
|
|
|
|
|
|
|
#include "sys-time.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <lualib.h>
|
|
|
|
#include <lauxlib.h>
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static script *script_init(void)
|
|
|
|
{
|
|
|
|
script *const sc = calloc(1, sizeof(*sc));
|
|
|
|
force_assert(sc);
|
|
|
|
return sc;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void script_free(script *sc)
|
|
|
|
{
|
|
|
|
if (!sc) return;
|
|
|
|
lua_pop(sc->L, 1); /* the function copy */
|
|
|
|
lua_close(sc->L);
|
|
|
|
free(sc->name.ptr);
|
|
|
|
free(sc->etag.ptr);
|
|
|
|
free(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
script_cache *script_cache_init(void)
|
|
|
|
{
|
|
|
|
script_cache *p = calloc(1, sizeof(script_cache));
|
|
|
|
force_assert(p);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void script_cache_free_data(script_cache *p)
|
|
|
|
{
|
|
|
|
if (!p) return;
|
|
|
|
for (uint32_t i = 0; i < p->used; ++i)
|
|
|
|
script_free(p->ptr[i]);
|
|
|
|
free(p->ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_State *script_cache_get_script(script_cache *cache, const buffer *name, int etag_flags)
|
|
|
|
{
|
|
|
|
script *sc = NULL;
|
|
|
|
stat_cache_entry *sce;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cache->used; ++i, sc = NULL) {
|
|
|
|
sc = cache->ptr[i];
|
|
|
|
if (!buffer_is_equal(name, &sc->name)) continue;
|
|
|
|
|
|
|
|
if (lua_gettop(sc->L) == 0) break;
|
|
|
|
force_assert(lua_gettop(sc->L) == 1);
|
|
|
|
sce = stat_cache_get_entry(&sc->name);
|
|
|
|
if (NULL == sce) {
|
|
|
|
lua_pop(sc->L, 1); /* pop the old function */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const buffer *etag = stat_cache_etag_get(sce, etag_flags);
|
|
|
|
if (NULL == etag || !buffer_is_equal(&sc->etag, etag)) {
|
|
|
|
/* the etag is outdated, reload the function */
|
|
|
|
lua_pop(sc->L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
force_assert(lua_isfunction(sc->L, -1));
|
|
|
|
|
|
|
|
return sc->L;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the script was script already loaded but either got changed or
|
|
|
|
* failed to load last time */
|
|
|
|
if (sc == NULL) {
|
|
|
|
sc = script_init();
|
|
|
|
|
|
|
|
if (cache->used == cache->size) {
|
|
|
|
cache->size += 16;
|
|
|
|
cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
cache->ptr[cache->used++] = sc;
|
|
|
|
|
|
|
|
buffer_copy_buffer(&sc->name, name);
|
|
|
|
|
|
|
|
sc->L = luaL_newstate();
|
|
|
|
luaL_openlibs(sc->L);
|
|
|
|
}
|
|
|
|
buffer_clear(&sc->etag);
|
|
|
|
|
|
|
|
if (0 != luaL_loadfile(sc->L, name->ptr)) {
|
|
|
|
/* oops, an error, return it */
|
|
|
|
return sc->L;
|
|
|
|
}
|
|
|
|
|
|
|
|
sce = stat_cache_get_entry(&sc->name);
|
|
|
|
if (sce) {
|
[multiple] reduce redundant NULL buffer checks
This commit is a large set of code changes and results in removal of
hundreds, perhaps thousands, of CPU instructions, a portion of which
are on hot code paths.
Most (buffer *) used by lighttpd are not NULL, especially since buffers
were inlined into numerous larger structs such as request_st and chunk.
In the small number of instances where that is not the case, a NULL
check is often performed earlier in a function where that buffer is
later used with a buffer_* func. In the handful of cases that remained,
a NULL check was added, e.g. with r->http_host and r->conf.server_tag.
- check for empty strings at config time and set value to NULL if blank
string will be ignored at runtime; at runtime, simple pointer check
for NULL can be used to check for a value that has been set and is not
blank ("")
- use buffer_is_blank() instead of buffer_string_is_empty(),
and use buffer_is_unset() instead of buffer_is_empty(),
where buffer is known not to be NULL so that NULL check can be skipped
- use buffer_clen() instead of buffer_string_length() when buffer is
known not to be NULL (to avoid NULL check at runtime)
- use buffer_truncate() instead of buffer_string_set_length() to
truncate string, and use buffer_extend() to extend
Examples where buffer known not to be NULL:
- cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL
(though we might set it to NULL if buffer_is_blank(cpv->v.b))
- address of buffer is arg (&foo)
(compiler optimizer detects this in most, but not all, cases)
- buffer is checked for NULL earlier in func
- buffer is accessed in same scope without a NULL check (e.g. b->ptr)
internal behavior change:
callers must not pass a NULL buffer to some funcs.
- buffer_init_buffer() requires non-null args
- buffer_copy_buffer() requires non-null args
- buffer_append_string_buffer() requires non-null args
- buffer_string_space() requires non-null arg
11 months ago
|
|
|
const buffer *etag = stat_cache_etag_get(sce, etag_flags);
|
|
|
|
if (etag)
|
|
|
|
buffer_copy_buffer(&sc->etag, etag);
|
|
|
|
}
|
|
|
|
|
|
|
|
force_assert(lua_isfunction(sc->L, -1));
|
|
|
|
|
|
|
|
return sc->L;
|
|
|
|
}
|