From ce077a6d2c2c06349d44b69cab341d3c650eec1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz> Date: Mon, 13 Jul 2015 18:22:50 +0200 Subject: [PATCH] generic/lru: count updates in slot for item-slot stickiness --- lib/generic/lru.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/generic/lru.h b/lib/generic/lru.h index b9ab19ac1..572b4f1ed 100644 --- a/lib/generic/lru.h +++ b/lib/generic/lru.h @@ -17,8 +17,10 @@ * @file lru.h * @brief LRU-like cache. * - * @note This is a naive LRU implementation, if value exists it is treated as old - * if the key collides. This may be improved with double hashing or hopscotch. + * @note This is a naive LRU implementation with a simple slot stickiness counting. + * Each write access increases stickiness on success, and decreases on collision. + * A slot is freed if the stickiness decreases to zero. This makes it less likely, + * that often-updated entries are jousted out of cache. * * # Example usage: * @@ -48,7 +50,9 @@ * } * char *enemies[] = {"goro", "raiden", "subzero", "scorpion"}; * for (int i = 0; i < 4; ++i) { - * *lru_set(&lru, enemies[i], strlen(enemies[i])) = i; + * int *val = lru_set(&lru, enemies[i], strlen(enemies[i])); + * if (val) + * *val = i; * } * * // We're done @@ -68,6 +72,7 @@ #define lru_slot_struct \ char *key; /**< Slot key */ \ uint32_t len; /**< Slot length */ \ + uint32_t refs; /**< Slot importance (#writes - #collisions) */ \ /** @brief Slot header. */ struct lru_slot { lru_slot_struct @@ -142,8 +147,14 @@ static inline void *lru_slot_set(struct lru_hash_base *lru, const char *key, uin } uint32_t id = hash(key, len) % lru->size; struct lru_slot *slot = lru_slot_at(lru, id); - if (!lru_slot_match(slot, key, len)) { + if (lru_slot_match(slot, key, len)) { + slot->refs += 1; /* Increase slot significance */ + } else { if (slot->key) { + slot->refs -= 1; /* Decrease slot significance */ + if (slot->refs > 0) { + return NULL; /* Couldn't joust former key. */ + } lru->evictions += 1; free(slot->key); if (lru->evict) { @@ -157,6 +168,7 @@ static inline void *lru_slot_set(struct lru_hash_base *lru, const char *key, uin } memcpy(slot->key, key, len); slot->len = len; + slot->refs = 1; } return lru_slot_val(slot, offset); } -- GitLab