summaryrefslogtreecommitdiff
path: root/src/stat_cache.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2019-12-05 03:16:25 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2020-07-08 19:54:28 -0400
commit68d8d4c532c51cdc5ac4959e002c0ba5cf34a2c1 (patch)
tree624ed9d55263abcbe8aa6c55b74a01c11d0424e9 /src/stat_cache.c
parentb5775b995156f91d94185ec58410a4ccfb7560a4 (diff)
downloadlighttpd-git-68d8d4c532c51cdc5ac4959e002c0ba5cf34a2c1.tar.gz
[multiple] stat_cache singleton
Diffstat (limited to 'src/stat_cache.c')
-rw-r--r--src/stat_cache.c497
1 files changed, 262 insertions, 235 deletions
diff --git a/src/stat_cache.c b/src/stat_cache.c
index 782388af..716f5b1f 100644
--- a/src/stat_cache.c
+++ b/src/stat_cache.c
@@ -38,19 +38,22 @@
*/
enum {
- STAT_CACHE_ENGINE_UNSET,
+ STAT_CACHE_ENGINE_SIMPLE, /*(default)*/
STAT_CACHE_ENGINE_NONE,
- STAT_CACHE_ENGINE_SIMPLE,
STAT_CACHE_ENGINE_FAM
};
struct stat_cache_fam; /* declaration */
typedef struct stat_cache {
+ int stat_cache_engine;
splay_tree *files; /* nodes of tree are (stat_cache_entry *) */
struct stat_cache_fam *scf;
+ log_error_st *errh;
} stat_cache;
+static stat_cache sc;
+
/* the famous DJB hash function for strings */
__attribute_pure__
@@ -206,10 +209,10 @@ static void fam_dir_tag_refcnt(splay_tree *t, int *keys, int *ndx)
}
}
-static void fam_dir_periodic_cleanup(server *srv) {
+static void fam_dir_periodic_cleanup() {
int max_ndx, i;
int keys[8192]; /* 32k size on stack */
- stat_cache_fam * const scf = srv->stat_cache->scf;
+ stat_cache_fam * const scf = sc.scf;
do {
if (!scf->dirs) return;
max_ndx = 0;
@@ -241,10 +244,10 @@ static void fam_dir_invalidate_tree(splay_tree *t, const char *name, size_t len)
}
/* declarations */
-static void stat_cache_delete_tree(server *srv, const char *name, size_t len);
-static void stat_cache_invalidate_dir_tree(server *srv, const char *name, size_t len);
+static void stat_cache_delete_tree(const char *name, size_t len);
+static void stat_cache_invalidate_dir_tree(const char *name, size_t len);
-static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
+static void stat_cache_handle_fdevent_in(stat_cache_fam *scf)
{
for (int i = 0, ndx; i || (i = FAMPending(&scf->fam)) > 0; --i) {
FAMEvent fe;
@@ -290,7 +293,7 @@ static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
buffer_append_string_len(n, CONST_STR_LEN("/"));
buffer_append_string_len(n,fe.filename,strlen(fe.filename));
/* (alternatively, could chose to stat() and update)*/
- stat_cache_invalidate_entry(srv, CONST_BUF_LEN(n));
+ stat_cache_invalidate_entry(CONST_BUF_LEN(n));
fam_link = /*(check if might be symlink to monitored dir)*/
stat_cache_sptree_find(&scf->dirs, CONST_BUF_LEN(n));
@@ -301,7 +304,7 @@ static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
if (fam_link) {
/* replaced symlink changes containing dir */
- stat_cache_invalidate_entry(srv, CONST_BUF_LEN(n));
+ stat_cache_invalidate_entry(CONST_BUF_LEN(n));
/* handle symlink to dir as deleted dir below */
fe.code = FAMDeleted;
fam_dir = fam_link;
@@ -315,15 +318,15 @@ static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
switch(fe.code) {
case FAMChanged:
- stat_cache_invalidate_entry(srv, CONST_BUF_LEN(fam_dir->name));
+ stat_cache_invalidate_entry(CONST_BUF_LEN(fam_dir->name));
break;
case FAMDeleted:
case FAMMoved:
- stat_cache_delete_tree(srv, CONST_BUF_LEN(fam_dir->name));
+ stat_cache_delete_tree(CONST_BUF_LEN(fam_dir->name));
fam_dir_invalidate_node(fam_dir);
if (scf->dirs)
fam_dir_invalidate_tree(scf->dirs,CONST_BUF_LEN(fam_dir->name));
- fam_dir_periodic_cleanup(srv);
+ fam_dir_periodic_cleanup();
break;
default:
break;
@@ -333,11 +336,11 @@ static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
static handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent)
{
- stat_cache_fam *scf = srv->stat_cache->scf;
+ stat_cache_fam * const scf = sc.scf;
UNUSED(_fce);
if (revent & FDEVENT_IN) {
- stat_cache_handle_fdevent_in(srv, scf);
+ stat_cache_handle_fdevent_in(scf);
}
if (revent & (FDEVENT_HUP|FDEVENT_RDHUP)) {
@@ -346,7 +349,7 @@ static handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent)
"FAM connection closed; disabling stat_cache.");
/* (although effectively STAT_CACHE_ENGINE_NONE,
* do not change here so that periodic jobs clean up memory)*/
- /*srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE; */
+ /*sc.stat_cache_engine = STAT_CACHE_ENGINE_NONE; */
fdevent_fdnode_event_del(srv->ev, scf->fdn);
fdevent_unregister(srv->ev, scf->fd);
scf->fdn = NULL;
@@ -400,7 +403,7 @@ static void stat_cache_free_fam(stat_cache_fam *scf) {
free(scf);
}
-static fam_dir_entry * fam_dir_monitor(server *srv, stat_cache_fam *scf, char *fn, size_t dirlen, struct stat *st)
+static fam_dir_entry * fam_dir_monitor(stat_cache_fam *scf, char *fn, size_t dirlen, struct stat *st)
{
if (NULL == scf->fdn) return NULL; /* FAM connection closed; do nothing */
const int fn_is_dir = S_ISDIR(st->st_mode);
@@ -461,9 +464,9 @@ static fam_dir_entry * fam_dir_monitor(server *srv, stat_cache_fam *scf, char *f
* fam_dir is not NULL and so splaytree_insert not called below)*/
if (scf->dirs) fam_dir_invalidate_tree(scf->dirs, fn, dirlen);
if (!fn_is_dir) /*(if dir, caller is updating stat_cache_entry)*/
- stat_cache_update_entry(srv, fn, dirlen, st, NULL);
+ stat_cache_update_entry(fn, dirlen, st, NULL);
/*(must not delete tree since caller is holding a valid node)*/
- stat_cache_invalidate_dir_tree(srv, fn, dirlen);
+ stat_cache_invalidate_dir_tree(fn, dirlen);
if (0 != FAMCancelMonitor(&scf->fam, &fam_dir->req)
|| 0 != FAMMonitorDirectory(&scf->fam, fam_dir->name->ptr,
&fam_dir->req,
@@ -482,9 +485,9 @@ static fam_dir_entry * fam_dir_monitor(server *srv, stat_cache_fam *scf, char *f
if (0 != FAMMonitorDirectory(&scf->fam,fam_dir->name->ptr,&fam_dir->req,
(void *)(intptr_t)dir_ndx)) {
- log_error(srv->errh, __FILE__, __LINE__,
- "monitoring dir failed: %s file: %s %s",
- fam_dir->name->ptr, fn, FamErrlist[FAMErrno]);
+ log_error(sc.errh, __FILE__, __LINE__,
+ "monitoring dir failed: %s file: %s %s",
+ fam_dir->name->ptr, fn, FamErrlist[FAMErrno]);
fam_dir_entry_free(fam_dir);
return NULL;
}
@@ -511,7 +514,7 @@ static fam_dir_entry * fam_dir_monitor(server *srv, stat_cache_fam *scf, char *f
fam_dir->fam_parent = NULL;
}
if (S_ISLNK(lst.st_mode)) {
- fam_dir->fam_parent = fam_dir_monitor(srv, scf, fn, dirlen, &lst);
+ fam_dir->fam_parent = fam_dir_monitor(scf, fn, dirlen, &lst);
}
}
@@ -522,127 +525,126 @@ static fam_dir_entry * fam_dir_monitor(server *srv, stat_cache_fam *scf, char *f
#endif
-stat_cache *stat_cache_init(server *srv) {
- stat_cache *sc = NULL;
- UNUSED(srv);
+static stat_cache_entry * stat_cache_entry_init(void) {
+ stat_cache_entry *sce = calloc(1, sizeof(*sce));
+ force_assert(NULL != sce);
+ return sce;
+}
- sc = calloc(1, sizeof(*sc));
- force_assert(NULL != sc);
+static void stat_cache_entry_free(void *data) {
+ stat_cache_entry *sce = data;
+ if (!sce) return;
-#ifdef HAVE_FAM_H
- if (STAT_CACHE_ENGINE_FAM == srv->srvconf.stat_cache_engine) {
- sc->scf = stat_cache_init_fam(srv);
- if (NULL == sc->scf) {
- free(sc);
- return NULL;
- }
- }
-#endif
+ #ifdef HAVE_FAM_H
+ /*(decrement refcnt only;
+ * defer cancelling FAM monitor on dir even if refcnt reaches zero)*/
+ if (sce->fam_dir) --((fam_dir_entry *)sce->fam_dir)->refcnt;
+ #endif
- return sc;
+ free(sce->name.ptr);
+ free(sce->etag.ptr);
+ if (sce->content_type.size) free(sce->content_type.ptr);
+
+ free(sce);
}
-static stat_cache_entry * stat_cache_entry_init(void) {
- stat_cache_entry *sce = NULL;
+#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
- sce = calloc(1, sizeof(*sce));
- force_assert(NULL != sce);
+static const char *attrname = "Content-Type";
+static char attrval[128];
+static buffer attrb = { attrval, 0, 0 };
- sce->name = buffer_init();
- sce->etag = buffer_init();
- sce->content_type = buffer_init();
+static int stat_cache_attr_get(char *name) {
+ #if defined(HAVE_XATTR)
+ int attrlen = sizeof(attrval)-1;
+ if (0 == attr_get(name, attrname, attrval, &attrlen, 0))
+ #elif defined(HAVE_EXTATTR)
+ ssize_t attrlen;
+ if (0 < (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, attrname,
+ attrval, sizeof(attrval)-1)))
+ #endif
+ {
+ attrval[attrlen] = '\0';
+ attrb.used = (uint32_t)(attrlen + 1);
+ return 1;
+ }
+ return 0;
+}
- return sce;
+#endif
+
+int stat_cache_init(server *srv) {
+ #ifdef HAVE_FAM_H
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
+ sc.errh = srv->errh;
+ sc.scf = stat_cache_init_fam(srv);
+ if (NULL == sc.scf) return 0;
+ }
+ #endif
+
+ return 1;
}
-static void stat_cache_entry_free(void *data) {
- stat_cache_entry *sce = data;
- if (!sce) return;
+void stat_cache_free(void) {
+ splay_tree *sptree = sc.files;
+ while (sptree) {
+ stat_cache_entry_free(sptree->data);
+ sptree = splaytree_delete(sptree, sptree->key);
+ }
+ sc.files = NULL;
- #ifdef HAVE_FAM_H
- /*(decrement refcnt only;
- * defer cancelling FAM monitor on dir even if refcnt reaches zero)*/
- if (sce->fam_dir) --((fam_dir_entry *)sce->fam_dir)->refcnt;
- #endif
+ #ifdef HAVE_FAM_H
+ stat_cache_free_fam(sc.scf);
+ sc.scf = NULL;
+ sc.errh = NULL;
+ #endif
- buffer_free(sce->etag);
- buffer_free(sce->name);
- buffer_free(sce->content_type);
+ #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ attrname = "Content-Type";
+ #endif
- free(sce);
+ sc.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE; /*(default)*/
}
-void stat_cache_free(stat_cache *sc) {
- while (sc->files) {
- splay_tree *node = sc->files;
- stat_cache_entry_free(node->data);
- sc->files = splaytree_delete(sc->files, node->key);
- }
-
-#ifdef HAVE_FAM_H
- stat_cache_free_fam(sc->scf);
-#endif
- free(sc);
+void stat_cache_xattrname (const char *name) {
+ #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ attrname = name;
+ #else
+ UNUSED(name);
+ #endif
}
int stat_cache_choose_engine (server *srv, const buffer *stat_cache_string) {
- if (buffer_string_is_empty(stat_cache_string)) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+ if (buffer_string_is_empty(stat_cache_string))
+ sc.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+ else if (buffer_eq_slen(stat_cache_string, CONST_STR_LEN("simple")))
+ sc.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
#ifdef HAVE_FAM_H
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
+ else if (buffer_eq_slen(stat_cache_string, CONST_STR_LEN("fam")))
+ sc.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
#endif
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
- } else {
- log_error(srv->errh, __FILE__, __LINE__,
- "server.stat-cache-engine can be one of \"disable\", \"simple\","
+ else if (buffer_eq_slen(stat_cache_string, CONST_STR_LEN("disable")))
+ sc.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "server.stat-cache-engine can be one of \"disable\", \"simple\","
#ifdef HAVE_FAM_H
- " \"fam\","
+ " \"fam\","
#endif
- " but not: %s", stat_cache_string->ptr);
- return -1;
- }
- return 0;
-}
-
-#if defined(HAVE_XATTR)
-static int stat_cache_attr_get(buffer *buf, char *name, const char *xattrname) {
- int attrlen;
- int ret;
-
- buffer_string_prepare_copy(buf, 1023);
- attrlen = buf->size - 1;
- if(0 == (ret = attr_get(name, xattrname, buf->ptr, &attrlen, 0))) {
- buffer_commit(buf, attrlen);
- }
- return ret;
-}
-#elif defined(HAVE_EXTATTR)
-static int stat_cache_attr_get(buffer *buf, char *name, const char *xattrname) {
- ssize_t attrlen;
-
- buffer_string_prepare_copy(buf, 1023);
-
- if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, xattrname, buf->ptr, buf->size - 1))) {
- buf->used = attrlen + 1;
- buf->ptr[attrlen] = '\0';
- return 0;
- }
- return -1;
+ " but not: %s", stat_cache_string->ptr);
+ return -1;
+ }
+ return 0;
}
-#endif
-const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *name, size_t nlen)
+const buffer * stat_cache_mimetype_by_ext(const array * const mimetypes, const char * const name, const size_t nlen)
{
- const char *end = name + nlen; /*(end of string)*/
- const size_t used = con->conf.mimetypes->used;
+ const char * const end = name + nlen; /*(end of string)*/
+ const uint32_t used = mimetypes->used;
if (used < 16) {
- for (size_t i = 0; i < used; ++i) {
+ for (uint32_t i = 0; i < used; ++i) {
/* suffix match */
- const data_string *ds = (data_string *)con->conf.mimetypes->data[i];
+ const data_string *ds = (data_string *)mimetypes->data[i];
const size_t klen = buffer_string_length(&ds->key);
if (klen <= nlen && buffer_eq_icase_ssn(end-klen, ds->key.ptr, klen))
return &ds->value;
@@ -659,107 +661,149 @@ const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *nam
s = name;
}
/* search for basename, then longest .ext2.ext1, then .ext1, then "" */
- ds = (const data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ ds = (const data_string *)array_get_element_klen(mimetypes, s, end - s);
if (NULL != ds) return &ds->value;
while (++s < end) {
while (*s != '.' && ++s != end) ;
if (s == end) break;
/* search ".ext" then "ext" */
- ds = (const data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ ds = (const data_string *)array_get_element_klen(mimetypes, s, end - s);
if (NULL != ds) return &ds->value;
/* repeat search without leading '.' to handle situation where
* admin configured mimetype.assign keys without leading '.' */
if (++s < end) {
if (*s == '.') { --s; continue; }
- ds = (const data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ ds = (const data_string *)array_get_element_klen(mimetypes, s, end - s);
if (NULL != ds) return &ds->value;
}
}
/* search for ""; catchall */
- ds = (const data_string *)array_get_element_klen(con->conf.mimetypes, CONST_STR_LEN(""));
+ ds = (const data_string *)array_get_element_klen(mimetypes, CONST_STR_LEN(""));
if (NULL != ds) return &ds->value;
}
return NULL;
}
-const buffer * stat_cache_content_type_get(const connection *con, const buffer *name, stat_cache_entry *sce)
+#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+
+const buffer * stat_cache_mimetype_by_xattr(const char * const name)
+{
+ return stat_cache_attr_get(name) ? &attrb : NULL;
+}
+
+const buffer * stat_cache_content_type_get_by_xattr(stat_cache_entry *sce, const array *mimetypes, int use_xattr)
{
/*(invalid caching if user config has multiple, different
* con->conf.mimetypes for same extension (not expected))*/
- if (!buffer_string_is_empty(sce->content_type)) return sce->content_type;
-
- if (S_ISREG(sce->st.st_mode)) {
- /* determine mimetype */
- buffer_clear(sce->content_type);
- #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
- if (con->conf.use_xattr) {
- stat_cache_attr_get(sce->content_type, name->ptr, con->srv->srvconf.xattr_name);
+ if (!buffer_string_is_empty(&sce->content_type)) return &sce->content_type;
+
+ if (!S_ISREG(sce->st.st_mode)) return NULL;
+
+ /* cache mimetype */
+ const buffer *mtype =
+ (use_xattr) ? stat_cache_mimetype_by_xattr(sce->name.ptr) : NULL;
+ if (NULL == mtype)
+ mtype = stat_cache_mimetype_by_ext(mimetypes,CONST_BUF_LEN(&sce->name));
+ if (NULL != mtype) {
+ if (sce->content_type.size) {
+ buffer_copy_buffer(&sce->content_type, mtype);
}
- #endif
- /* xattr did not set a content-type. ask the config */
- if (buffer_string_is_empty(sce->content_type)) {
- const buffer *type = stat_cache_mimetype_by_ext(con, CONST_BUF_LEN(name));
- if (NULL != type) {
- buffer_copy_buffer(sce->content_type, type);
- }
+ else if (mtype == &attrb) {
+ sce->content_type.ptr = NULL;
+ buffer_copy_buffer(&sce->content_type, mtype);
+ }
+ else {
+ /*(copy pointers from mimetypes array; avoid allocation)*/
+ sce->content_type.ptr = mtype->ptr;
+ sce->content_type.used = mtype->used;
+ /*(leave sce->content_type.size = 0 to flag not-allocated)*/
}
- return sce->content_type;
}
+ else
+ buffer_clear(&sce->content_type);
- return NULL;
+ return &sce->content_type;
}
+#else
+
+const buffer * stat_cache_content_type_get_by_ext(stat_cache_entry *sce, const array *mimetypes)
+{
+ /*(invalid caching if user config has multiple, different
+ * con->conf.mimetypes for same extension (not expected))*/
+ if (!buffer_string_is_empty(&sce->content_type)) return &sce->content_type;
+
+ if (!S_ISREG(sce->st.st_mode)) return NULL;
+
+ /* cache mimetype */
+ const buffer * const mtype =
+ stat_cache_mimetype_by_ext(mimetypes, CONST_BUF_LEN(&sce->name));
+ if (NULL != mtype) {
+ /*(copy pointers from mimetypes array; avoid allocation)*/
+ sce->content_type.ptr = mtype->ptr;
+ sce->content_type.used = mtype->used;
+ /*(leave sce->content_type.size = 0 to flag not-allocated)*/
+ }
+ else
+ buffer_clear(&sce->content_type);
+
+ return &sce->content_type;
+}
+
+#endif
+
const buffer * stat_cache_etag_get(stat_cache_entry *sce, int flags) {
/*(invalid caching if user cfg has multiple, different con->conf.etag_flags
* for same path (not expected, since etag flags should be by filesystem))*/
- if (!buffer_string_is_empty(sce->etag)) return sce->etag;
+ if (!buffer_string_is_empty(&sce->etag)) return &sce->etag;
if (S_ISREG(sce->st.st_mode) || S_ISDIR(sce->st.st_mode)) {
- etag_create(sce->etag, &sce->st, flags);
- return sce->etag;
+ if (0 == flags) return NULL;
+ etag_create(&sce->etag, &sce->st, flags);
+ return &sce->etag;
}
return NULL;
}
-void stat_cache_update_entry(server *srv, const char *name, size_t len,
+void stat_cache_update_entry(const char *name, size_t len,
struct stat *st, buffer *etagb)
{
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_NONE) return;
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_NONE) return;
force_assert(0 != len);
if (name[len-1] == '/') { if (0 == --len) len = 1; }
- splay_tree **sptree = &srv->stat_cache->files;
+ splay_tree **sptree = &sc.files;
stat_cache_entry *sce =
stat_cache_sptree_find(sptree, name, len);
- if (sce && buffer_is_equal_string(sce->name, name, len)) {
+ if (sce && buffer_is_equal_string(&sce->name, name, len)) {
sce->stat_ts = log_epoch_secs;
sce->st = *st; /* etagb might be NULL to clear etag (invalidate) */
- buffer_copy_string_len(sce->etag, CONST_BUF_LEN(etagb));
+ buffer_copy_string_len(&sce->etag, CONST_BUF_LEN(etagb));
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
- buffer_clear(sce->content_type);
+ buffer_clear(&sce->content_type);
#endif
}
}
-void stat_cache_delete_entry(server *srv, const char *name, size_t len)
+void stat_cache_delete_entry(const char *name, size_t len)
{
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_NONE) return;
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_NONE) return;
force_assert(0 != len);
if (name[len-1] == '/') { if (0 == --len) len = 1; }
- splay_tree **sptree = &srv->stat_cache->files;
+ splay_tree **sptree = &sc.files;
stat_cache_entry *sce = stat_cache_sptree_find(sptree, name, len);
- if (sce && buffer_is_equal_string(sce->name, name, len)) {
+ if (sce && buffer_is_equal_string(&sce->name, name, len)) {
stat_cache_entry_free(sce);
*sptree = splaytree_delete(*sptree, (*sptree)->key);
}
}
-void stat_cache_invalidate_entry(server *srv, const char *name, size_t len)
+void stat_cache_invalidate_entry(const char *name, size_t len)
{
- splay_tree **sptree = &srv->stat_cache->files;
+ splay_tree **sptree = &sc.files;
stat_cache_entry *sce = stat_cache_sptree_find(sptree, name, len);
- if (sce && buffer_is_equal_string(sce->name, name, len)) {
+ if (sce && buffer_is_equal_string(&sce->name, name, len)) {
sce->stat_ts = 0;
#ifdef HAVE_FAM_H
if (sce->fam_dir != NULL) {
@@ -778,7 +822,7 @@ static void stat_cache_invalidate_dir_tree_walk(splay_tree *t,
if (t->left) stat_cache_invalidate_dir_tree_walk(t->left, name, len);
if (t->right) stat_cache_invalidate_dir_tree_walk(t->right, name, len);
- buffer *b = ((stat_cache_entry *)t->data)->name;
+ buffer *b = &((stat_cache_entry *)t->data)->name;
size_t blen = buffer_string_length(b);
if (blen > len && b->ptr[len] == '/' && 0 == memcmp(b->ptr, name, len)) {
stat_cache_entry *sce = t->data;
@@ -790,10 +834,9 @@ static void stat_cache_invalidate_dir_tree_walk(splay_tree *t,
}
}
-static void stat_cache_invalidate_dir_tree(server *srv,
- const char *name, size_t len)
+static void stat_cache_invalidate_dir_tree(const char *name, size_t len)
{
- splay_tree *sptree = srv->stat_cache->files;
+ splay_tree * const sptree = sc.files;
if (sptree) stat_cache_invalidate_dir_tree_walk(sptree, name, len);
}
@@ -812,51 +855,52 @@ static void stat_cache_tag_dir_tree(splay_tree *t, const char *name, size_t len,
if (t->right) stat_cache_tag_dir_tree(t->right, name, len, keys, ndx);
if (*ndx == 8192) return; /*(must match num array entries in keys[])*/
- buffer *b = ((stat_cache_entry *)t->data)->name;
+ buffer *b = &((stat_cache_entry *)t->data)->name;
size_t blen = buffer_string_length(b);
if (blen > len && b->ptr[len] == '/' && 0 == memcmp(b->ptr, name, len))
keys[(*ndx)++] = t->key;
}
-static void stat_cache_prune_dir_tree(stat_cache * const sc,
- const char *name, size_t len)
+static void stat_cache_prune_dir_tree(const char *name, size_t len)
{
int max_ndx, i;
int keys[8192]; /* 32k size on stack */
+ splay_tree *sptree = sc.files;
do {
- if (!sc->files) return;
+ if (!sptree) return;
max_ndx = 0;
- stat_cache_tag_dir_tree(sc->files, name, len, keys, &max_ndx);
+ stat_cache_tag_dir_tree(sptree, name, len, keys, &max_ndx);
for (i = 0; i < max_ndx; ++i) {
const int ndx = keys[i];
- splay_tree *node = sc->files = splaytree_splay(sc->files, ndx);
+ splay_tree *node = sptree = splaytree_splay(sptree, ndx);
if (node && node->key == ndx) {
stat_cache_entry_free(node->data);
- sc->files = splaytree_delete(sc->files, ndx);
+ sptree = splaytree_delete(sptree, ndx);
}
}
} while (max_ndx == sizeof(keys)/sizeof(int));
+ sc.files = sptree;
}
-static void stat_cache_delete_tree(server *srv, const char *name, size_t len)
+static void stat_cache_delete_tree(const char *name, size_t len)
{
- stat_cache_delete_entry(srv, name, len);
- stat_cache_prune_dir_tree(srv->stat_cache, name, len);
+ stat_cache_delete_entry(name, len);
+ stat_cache_prune_dir_tree(name, len);
}
-void stat_cache_delete_dir(server *srv, const char *name, size_t len)
+void stat_cache_delete_dir(const char *name, size_t len)
{
force_assert(0 != len);
if (name[len-1] == '/') { if (0 == --len) len = 1; }
- stat_cache_delete_tree(srv, name, len);
+ stat_cache_delete_tree(name, len);
#ifdef HAVE_FAM_H
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
- splay_tree **sptree = &srv->stat_cache->scf->dirs;
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
+ splay_tree **sptree = &sc.scf->dirs;
fam_dir_entry *fam_dir = stat_cache_sptree_find(sptree, name, len);
if (fam_dir && buffer_is_equal_string(fam_dir->name, name, len))
fam_dir_invalidate_node(fam_dir);
if (*sptree) fam_dir_invalidate_tree(*sptree, name, len);
- fam_dir_periodic_cleanup(srv);
+ fam_dir_periodic_cleanup();
}
#endif
}
@@ -870,14 +914,11 @@ void stat_cache_delete_dir(server *srv, const char *name, size_t len)
* - HANDLER_ERROR on stat() failed -> see errno for problem
*/
-handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry **ret_sce) {
+stat_cache_entry * stat_cache_get_entry(const buffer *name) {
stat_cache_entry *sce = NULL;
- stat_cache *sc;
struct stat st;
int file_ndx;
- *ret_sce = NULL;
-
/* consistency: ensure lookup name does not end in '/' unless root "/"
* (but use full path given with stat(), even with trailing '/') */
int final_slash = 0;
@@ -887,41 +928,37 @@ handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry *
/* Note: paths are expected to be normalized before calling stat_cache,
* e.g. without repeated '/' */
- if (name->ptr[0] != '/') return HANDLER_ERROR;
+ if (name->ptr[0] != '/') return NULL;
/*
* check if the directory for this file has changed
*/
- server * const srv = con->srv;
const time_t cur_ts = log_epoch_secs;
- sc = srv->stat_cache;
-
file_ndx = hashme(name->ptr, len);
- sc->files = splaytree_splay(sc->files, file_ndx);
+ splay_tree * const sptree = sc.files = splaytree_splay(sc.files, file_ndx);
- if (sc->files && (sc->files->key == file_ndx)) {
+ if (sptree && (sptree->key == file_ndx)) {
/* we have seen this file already and
* don't stat() it again in the same second */
- sce = sc->files->data;
+ sce = sptree->data;
/* check if the name is the same, we might have a collision */
- if (buffer_is_equal_string(sce->name, name->ptr, len)) {
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
+ if (buffer_is_equal_string(&sce->name, name->ptr, len)) {
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
if (sce->stat_ts == cur_ts) {
if (final_slash && !S_ISDIR(sce->st.st_mode)) {
errno = ENOTDIR;
- return HANDLER_ERROR;
+ return NULL;
}
- *ret_sce = sce;
- return HANDLER_GO_ON;
+ return sce;
}
}
#ifdef HAVE_FAM_H
- else if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM
+ else if (sc.stat_cache_engine == STAT_CACHE_ENGINE_FAM
&& sce->fam_dir) { /* entry is in monitored dir */
/* re-stat() periodically, even if monitoring for changes
* (due to limitations in stat_cache.c use of FAM)
@@ -929,10 +966,9 @@ handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry *
if (cur_ts - sce->stat_ts < 16) {
if (final_slash && !S_ISDIR(sce->st.st_mode)) {
errno = ENOTDIR;
- return HANDLER_ERROR;
+ return NULL;
}
- *ret_sce = sce;
- return HANDLER_GO_ON;
+ return sce;
}
}
#endif
@@ -943,36 +979,36 @@ handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry *
}
if (-1 == stat(name->ptr, &st)) {
- return HANDLER_ERROR;
+ return NULL;
}
if (S_ISREG(st.st_mode)) {
/* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */
if (name->ptr[buffer_string_length(name) - 1] == '/') {
errno = ENOTDIR;
- return HANDLER_ERROR;
+ return NULL;
}
}
if (NULL == sce) {
sce = stat_cache_entry_init();
- buffer_copy_string_len(sce->name, name->ptr, len);
+ buffer_copy_string_len(&sce->name, name->ptr, len);
/* already splayed file_ndx */
- if ((NULL != sc->files) && (sc->files->key == file_ndx)) {
+ if (NULL != sptree && sptree->key == file_ndx) {
/* hash collision: replace old entry */
- stat_cache_entry_free(sc->files->data);
- sc->files->data = sce;
+ stat_cache_entry_free(sptree->data);
+ sptree->data = sce;
} else {
- sc->files = splaytree_insert(sc->files, file_ndx, sce);
+ sc.files = splaytree_insert(sptree, file_ndx, sce);
}
} else {
- buffer_clear(sce->etag);
+ buffer_clear(&sce->etag);
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
- buffer_clear(sce->content_type);
+ buffer_clear(&sce->content_type);
#endif
}
@@ -980,10 +1016,10 @@ handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry *
sce->st = st; /*(copy prior to calling fam_dir_monitor())*/
#ifdef HAVE_FAM_H
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
+ if (sc.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
if (sce->fam_dir) --((fam_dir_entry *)sce->fam_dir)->refcnt;
sce->fam_dir =
- fam_dir_monitor(srv, sc->scf, CONST_BUF_LEN(name), &st);
+ fam_dir_monitor(sc.scf, CONST_BUF_LEN(name), &st);
#if 0 /*(performed below)*/
if (NULL != sce->fam_dir) {
/*(may have been invalidated by dir change)*/
@@ -994,12 +1030,10 @@ handler_t stat_cache_get_entry(connection *con, buffer *name, stat_cache_entry *
#endif
sce->stat_ts = cur_ts;
- *ret_sce = sce;
-
- return HANDLER_GO_ON;
+ return sce;
}
-int stat_cache_path_contains_symlink(connection *con, const buffer *name) {
+int stat_cache_path_contains_symlink(const buffer *name, log_error_st *errh) {
/* caller should check for symlinks only if we should block symlinks. */
/* catch the obvious symlinks
@@ -1035,8 +1069,7 @@ int stat_cache_path_contains_symlink(connection *con, const buffer *name) {
if (S_ISLNK(st.st_mode)) return 1;
}
else {
- log_perror(con->conf.errh, __FILE__, __LINE__,
- "lstat failed for: %s", buf);
+ log_perror(errh, __FILE__, __LINE__, "lstat failed for: %s", buf);
return -1;
}
} while ((s_cur = strrchr(buf, '/')) != buf);
@@ -1068,7 +1101,7 @@ int stat_cache_open_rdonly_fstat (const buffer *name, struct stat *st, int symli
* and remove them in a second loop
*/
-static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, size_t * const ndx, const time_t max_age, const time_t cur_ts) {
+static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, uint32_t * const ndx, const time_t max_age, const time_t cur_ts) {
if (!t) return;
stat_cache_tag_old_entries(t->left, keys, ndx, max_age, cur_ts);
@@ -1081,43 +1114,39 @@ static void stat_cache_tag_old_entries(splay_tree * const t, int * const keys, s
}
}
-static void stat_cache_periodic_cleanup(stat_cache * const sc, const time_t max_age, const time_t cur_ts) {
- size_t max_ndx = 0, i;
- int *keys;
-
- if (!sc->files) return;
+static void stat_cache_periodic_cleanup(const time_t max_age, const time_t cur_ts) {
+ splay_tree *sptree = sc.files;
+ if (!sptree) return;
- keys = calloc(1, sizeof(int) * sc->files->size);
+ int * const keys = calloc(1, sizeof(int) * sptree->size);
force_assert(NULL != keys);
- stat_cache_tag_old_entries(sc->files, keys, &max_ndx, max_age, cur_ts);
+ uint32_t max_ndx = 0;
+ stat_cache_tag_old_entries(sptree, keys, &max_ndx, max_age, cur_ts);
- for (i = 0; i < max_ndx; i++) {
+ for (uint32_t i = 0; i < max_ndx; ++i) {
int ndx = keys[i];
- splay_tree *node;
-
- sc->files = splaytree_splay(sc->files, ndx);
-
- node = sc->files;
-
- if (node && (node->key == ndx)) {
- stat_cache_entry_free(node->data);
- sc->files = splaytree_delete(sc->files, ndx);
+ sptree = splaytree_splay(sptree, ndx);
+ if (sptree && sptree->key == ndx) {
+ stat_cache_entry_free(sptree->data);
+ sptree = splaytree_delete(sptree, ndx);
}
}
+ sc.files = sptree;
+
free(keys);
}
-int stat_cache_trigger_cleanup(server *srv) {
+void stat_cache_trigger_cleanup(void) {
time_t max_age = 2;
#ifdef HAVE_FAM_H
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
- if (log_epoch_secs & 0x1F) return 0;
+ if (STAT_CACHE_ENGINE_FAM == sc.stat_cache_engine) {
+ if (log_epoch_secs & 0x1F) return;
/* once every 32 seconds (0x1F == 31) */
max_age = 32;
- fam_dir_periodic_cleanup(srv);
+ fam_dir_periodic_cleanup();
/* By doing this before stat_cache_periodic_cleanup(),
* entries used within the next max_age secs will remain
* monitored, instead of effectively flushing and
@@ -1125,7 +1154,5 @@ int stat_cache_trigger_cleanup(server *srv) {
}
#endif
- stat_cache_periodic_cleanup(srv->stat_cache, max_age, log_epoch_secs);
-
- return 0;
+ stat_cache_periodic_cleanup(max_age, log_epoch_secs);
}