You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
4.3 KiB

#include <lighttpd/events.h>
/* API to "fetch" data async. entries are revalidated on every lookup; revalidation should only check
* against a simple TTL. revalidation can trigger refresh, which doesn't invalidate the current entry,
* but starts a new lookup to check whether an update is needed.
* If a lookup fails ("key not found") it still keeps an entry with a NULL data,
* which is also revalidated on lookup (you should use a TTL for negative hits too).
typedef struct liFetchDatabase liFetchDatabase;
typedef struct liFetchCallbacks liFetchCallbacks;
typedef struct liFetchEntry liFetchEntry;
typedef struct liFetchWait liFetchWait;
typedef void (*liFetchWakeupCB)(gpointer wakeup_data);
struct liFetchEntry {
GString *key;
gpointer data; /* read-only after li_fetch_entry_ready() */
gpointer backend_data;
struct liFetchCallbacks {
/* key is in entry->key. set entry->data (and entry->backend_data if needed).
* call li_fetch_entry_ready(entry) if done. if entry->data == NULL it means "not found"
* entry->data/backend_data could already contain data from a refresh with li_fetch_entry_refresh_skip().
void (*lookup)(liFetchDatabase* db, gpointer data, liFetchEntry *entry);
/* called on every lookup, should do a very simple check to verify the entry is still valid.
* DON'T MODIFY entry->data! return FALSE to trigger a new lookup, return TRUE if entry is still valid.
* you can trigger a refresh before returing TRUE with li_fetch_entry_refresh(entry)
gboolean (*revalidate)(liFetchDatabase* db, gpointer data, liFetchEntry *entry);
/* check whether entry should be updated in background. put new data in new_entry.
* call li_fetch_entry_refresh_skip() if old entry is still good (new entry will be deleted)
* call li_fetch_entry_refresh_ready() if old entry should be replaced.
void (*refresh)(liFetchDatabase* db, gpointer data, liFetchEntry *cur_entry, liFetchEntry *new_entry);
/* optional */
void (*free_entry)(gpointer data, liFetchEntry *entry);
/* optional. only called after all entries are freed */
void (*free_db)(gpointer data);
/* generic API */
LI_API void li_fetch_database_acquire(liFetchDatabase* db);
LI_API void li_fetch_database_release(liFetchDatabase* db);
LI_API void li_fetch_entry_acquire(liFetchEntry *entry);
LI_API void li_fetch_entry_release(liFetchEntry *entry);
/* "management" API */
LI_API void li_fetch_invalidate(liFetchDatabase* db, GString *key);
/* API for backends */
LI_API liFetchDatabase* li_fetch_database_new(const liFetchCallbacks *callbacks, gpointer data, guint cache_size, guint neg_cache_size);
/* mark entry as ready to be used. call after lookup() is done */
LI_API void li_fetch_entry_ready(liFetchEntry *entry);
/* trigger a refresh in the background while the entry is still valid. while a refresh is already in progress further refreshes are ignored */
LI_API void li_fetch_entry_refresh(liFetchEntry *entry);
/* li_fetch_entry_refresh_skip can trigger a new lookup if old entry got invalid */
LI_API void li_fetch_entry_refresh_skip(liFetchEntry *new_entry);
LI_API void li_fetch_entry_refresh_ready(liFetchEntry *new_entry);
/* API for frontend */
LI_API gboolean li_fetch_entry_revalidate(liFetchEntry *entry);
/* result == NULL: waiting, jobref will be triggered if ready (call _get again).
* result != NULL:
* call li_fetch_entry_release if you're done with it
* result->data == NULL: not found
LI_API liFetchEntry* li_fetch_get(liFetchDatabase* db, GString *key, liJobRef *jobref, liFetchWait **wait);
/* result == NULL: waiting, wakeup(wakeup_data) will be called if ready (call _get again, can get called in any thread context)
* result != NULL:
* call li_fetch_entry_release if you're done with it
* result->data == NULL: not found
LI_API liFetchEntry* li_fetch_get2(liFetchDatabase* db, GString *key, liFetchWakeupCB wakeup, gpointer wakeup_data, liFetchWait **wait);
LI_API void li_fetch_cancel(liFetchWait **wait);