|
|
|
@ -12,9 +12,13 @@ void li_stat_cache_new(liWorker *wrk, gdouble ttl) {
|
|
|
|
|
liStatCache *sc;
|
|
|
|
|
GError *err;
|
|
|
|
|
|
|
|
|
|
/* ttl default 10s */
|
|
|
|
|
if (ttl < 1)
|
|
|
|
|
if (ttl < 0) {
|
|
|
|
|
/* fall back to default if not sane */
|
|
|
|
|
ttl = 10.0;
|
|
|
|
|
} else if (ttl == 0) {
|
|
|
|
|
/* ttl means disabled stat cache */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc = g_slice_new0(liStatCache);
|
|
|
|
|
sc->ttl = ttl;
|
|
|
|
@ -43,6 +47,10 @@ void li_stat_cache_free(liStatCache *sc) {
|
|
|
|
|
liStatCacheEntry *sce;
|
|
|
|
|
liWaitQueueElem *wqe;
|
|
|
|
|
|
|
|
|
|
/* check if stat cache was enabled */
|
|
|
|
|
if (!sc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* wake up thread */
|
|
|
|
|
sce = g_slice_new0(liStatCacheEntry);
|
|
|
|
|
g_async_queue_push(sc->job_queue_out, sce);
|
|
|
|
@ -296,43 +304,40 @@ static liHandlerResult stat_cache_get(liVRequest *vr, GString *path, struct stat
|
|
|
|
|
liStatCacheEntry *sce;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (NULL == vr) goto callstat;
|
|
|
|
|
|
|
|
|
|
sc = vr->wrk->stat_cache;
|
|
|
|
|
sce = g_hash_table_lookup(sc->entries, path);
|
|
|
|
|
/* force blocking call if we are not in a vrequest context or stat cache is disabled */
|
|
|
|
|
if (!vr || !(sc = vr->wrk->stat_cache))
|
|
|
|
|
async = FALSE;
|
|
|
|
|
|
|
|
|
|
if (sce) {
|
|
|
|
|
/* cache hit, check state */
|
|
|
|
|
if (g_atomic_int_get(&sce->state) == STAT_CACHE_ENTRY_WAITING) {
|
|
|
|
|
if (async) {
|
|
|
|
|
sce = NULL;
|
|
|
|
|
goto callstat;
|
|
|
|
|
}
|
|
|
|
|
if (async) {
|
|
|
|
|
sce = g_hash_table_lookup(sc->entries, path);
|
|
|
|
|
|
|
|
|
|
/* already waiting for it? */
|
|
|
|
|
for (i = 0; i < vr->stat_cache_entries->len; i++) {
|
|
|
|
|
if (g_ptr_array_index(vr->stat_cache_entries, i) == sce) {
|
|
|
|
|
return LI_HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
if (sce) {
|
|
|
|
|
/* cache hit, check state */
|
|
|
|
|
if (g_atomic_int_get(&sce->state) == STAT_CACHE_ENTRY_WAITING) {
|
|
|
|
|
/* already waiting for it? */
|
|
|
|
|
for (i = 0; i < vr->stat_cache_entries->len; i++) {
|
|
|
|
|
if (g_ptr_array_index(vr->stat_cache_entries, i) == sce) {
|
|
|
|
|
return LI_HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
li_stat_cache_entry_acquire(vr, sce);
|
|
|
|
|
return LI_HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc->hits++;
|
|
|
|
|
} else {
|
|
|
|
|
/* cache miss, allocate new entry */
|
|
|
|
|
sce = stat_cache_entry_new(path);
|
|
|
|
|
sce->type = STAT_CACHE_ENTRY_SINGLE;
|
|
|
|
|
li_stat_cache_entry_acquire(vr, sce);
|
|
|
|
|
li_waitqueue_push(&sc->delete_queue, &sce->queue_elem);
|
|
|
|
|
g_hash_table_insert(sc->entries, sce->data.path, sce);
|
|
|
|
|
g_async_queue_push(sc->job_queue_out, sce);
|
|
|
|
|
sc->misses++;
|
|
|
|
|
return LI_HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc->hits++;
|
|
|
|
|
} else if (async) {
|
|
|
|
|
/* cache miss, allocate new entry */
|
|
|
|
|
sce = stat_cache_entry_new(path);
|
|
|
|
|
sce->type = STAT_CACHE_ENTRY_SINGLE;
|
|
|
|
|
li_stat_cache_entry_acquire(vr, sce);
|
|
|
|
|
li_waitqueue_push(&sc->delete_queue, &sce->queue_elem);
|
|
|
|
|
g_hash_table_insert(sc->entries, sce->data.path, sce);
|
|
|
|
|
g_async_queue_push(sc->job_queue_out, sce);
|
|
|
|
|
sc->misses++;
|
|
|
|
|
return LI_HANDLER_WAIT_FOR_EVENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callstat:
|
|
|
|
|
if (fd) {
|
|
|
|
|
/* open + fstat */
|
|
|
|
|
while (-1 == (*fd = open(path->str, O_RDONLY))) {
|
|
|
|
|