diff --git a/src/stat_cache.c b/src/stat_cache.c index d30a80f1..056c3a14 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -533,6 +533,7 @@ static stat_cache_entry * stat_cache_entry_init(void) { stat_cache_entry *sce = calloc(1, sizeof(*sce)); force_assert(NULL != sce); sce->fd = -1; + sce->refcnt = 1; return sce; } @@ -540,6 +541,8 @@ static void stat_cache_entry_free(void *data) { stat_cache_entry *sce = data; if (!sce) return; + if (--sce->refcnt) return; + #ifdef HAVE_FAM_H /*(decrement refcnt only; * defer cancelling FAM monitor on dir even if refcnt reaches zero)*/ @@ -554,6 +557,15 @@ static void stat_cache_entry_free(void *data) { free(sce); } +void stat_cache_entry_refchg(void *data, int mod) { + /*(expect mod == -1 or mod == 1)*/ + stat_cache_entry * const sce = data; + if (mod < 0 && 1 == sce->refcnt) + stat_cache_entry_free(data); + else + sce->refcnt += mod; +} + #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) static const char *attrname = "Content-Type"; @@ -813,8 +825,15 @@ void stat_cache_update_entry(const char *name, uint32_t len, buffer_clear(&sce->content_type); #endif if (sce->fd >= 0) { - close(sce->fd); - sce->fd = -1; + if (1 == sce->refcnt) { + close(sce->fd); + sce->fd = -1; + } + else { + --sce->refcnt; /* stat_cache_entry_free(sce); */ + (*sptree)->data = sce = stat_cache_entry_init(); + buffer_copy_string_len(&sce->name, name, len); + } } sce->st = *st; } @@ -1056,8 +1075,15 @@ stat_cache_entry * stat_cache_get_entry(const buffer *name) { if (sce->fd >= 0) { /* close fd if file changed */ if (!stat_cache_stat_eq(&sce->st, &st)) { - close(sce->fd); - sce->fd = -1; + if (1 == sce->refcnt) { + close(sce->fd); + sce->fd = -1; + } + else { + --sce->refcnt; /* stat_cache_entry_free(sce); */ + sptree->data = sce = stat_cache_entry_init(); + buffer_copy_string_len(&sce->name, name->ptr, len); + } } } diff --git a/src/stat_cache.h b/src/stat_cache.h index 6f4bd1bd..5a2b11e3 100644 --- a/src/stat_cache.h +++ b/src/stat_cache.h @@ -12,10 +12,11 @@ typedef struct stat stat_cache_st; -typedef struct { +typedef struct stat_cache_entry { buffer name; time_t stat_ts; int fd; + int refcnt; #ifdef HAVE_FAM_H void *fam_dir; #endif @@ -35,6 +36,8 @@ int stat_cache_init(struct fdevents *ev, log_error_st *errh); __attribute_cold__ void stat_cache_free(void); +void stat_cache_entry_refchg(void *data, int mod); + __attribute_cold__ void stat_cache_xattrname (const char *name);