[core] stat_cache_get_entry_open()

simple interface to cache open file by extending struct stat_cache_entry

future: should probably create fd cache separate from stat_cache,
        perhaps along w/ http-specific fields like etag and content_type
master
Glenn Strauss 2 years ago
parent e99126074c
commit d8e5e21eb7

@ -532,6 +532,7 @@ static fam_dir_entry * fam_dir_monitor(stat_cache_fam *scf, char *fn, uint32_t d
static stat_cache_entry * stat_cache_entry_init(void) {
stat_cache_entry *sce = calloc(1, sizeof(*sce));
force_assert(NULL != sce);
sce->fd = -1;
return sce;
}
@ -548,6 +549,7 @@ static void stat_cache_entry_free(void *data) {
free(sce->name.ptr);
free(sce->etag.ptr);
if (sce->content_type.size) free(sce->content_type.ptr);
if (sce->fd >= 0) close(sce->fd);
free(sce);
}
@ -778,6 +780,22 @@ const buffer * stat_cache_etag_get(stat_cache_entry *sce, int flags) {
return NULL;
}
__attribute_pure__
static int stat_cache_stat_eq(const struct stat * const sta, const struct stat * const stb) {
return
#ifdef st_mtime /* use high-precision timestamp if available */
#if defined(__APPLE__) && defined(__MACH__)
sta->st_mtimespec.tv_nsec == stb->st_mtimespec.tv_nsec
#else
sta->st_mtim.tv_nsec == stb->st_mtim.tv_nsec
#endif
#endif
&& sta->st_mtime == stb->st_mtime
&& sta->st_size == stb->st_size
&& sta->st_ino == stb->st_ino
&& sta->st_dev == stb->st_dev;
}
void stat_cache_update_entry(const char *name, uint32_t len,
struct stat *st, buffer *etagb)
{
@ -788,12 +806,19 @@ void stat_cache_update_entry(const char *name, uint32_t len,
stat_cache_entry *sce =
stat_cache_sptree_find(sptree, name, len);
if (sce && buffer_is_equal_string(&sce->name, name, len)) {
if (!stat_cache_stat_eq(&sce->st, st)) {
/* etagb might be NULL to clear etag (invalidate) */
buffer_copy_string_len(&sce->etag, CONST_BUF_LEN(etagb));
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
buffer_clear(&sce->content_type);
#endif
if (sce->fd >= 0) {
close(sce->fd);
sce->fd = -1;
}
sce->st = *st;
}
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));
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
buffer_clear(&sce->content_type);
#endif
}
}
@ -1028,6 +1053,14 @@ 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;
}
}
sce->st = st; /*(copy prior to calling fam_dir_monitor())*/
#ifdef HAVE_FAM_H
@ -1048,6 +1081,15 @@ stat_cache_entry * stat_cache_get_entry(const buffer *name) {
return sce;
}
stat_cache_entry * stat_cache_get_entry_open(const buffer * const name, const int symlinks) {
stat_cache_entry * const sce = stat_cache_get_entry(name);
if (NULL == sce) return NULL;
if (sce->fd >= 0) return sce;
if (sce->st.st_size > 0)
sce->fd = stat_cache_open_rdonly_fstat(name, &sce->st, symlinks);
return sce; /* (note: sce->fd might still be -1 if open() failed) */
}
int stat_cache_path_isdir(const buffer *name) {
const stat_cache_entry * const sce = stat_cache_get_entry(name);
return (sce && (S_ISDIR(sce->st.st_mode) ? 1 : (errno = ENOTDIR, 0)));

@ -13,6 +13,7 @@
typedef struct {
buffer name;
time_t stat_ts;
int fd;
#ifdef HAVE_FAM_H
void *fam_dir;
#endif
@ -50,6 +51,7 @@ void stat_cache_delete_entry(const char *name, uint32_t len);
void stat_cache_delete_dir(const char *name, uint32_t len);
void stat_cache_invalidate_entry(const char *name, uint32_t len);
stat_cache_entry * stat_cache_get_entry(const buffer *name);
stat_cache_entry * stat_cache_get_entry_open(const buffer *name, int symlinks);
int stat_cache_path_isdir(const buffer *name);
__attribute_cold__

Loading…
Cancel
Save