From 111403fe72805468d760a8f3a41f5a24dee8d081 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 28 Feb 2019 08:56:37 -0800 Subject: [PATCH] map: Fix removal of entries from the table Removing entries from an open addressed hash table creates holes in the collision chains, preventing previous colliding entries to be found. By inserting tombstones, rather than clearing deleted entries makes it possible to distinguish the end of a chain from a hole. Reviewed-by: Arun Kumar Neelakantam Signed-off-by: Bjorn Andersson --- src/map.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/map.c b/src/map.c index f22c834..eed3488 100644 --- a/src/map.c +++ b/src/map.c @@ -31,6 +31,9 @@ struct map_entry { struct map_item *item; }; +/* Marker for deleted items */ +static struct map_item deleted; + void map_destroy(struct map *map) { free(map->data); @@ -43,7 +46,8 @@ void map_clear(struct map *map, void (*release)(struct map_item *)) for (i = 0; i < map->size; ++i){ if (!map->data[i].item) continue; - (* release)(map->data[i].item); + if (map->data[i].item != &deleted) + (* release)(map->data[i].item); map->data[i].item = NULL; } map->count = 0; @@ -69,7 +73,7 @@ static int map_hash(struct map *map, unsigned int key) for (i = 0; i < map->size; ++i) { e = &map->data[idx]; - if (!e->item) { + if (!e->item || e->item == &deleted) { ++map->count; return idx; } @@ -94,8 +98,12 @@ int map_reput(struct map *map, unsigned int key, struct map_item *value, return rc; } - if (old) - *old = map->data[rc].item; + if (old) { + if (map->data[rc].item == &deleted) + *old = NULL; + else + *old = map->data[rc].item; + } map->data[rc].item = value; if (value) map->data[rc].item->key = key; @@ -126,7 +134,7 @@ static int map_rehash(struct map *map) map->count = 0; for (i = 0; i < o_size; ++i){ - if (!oldt[i].item) + if (!oldt[i].item || oldt[i].item == &deleted) continue; rc = map_put(map, oldt[i].item->key, oldt[i].item); if (rc < 0) @@ -150,11 +158,14 @@ static struct map_entry *map_find(const struct map *map, unsigned int key) for (i = 0; i < map->size; ++i) { e = &map->data[idx]; + idx = (idx + 1) % map->size; + if (!e->item) break; + if (e->item == &deleted) + continue; if (e->item->key == key) return e; - idx = (idx + 1) % map->size; } return NULL; } @@ -180,7 +191,7 @@ int map_remove(struct map *map, unsigned int key) e = map_find(map, key); if (e) { - e->item = NULL; + e->item = &deleted; --map->count; } return !e; @@ -196,7 +207,7 @@ static struct map_entry *map_iter_from(const struct map *map, unsigned int start unsigned int i = start; for (; i < map->size; ++i) { - if (map->data[i].item) + if (map->data[i].item && map->data[i].item != &deleted) return &map->data[i]; } return NULL;