/** * Remove cached entry for key, optionally disposing of the whole structure. * Cached entry is flushed if it was dirty and flush is set. * * @return the reusable cached entry if dispose was FALSE and the key was * indeed cached, NULL otherwise. */ static struct cached * remove_entry(dbmw_t *dw, gconstpointer key, gboolean dispose, gboolean flush) { struct cached *old; gpointer old_key; gboolean found; found = map_lookup_extended(dw->values, key, &old_key, (gpointer) &old); if (!found) return NULL; g_assert(old != NULL); if (old->dirty && flush) write_back(dw, key, old); hash_list_remove(dw->keys, key); map_remove(dw->values, key); wfree(old_key, dbmw_keylen(dw, old_key)); if (!dispose) return old; /* * Dispose of the cache structure. */ free_value(dw, old, TRUE); WFREE(old); return NULL; }
/** * Map iterator to free cached entries. */ static gboolean free_cached(gpointer key, gpointer value, gpointer data) { dbmw_t *dw = data; struct cached *entry = value; dbmw_check(dw); g_assert(!entry->len == !entry->data); free_value(dw, entry, TRUE); wfree(key, dbmw_keylen(dw, key)); WFREE(entry); return TRUE; }
/** * Map iterator to free cached entries. */ static bool free_cached(void *key, void *value, void *data) { dbmw_t *dw = data; struct cached *entry = value; dbmw_check(dw); g_assert(!entry->len == !entry->data); free_value(dw, entry, TRUE); wfree(key, dbmw_keylen(dw, key)); WFREE(entry); return TRUE; }
/** * Allocate a new entry in the cache to hold the deserialized value. * * @param dw the DBM wrapper * @param key key we want a cache entry for * @param filled optionally, a new cache entry already filled with the data * * @attention * An older cache entry structure can be returned, and it will still * point to the previous data. Caller should normally invoke fill_entry() * immediately to make sure these stale data are not associated wrongly * with the new key, or supply his own filled structure directly. * * @return a cache entry object that can be filled with the value. */ static struct cached * allocate_entry(dbmw_t *dw, gconstpointer key, struct cached *filled) { struct cached *entry; gpointer saved_key; g_assert(!hash_list_contains(dw->keys, key)); g_assert(!map_contains(dw->values, key)); g_assert(!filled || (!filled->len == !filled->data)); saved_key = wcopy(key, dbmw_keylen(dw, key)); /* * If we have less keys cached than our maximum, add it. * Otherwise evict the least recently used key, at the head. */ if (hash_list_length(dw->keys) < dw->max_cached) { if (filled) entry = filled; else WALLOC0(entry); } else { gpointer head; g_assert(hash_list_length(dw->keys) == dw->max_cached); head = hash_list_head(dw->keys); entry = remove_entry(dw, head, filled != NULL, TRUE); g_assert(filled != NULL || entry != NULL); if (filled) entry = filled; } /* * Add entry into cache. */ g_assert(entry); hash_list_append(dw->keys, saved_key); map_insert(dw->values, saved_key, entry); return entry; }
/** * Map iterator to free cached entries that have been marked as removable. */ static gboolean cache_free_removable(gpointer key, gpointer value, gpointer data) { dbmw_t *dw = data; struct cached *entry = value; dbmw_check(dw); g_assert(!entry->len == !entry->data); if (!entry->removable) return FALSE; free_value(dw, entry, TRUE); hash_list_remove(dw->keys, key); wfree(key, dbmw_keylen(dw, key)); WFREE(entry); return TRUE; }
/** * Remove cached entry for key, optionally disposing of the whole structure. * Cached entry is flushed if it was dirty and flush is set. * * @return the reusable cached entry if dispose was FALSE and the key was * indeed cached, NULL otherwise. */ static struct cached * remove_entry(dbmw_t *dw, const void *key, bool dispose, bool flush) { struct cached *old; void *old_key; bool found; found = map_lookup_extended(dw->values, key, &old_key, (void *) &old); if (!found) return NULL; g_assert(old != NULL); if (dbg_ds_debugging(dw->dbg, 3, DBG_DSF_CACHING)) { dbg_ds_log(dw->dbg, dw, "%s: %s key=%s (%s)", G_STRFUNC, old->dirty ? "dirty" : "clean", dbg_ds_keystr(dw->dbg, key, (size_t) -1), flush ? "flushing" : " discarding"); } if (old->dirty && flush) write_back(dw, key, old); hash_list_remove(dw->keys, key); map_remove(dw->values, key); wfree(old_key, dbmw_keylen(dw, old_key)); if (!dispose) return old; /* * Dispose of the cache structure. */ free_value(dw, old, TRUE); WFREE(old); return NULL; }