|
version 1.1, 2013/10/14 10:32:48
|
version 1.1.1.3, 2016/11/02 10:35:00
|
|
Line 1
|
Line 1
|
| |
#include "first.h" |
| |
|
| #include "log.h" |
#include "log.h" |
| #include "stat_cache.h" |
#include "stat_cache.h" |
| #include "fdevent.h" |
#include "fdevent.h" |
|
Line 18
|
Line 20
|
| # include <attr/attributes.h> |
# include <attr/attributes.h> |
| #endif |
#endif |
| |
|
| |
#ifdef HAVE_SYS_EXTATTR_H |
| |
# include <sys/extattr.h> |
| |
#endif |
| |
|
| #ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
| # include <fam.h> |
# include <fam.h> |
| #endif |
#endif |
|
Line 69
|
Line 75
|
| #ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
| typedef struct { |
typedef struct { |
| FAMRequest *req; |
FAMRequest *req; |
| FAMConnection *fc; |
|
| |
|
| buffer *name; |
buffer *name; |
| |
|
|
Line 102 static fake_keys ctrl;
|
Line 107 static fake_keys ctrl;
|
| #endif |
#endif |
| |
|
| stat_cache *stat_cache_init(void) { |
stat_cache *stat_cache_init(void) { |
| stat_cache *fc = NULL; | stat_cache *sc = NULL; |
| |
|
| fc = calloc(1, sizeof(*fc)); | sc = calloc(1, sizeof(*sc)); |
| | force_assert(NULL != sc); |
| |
|
| fc->dir_name = buffer_init(); | sc->dir_name = buffer_init(); |
| fc->hash_key = buffer_init(); | sc->hash_key = buffer_init(); |
| | |
| #ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
| fc->fam = calloc(1, sizeof(*fc->fam)); | sc->fam_fcce_ndx = -1; |
| #endif |
#endif |
| |
|
| #ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
| ctrl.size = 0; |
ctrl.size = 0; |
| #endif |
#endif |
| |
|
| return fc; | return sc; |
| } |
} |
| |
|
| static stat_cache_entry * stat_cache_entry_init(void) { |
static stat_cache_entry * stat_cache_entry_init(void) { |
| stat_cache_entry *sce = NULL; |
stat_cache_entry *sce = NULL; |
| |
|
| sce = calloc(1, sizeof(*sce)); |
sce = calloc(1, sizeof(*sce)); |
| |
force_assert(NULL != sce); |
| |
|
| sce->name = buffer_init(); |
sce->name = buffer_init(); |
| sce->etag = buffer_init(); |
sce->etag = buffer_init(); |
|
Line 147 static fam_dir_entry * fam_dir_entry_init(void) {
|
Line 155 static fam_dir_entry * fam_dir_entry_init(void) {
|
| fam_dir_entry *fam_dir = NULL; |
fam_dir_entry *fam_dir = NULL; |
| |
|
| fam_dir = calloc(1, sizeof(*fam_dir)); |
fam_dir = calloc(1, sizeof(*fam_dir)); |
| |
force_assert(NULL != fam_dir); |
| |
|
| fam_dir->name = buffer_init(); |
fam_dir->name = buffer_init(); |
| |
|
| return fam_dir; |
return fam_dir; |
| } |
} |
| |
|
| static void fam_dir_entry_free(void *data) { | static void fam_dir_entry_free(FAMConnection *fc, void *data) { |
| fam_dir_entry *fam_dir = data; |
fam_dir_entry *fam_dir = data; |
| |
|
| if (!fam_dir) return; |
if (!fam_dir) return; |
| |
|
| FAMCancelMonitor(fam_dir->fc, fam_dir->req); | FAMCancelMonitor(fc, fam_dir->req); |
| |
|
| buffer_free(fam_dir->name); |
buffer_free(fam_dir->name); |
| free(fam_dir->req); |
free(fam_dir->req); |
|
Line 177 void stat_cache_free(stat_cache *sc) {
|
Line 186 void stat_cache_free(stat_cache *sc) {
|
| stat_cache_entry_free(node->data); |
stat_cache_entry_free(node->data); |
| sc->files = splaytree_delete(sc->files, node->key); |
sc->files = splaytree_delete(sc->files, node->key); |
| |
|
| assert(osize - 1 == splaytree_size(sc->files)); | force_assert(osize - 1 == splaytree_size(sc->files)); |
| } |
} |
| |
|
| buffer_free(sc->dir_name); |
buffer_free(sc->dir_name); |
|
Line 190 void stat_cache_free(stat_cache *sc) {
|
Line 199 void stat_cache_free(stat_cache *sc) {
|
| |
|
| osize = sc->dirs->size; |
osize = sc->dirs->size; |
| |
|
| fam_dir_entry_free(node->data); | fam_dir_entry_free(&sc->fam, node->data); |
| sc->dirs = splaytree_delete(sc->dirs, node->key); |
sc->dirs = splaytree_delete(sc->dirs, node->key); |
| |
|
| if (osize == 1) { |
if (osize == 1) { |
| assert(NULL == sc->dirs); | force_assert(NULL == sc->dirs); |
| } else { |
} else { |
| assert(osize == (sc->dirs->size + 1)); | force_assert(osize == (sc->dirs->size + 1)); |
| } |
} |
| } |
} |
| |
|
| if (sc->fam) { | if (-1 != sc->fam_fcce_ndx) { |
| FAMClose(sc->fam); | /* fd events already gone */ |
| free(sc->fam); | sc->fam_fcce_ndx = -1; |
| | |
| | FAMClose(&sc->fam); |
| } |
} |
| #endif |
#endif |
| free(sc); |
free(sc); |
| } |
} |
| |
|
| #ifdef HAVE_XATTR | #if defined(HAVE_XATTR) |
| static int stat_cache_attr_get(buffer *buf, char *name) { | static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) { |
| int attrlen; |
int attrlen; |
| int ret; |
int ret; |
| |
|
| attrlen = 1024; | buffer_string_prepare_copy(buf, 1023); |
| buffer_prepare_copy(buf, attrlen); | attrlen = buf->size - 1; |
| attrlen--; | if(0 == (ret = attr_get(name, xattrname, buf->ptr, &attrlen, 0))) { |
| if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) { | buffer_commit(buf, attrlen); |
| | } |
| | return ret; |
| | } |
| | #elif defined(HAVE_EXTATTR) |
| | static int stat_cache_attr_get(buffer *buf, char *name, 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->used = attrlen + 1; |
| buf->ptr[attrlen] = '\0'; |
buf->ptr[attrlen] = '\0'; |
| |
return 0; |
| } |
} |
| return ret; | return -1; |
| } |
} |
| #endif |
#endif |
| |
|
|
Line 232 static uint32_t hashme(buffer *str) {
|
Line 254 static uint32_t hashme(buffer *str) {
|
| hash = ((hash << 5) + hash) + *s; |
hash = ((hash << 5) + hash) + *s; |
| } |
} |
| |
|
| hash &= ~(1 << 31); /* strip the highest bit */ | hash &= ~(((uint32_t)1) << 31); /* strip the highest bit */ |
| |
|
| return hash; |
return hash; |
| } |
} |
|
Line 246 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 268 handler_t stat_cache_handle_fdevent(server *srv, void
|
| UNUSED(_fce); |
UNUSED(_fce); |
| /* */ |
/* */ |
| |
|
| if ((revent & FDEVENT_IN) && | if (revent & FDEVENT_IN) { |
| sc->fam) { | events = FAMPending(&sc->fam); |
| |
|
| events = FAMPending(sc->fam); |
|
| |
|
| for (i = 0; i < events; i++) { |
for (i = 0; i < events; i++) { |
| FAMEvent fe; |
FAMEvent fe; |
| fam_dir_entry *fam_dir; |
fam_dir_entry *fam_dir; |
| splay_tree *node; |
splay_tree *node; |
| int ndx, j; |
int ndx, j; |
| |
|
| FAMNextEvent(sc->fam, &fe); | FAMNextEvent(&sc->fam, &fe); |
| |
|
| /* handle event */ |
/* handle event */ |
| |
|
|
Line 277 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 297 handler_t stat_cache_handle_fdevent(server *srv, void
|
| |
|
| for (j = 0; j < 2; j++) { |
for (j = 0; j < 2; j++) { |
| buffer_copy_string(sc->hash_key, fe.filename); |
buffer_copy_string(sc->hash_key, fe.filename); |
| buffer_append_long(sc->hash_key, j); | buffer_append_int(sc->hash_key, j); |
| |
|
| ndx = hashme(sc->hash_key); |
ndx = hashme(sc->hash_key); |
| |
|
|
Line 287 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 307 handler_t stat_cache_handle_fdevent(server *srv, void
|
| if (node && (node->key == ndx)) { |
if (node && (node->key == ndx)) { |
| int osize = splaytree_size(sc->dirs); |
int osize = splaytree_size(sc->dirs); |
| |
|
| fam_dir_entry_free(node->data); | fam_dir_entry_free(&sc->fam, node->data); |
| sc->dirs = splaytree_delete(sc->dirs, ndx); |
sc->dirs = splaytree_delete(sc->dirs, ndx); |
| |
|
| assert(osize - 1 == splaytree_size(sc->dirs)); | force_assert(osize - 1 == splaytree_size(sc->dirs)); |
| } |
} |
| } |
} |
| break; |
break; |
|
Line 302 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 322 handler_t stat_cache_handle_fdevent(server *srv, void
|
| |
|
| if (revent & FDEVENT_HUP) { |
if (revent & FDEVENT_HUP) { |
| /* fam closed the connection */ |
/* fam closed the connection */ |
| srv->stat_cache->fam_fcce_ndx = -1; | fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(&sc->fam)); |
| | fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(&sc->fam)); |
| |
|
| fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam)); | FAMClose(&sc->fam); |
| fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam)); | |
| |
| FAMClose(sc->fam); | |
| free(sc->fam); | |
| |
| sc->fam = NULL; | |
| } |
} |
| |
|
| return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
|
Line 319 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 334 handler_t stat_cache_handle_fdevent(server *srv, void
|
| static int buffer_copy_dirname(buffer *dst, buffer *file) { |
static int buffer_copy_dirname(buffer *dst, buffer *file) { |
| size_t i; |
size_t i; |
| |
|
| if (buffer_is_empty(file)) return -1; | if (buffer_string_is_empty(file)) return -1; |
| |
|
| for (i = file->used - 1; i+1 > 0; i--) { | for (i = buffer_string_length(file); i > 0; i--) { |
| if (file->ptr[i] == '/') { |
if (file->ptr[i] == '/') { |
| buffer_copy_string_len(dst, file->ptr, i); |
buffer_copy_string_len(dst, file->ptr, i); |
| return 0; |
return 0; |
|
Line 359 handler_t stat_cache_get_entry(server *srv, connection
|
Line 374 handler_t stat_cache_get_entry(server *srv, connection
|
| #ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
| fam_dir_entry *fam_dir = NULL; |
fam_dir_entry *fam_dir = NULL; |
| int dir_ndx = -1; |
int dir_ndx = -1; |
| splay_tree *dir_node = NULL; |
|
| #endif |
#endif |
| stat_cache_entry *sce = NULL; |
stat_cache_entry *sce = NULL; |
| stat_cache *sc; |
stat_cache *sc; |
|
Line 372 handler_t stat_cache_get_entry(server *srv, connection
|
Line 386 handler_t stat_cache_get_entry(server *srv, connection
|
| #endif |
#endif |
| |
|
| int file_ndx; |
int file_ndx; |
| splay_tree *file_node = NULL; |
|
| |
|
| *ret_sce = NULL; |
*ret_sce = NULL; |
| |
|
|
Line 382 handler_t stat_cache_get_entry(server *srv, connection
|
Line 395 handler_t stat_cache_get_entry(server *srv, connection
|
| |
|
| sc = srv->stat_cache; |
sc = srv->stat_cache; |
| |
|
| buffer_copy_string_buffer(sc->hash_key, name); | buffer_copy_buffer(sc->hash_key, name); |
| buffer_append_long(sc->hash_key, con->conf.follow_symlink); | buffer_append_int(sc->hash_key, con->conf.follow_symlink); |
| |
|
| file_ndx = hashme(sc->hash_key); |
file_ndx = hashme(sc->hash_key); |
| sc->files = splaytree_splay(sc->files, file_ndx); |
sc->files = splaytree_splay(sc->files, file_ndx); |
|
Line 397 handler_t stat_cache_get_entry(server *srv, connection
|
Line 410 handler_t stat_cache_get_entry(server *srv, connection
|
| if (sc->files && (sc->files->key == file_ndx)) { |
if (sc->files && (sc->files->key == file_ndx)) { |
| #ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
| /* it was in the cache */ |
/* it was in the cache */ |
| assert(i < ctrl.used); | force_assert(i < ctrl.used); |
| #endif |
#endif |
| |
|
| /* we have seen this file already and |
/* we have seen this file already and |
| * don't stat() it again in the same second */ |
* don't stat() it again in the same second */ |
| |
|
| file_node = sc->files; | sce = sc->files->data; |
| |
|
| sce = file_node->data; |
|
| |
|
| /* check if the name is the same, we might have a collision */ |
/* check if the name is the same, we might have a collision */ |
| |
|
| if (buffer_is_equal(name, sce->name)) { |
if (buffer_is_equal(name, sce->name)) { |
| if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { |
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { |
| if (sce->stat_ts == srv->cur_ts) { | if (sce->stat_ts == srv->cur_ts && con->conf.follow_symlink) { |
| *ret_sce = sce; |
*ret_sce = sce; |
| return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
| } |
} |
| } |
} |
| } else { |
} else { |
| /* oops, a collision, | /* collision, forget about the entry */ |
| * | sce = NULL; |
| * file_node is used by the FAM check below to see if we know this file | |
| * and if we can save a stat(). | |
| * | |
| * BUT, the sce is not reset here as the entry into the cache is ok, we | |
| * it is just not pointing to our requested file. | |
| * | |
| * */ | |
| |
| file_node = NULL; | |
| } |
} |
| } else { |
} else { |
| #ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
|
Line 435 handler_t stat_cache_get_entry(server *srv, connection
|
Line 437 handler_t stat_cache_get_entry(server *srv, connection
|
| log_error_write(srv, __FILE__, __LINE__, "xSB", |
log_error_write(srv, __FILE__, __LINE__, "xSB", |
| file_ndx, "was already inserted but not found in cache, ", name); |
file_ndx, "was already inserted but not found in cache, ", name); |
| } |
} |
| assert(i == ctrl.used); | force_assert(i == ctrl.used); |
| #endif |
#endif |
| } |
} |
| |
|
|
Line 448 handler_t stat_cache_get_entry(server *srv, connection
|
Line 450 handler_t stat_cache_get_entry(server *srv, connection
|
| return HANDLER_ERROR; |
return HANDLER_ERROR; |
| } |
} |
| |
|
| buffer_copy_string_buffer(sc->hash_key, sc->dir_name); | buffer_copy_buffer(sc->hash_key, sc->dir_name); |
| buffer_append_long(sc->hash_key, con->conf.follow_symlink); | buffer_append_int(sc->hash_key, con->conf.follow_symlink); |
| |
|
| dir_ndx = hashme(sc->hash_key); |
dir_ndx = hashme(sc->hash_key); |
| |
|
| sc->dirs = splaytree_splay(sc->dirs, dir_ndx); |
sc->dirs = splaytree_splay(sc->dirs, dir_ndx); |
| |
|
| if (sc->dirs && (sc->dirs->key == dir_ndx)) { | if ((NULL != sc->dirs) && (sc->dirs->key == dir_ndx)) { |
| dir_node = sc->dirs; | fam_dir = sc->dirs->data; |
| } | |
| |
|
| if (dir_node && file_node) { | /* check whether we got a collision */ |
| /* we found a file */ | if (buffer_is_equal(sc->dir_name, fam_dir->name)) { |
| | /* test whether a found file cache entry is still ok */ |
| | if ((NULL != sce) && (fam_dir->version == sce->dir_version)) { |
| | /* the stat()-cache entry is still ok */ |
| |
|
| sce = file_node->data; | *ret_sce = sce; |
| fam_dir = dir_node->data; | return HANDLER_GO_ON; |
| } |
| if (fam_dir->version == sce->dir_version) { | } else { |
| /* the stat()-cache entry is still ok */ | /* hash collision, forget about the entry */ |
| fam_dir = NULL; |
| *ret_sce = sce; | |
| return HANDLER_GO_ON; | |
| } |
} |
| } |
} |
| } |
} |
|
Line 488 handler_t stat_cache_get_entry(server *srv, connection
|
Line 490 handler_t stat_cache_get_entry(server *srv, connection
|
| |
|
| if (S_ISREG(st.st_mode)) { |
if (S_ISREG(st.st_mode)) { |
| /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ |
/* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ |
| if (name->ptr[name->used-2] == '/') { | if (name->ptr[buffer_string_length(name) - 1] == '/') { |
| errno = ENOTDIR; |
errno = ENOTDIR; |
| return HANDLER_ERROR; |
return HANDLER_ERROR; |
| } |
} |
|
Line 501 handler_t stat_cache_get_entry(server *srv, connection
|
Line 503 handler_t stat_cache_get_entry(server *srv, connection
|
| } |
} |
| |
|
| if (NULL == sce) { |
if (NULL == sce) { |
| #ifdef DEBUG_STAT_CACHE |
|
| int osize = splaytree_size(sc->files); |
|
| #endif |
|
| |
|
| sce = stat_cache_entry_init(); |
sce = stat_cache_entry_init(); |
| buffer_copy_string_buffer(sce->name, name); | buffer_copy_buffer(sce->name, name); |
| |
|
| sc->files = splaytree_insert(sc->files, file_ndx, sce); | /* already splayed file_ndx */ |
| #ifdef DEBUG_STAT_CACHE | if ((NULL != sc->files) && (sc->files->key == file_ndx)) { |
| if (ctrl.size == 0) { | /* hash collision: replace old entry */ |
| ctrl.size = 16; | stat_cache_entry_free(sc->files->data); |
| ctrl.used = 0; | sc->files->data = sce; |
| ctrl.ptr = malloc(ctrl.size * sizeof(*ctrl.ptr)); | } else { |
| } else if (ctrl.size == ctrl.used) { | int osize = splaytree_size(sc->files); |
| ctrl.size += 16; | |
| ctrl.ptr = realloc(ctrl.ptr, ctrl.size * sizeof(*ctrl.ptr)); | |
| } | |
| |
|
| ctrl.ptr[ctrl.used++] = file_ndx; | sc->files = splaytree_insert(sc->files, file_ndx, sce); |
| | force_assert(osize + 1 == splaytree_size(sc->files)); |
| |
|
| assert(sc->files); | #ifdef DEBUG_STAT_CACHE |
| assert(sc->files->data == sce); | if (ctrl.size == 0) { |
| assert(osize + 1 == splaytree_size(sc->files)); | ctrl.size = 16; |
| | ctrl.used = 0; |
| | ctrl.ptr = malloc(ctrl.size * sizeof(*ctrl.ptr)); |
| | force_assert(NULL != ctrl.ptr); |
| | } else if (ctrl.size == ctrl.used) { |
| | ctrl.size += 16; |
| | ctrl.ptr = realloc(ctrl.ptr, ctrl.size * sizeof(*ctrl.ptr)); |
| | force_assert(NULL != ctrl.ptr); |
| | } |
| | |
| | ctrl.ptr[ctrl.used++] = file_ndx; |
| #endif |
#endif |
| |
} |
| |
force_assert(sc->files); |
| |
force_assert(sc->files->data == sce); |
| } |
} |
| |
|
| sce->st = st; |
sce->st = st; |
|
Line 560 handler_t stat_cache_get_entry(server *srv, connection
|
Line 570 handler_t stat_cache_get_entry(server *srv, connection
|
| * we assume "/" can not be symlink, so |
* we assume "/" can not be symlink, so |
| * skip the symlink stuff if our path is / |
* skip the symlink stuff if our path is / |
| **/ |
**/ |
| else if ((name->used > 2)) { | else if (buffer_string_length(name) > 1) { |
| buffer *dname; |
buffer *dname; |
| char *s_cur; |
char *s_cur; |
| |
|
| dname = buffer_init(); |
dname = buffer_init(); |
| buffer_copy_string_buffer(dname, name); | buffer_copy_buffer(dname, name); |
| |
|
| while ((s_cur = strrchr(dname->ptr,'/'))) { | while ((s_cur = strrchr(dname->ptr, '/'))) { |
| *s_cur = '\0'; | buffer_string_set_length(dname, s_cur - dname->ptr); |
| dname->used = s_cur - dname->ptr + 1; | |
| if (dname->ptr == s_cur) { |
if (dname->ptr == s_cur) { |
| #ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
| log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); |
log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); |
|
Line 597 handler_t stat_cache_get_entry(server *srv, connection
|
Line 606 handler_t stat_cache_get_entry(server *srv, connection
|
| if (S_ISREG(st.st_mode)) { |
if (S_ISREG(st.st_mode)) { |
| /* determine mimetype */ |
/* determine mimetype */ |
| buffer_reset(sce->content_type); |
buffer_reset(sce->content_type); |
| #ifdef HAVE_XATTR | #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) |
| if (con->conf.use_xattr) { |
if (con->conf.use_xattr) { |
| stat_cache_attr_get(sce->content_type, name->ptr); | stat_cache_attr_get(sce->content_type, name->ptr, srv->srvconf.xattr_name->ptr); |
| } |
} |
| #endif |
#endif |
| /* xattr did not set a content-type. ask the config */ |
/* xattr did not set a content-type. ask the config */ |
| if (buffer_is_empty(sce->content_type)) { | if (buffer_string_is_empty(sce->content_type)) { |
| | size_t namelen = buffer_string_length(name); |
| | |
| for (k = 0; k < con->conf.mimetypes->used; k++) { |
for (k = 0; k < con->conf.mimetypes->used; k++) { |
| data_string *ds = (data_string *)con->conf.mimetypes->data[k]; |
data_string *ds = (data_string *)con->conf.mimetypes->data[k]; |
| buffer *type = ds->key; |
buffer *type = ds->key; |
| |
size_t typelen = buffer_string_length(type); |
| |
|
| if (type->used == 0) continue; | if (buffer_is_empty(type)) continue; |
| |
|
| /* check if the right side is the same */ |
/* check if the right side is the same */ |
| if (type->used > name->used) continue; | if (typelen > namelen) continue; |
| |
|
| if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) { | if (0 == strncasecmp(name->ptr + namelen - typelen, type->ptr, typelen)) { |
| buffer_copy_string_buffer(sce->content_type, ds->value); | buffer_copy_buffer(sce->content_type, ds->value); |
| break; |
break; |
| } |
} |
| } |
} |
|
Line 625 handler_t stat_cache_get_entry(server *srv, connection
|
Line 637 handler_t stat_cache_get_entry(server *srv, connection
|
| } |
} |
| |
|
| #ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
| if (sc->fam && | if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { |
| (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) { | |
| /* is this directory already registered ? */ |
/* is this directory already registered ? */ |
| if (!dir_node) { | if (NULL == fam_dir) { |
| fam_dir = fam_dir_entry_init(); |
fam_dir = fam_dir_entry_init(); |
| fam_dir->fc = sc->fam; |
|
| |
|
| buffer_copy_string_buffer(fam_dir->name, sc->dir_name); | buffer_copy_buffer(fam_dir->name, sc->dir_name); |
| |
|
| fam_dir->version = 1; |
fam_dir->version = 1; |
| |
|
| fam_dir->req = calloc(1, sizeof(FAMRequest)); |
fam_dir->req = calloc(1, sizeof(FAMRequest)); |
| |
force_assert(NULL != fam_dir); |
| |
|
| if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, | if (0 != FAMMonitorDirectory(&sc->fam, fam_dir->name->ptr, |
| fam_dir->req, fam_dir)) { |
fam_dir->req, fam_dir)) { |
| |
|
| log_error_write(srv, __FILE__, __LINE__, "sbsbs", |
log_error_write(srv, __FILE__, __LINE__, "sbsbs", |
|
Line 647 handler_t stat_cache_get_entry(server *srv, connection
|
Line 658 handler_t stat_cache_get_entry(server *srv, connection
|
| "file:", name, |
"file:", name, |
| FamErrlist[FAMErrno]); |
FamErrlist[FAMErrno]); |
| |
|
| fam_dir_entry_free(fam_dir); | fam_dir_entry_free(&sc->fam, fam_dir); |
| | fam_dir = NULL; |
| } else { |
} else { |
| int osize = 0; | int osize = splaytree_size(sc->dirs); |
| |
|
| if (sc->dirs) { | /* already splayed dir_ndx */ |
| osize = sc->dirs->size; | if ((NULL != sc->dirs) && (sc->dirs->key == dir_ndx)) { |
| | /* hash collision: replace old entry */ |
| | fam_dir_entry_free(&sc->fam, sc->dirs->data); |
| | sc->dirs->data = fam_dir; |
| | } else { |
| | sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); |
| | force_assert(osize == (splaytree_size(sc->dirs) - 1)); |
| } |
} |
| |
|
| sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); | force_assert(sc->dirs); |
| assert(sc->dirs); | force_assert(sc->dirs->data == fam_dir); |
| assert(sc->dirs->data == fam_dir); | |
| assert(osize == (sc->dirs->size - 1)); | |
| } |
} |
| } else { |
|
| fam_dir = dir_node->data; |
|
| } |
} |
| |
|
| /* bind the fam_fc to the stat() cache entry */ |
/* bind the fam_fc to the stat() cache entry */ |
| |
|
| if (fam_dir) { |
if (fam_dir) { |
| sce->dir_version = fam_dir->version; |
sce->dir_version = fam_dir->version; |
| sce->dir_ndx = dir_ndx; |
|
| } |
} |
| } |
} |
| #endif |
#endif |
|
Line 678 handler_t stat_cache_get_entry(server *srv, connection
|
Line 691 handler_t stat_cache_get_entry(server *srv, connection
|
| return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
| } |
} |
| |
|
| |
int stat_cache_open_rdonly_fstat (server *srv, connection *con, buffer *name, struct stat *st) { |
| |
/*(Note: O_NOFOLLOW affects only the final path segment, the target file, |
| |
* not any intermediate symlinks along the path)*/ |
| |
#ifndef O_BINARY |
| |
#define O_BINARY 0 |
| |
#endif |
| |
#ifndef O_LARGEFILE |
| |
#define O_LARGEFILE 0 |
| |
#endif |
| |
#ifndef O_NOCTTY |
| |
#define O_NOCTTY 0 |
| |
#endif |
| |
#ifndef O_NONBLOCK |
| |
#define O_NONBLOCK 0 |
| |
#endif |
| |
#ifndef O_NOFOLLOW |
| |
#define O_NOFOLLOW 0 |
| |
#endif |
| |
const int oflags = O_BINARY | O_LARGEFILE | O_NOCTTY | O_NONBLOCK |
| |
| (con->conf.follow_symlink ? 0 : O_NOFOLLOW); |
| |
const int fd = open(name->ptr, O_RDONLY | oflags); |
| |
if (fd >= 0) { |
| |
if (0 == fstat(fd, st)) { |
| |
return fd; |
| |
} else { |
| |
close(fd); |
| |
} |
| |
} |
| |
UNUSED(srv); /*(might log_error_write(srv, ...) in the future)*/ |
| |
return -1; |
| |
} |
| |
|
| /** |
/** |
| * remove stat() from cache which havn't been stat()ed for |
* remove stat() from cache which havn't been stat()ed for |
| * more than 10 seconds |
* more than 10 seconds |
|
Line 713 int stat_cache_trigger_cleanup(server *srv) {
|
Line 758 int stat_cache_trigger_cleanup(server *srv) {
|
| |
|
| if (!sc->files) return 0; |
if (!sc->files) return 0; |
| |
|
| keys = calloc(1, sizeof(size_t) * sc->files->size); | keys = calloc(1, sizeof(int) * sc->files->size); |
| | force_assert(NULL != keys); |
| |
|
| stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx); |
stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx); |
| |
|
|
Line 742 int stat_cache_trigger_cleanup(server *srv) {
|
Line 788 int stat_cache_trigger_cleanup(server *srv) {
|
| } |
} |
| } |
} |
| |
|
| assert(osize - 1 == splaytree_size(sc->files)); | force_assert(osize - 1 == splaytree_size(sc->files)); |
| #endif |
#endif |
| } |
} |
| } |
} |