Change linkmap structure to handle collisions by placing into the

next free bucket rather than by using a linked list structure. Fix
bug where the filename was being freed in linkmap buckets, even
though the data was owned by the caller.
This commit is contained in:
Nathan Fisher 2023-09-14 22:17:11 -04:00
parent 826df41c01
commit ee7c9b1b5d
2 changed files with 21 additions and 55 deletions

View file

@ -125,7 +125,6 @@ typedef struct __bucket {
} key;
uint64_t hash;
char * path;
struct __bucket * next;
} haggis_bucket;
typedef struct {

View file

@ -30,10 +30,10 @@
* other than his own.
*/
#include "haggis.h"
#include "haggis_private.h"
#include <limits.h> // PATH_MAX
#include <stdio.h>
#include <stdlib.h> // calloc, free
#include <string.h> // strndup
@ -63,38 +63,6 @@ uint64_t hash_str_fnv1a_64(char * s) {
return hash;
}
haggis_bucket* haggis_bucket_init(ino_t inode, uint64_t hash, char * path) {
haggis_bucket *bucket;
bucket = calloc(1, sizeof(haggis_bucket));
if (bucket == NULL) return NULL;
bucket->key.val = inode;
bucket->hash = hash;
bucket->path = path;
bucket->next = NULL;
return bucket;
}
void haggis_bucket_deinit(haggis_bucket *nod) {
if (nod->path != NULL)
free(nod->path);
free(nod);
}
char* haggis_bucket_search_append(haggis_bucket *head, haggis_bucket *tail) {
char* target;
while (head->next != NULL) {
if (head->key.val == tail->key.val) {
target = strndup(head->path, PATH_MAX - 1);
return target;
}
head = head->next;
}
head->next = tail;
return NULL;
}
haggis_linkmap* haggis_linkmap_init() {
haggis_linkmap *map;
@ -111,13 +79,6 @@ haggis_linkmap* haggis_linkmap_init() {
}
void haggis_linkmap_deinit(haggis_linkmap *map) {
int i;
for (i = 0; i < map->capacity; i++) {
if (map->buckets[i].next != NULL) {
haggis_bucket_deinit(map->buckets[i].next);
}
}
free(map->buckets);
free(map);
}
@ -130,6 +91,9 @@ int haggis_linkmap_expand(haggis_linkmap *map) {
buckets_new = calloc(map->capacity + HAGGIS_BUCKETS_BASE, sizeof(haggis_bucket));
if (buckets_new == NULL)
return 2;
for (i = 0; i < map->capacity + HAGGIS_BUCKETS_BASE; i++) {
map->buckets[i].path = NULL;
}
for (i = 0; i < map->capacity; i++) {
if (map->buckets[i].key.val != 0) {
hash = hash_fnv1a_64(&map->buckets[i].key.bytes[0], sizeof(ino_t));
@ -151,8 +115,7 @@ char* haggis_linkmap_get_or_add(haggis_linkmap *map, ino_t inode, char * path) {
u8 bytes[sizeof(ino_t)];
} key;
char * target = NULL;
size_t idx, hash;
haggis_bucket *b;
size_t idx, hash, i;
pthread_mutex_lock(&map->mutex);
if (map->len >= map->capacity)
@ -160,18 +123,22 @@ char* haggis_linkmap_get_or_add(haggis_linkmap *map, ino_t inode, char * path) {
key.val = inode;
hash = hash_fnv1a_64(key.bytes, sizeof(ino_t));
idx = hash % map->capacity;
if (map->buckets[idx].key.val == inode) {
target = strndup(map->buckets[idx].path, PATH_MAX - 1);
map->buckets[idx].path = path;
} else if (map->buckets[idx].key.val == 0) {
map->buckets[idx].key.val = inode;
map->buckets[idx].hash = hash;
map->buckets[idx].path = path;
map->len++;
} else {
b = haggis_bucket_init(key.val, hash, path);
if (b == NULL) return NULL;
target = haggis_bucket_search_append(&map->buckets[idx], b);
for (i = 0; i < map->capacity; i++) {
if (map->buckets[idx].key.val == inode) {
target = strndup(map->buckets[idx].path, PATH_MAX - 1);
map->buckets[idx].path = path;
break;
} else if (map->buckets[idx].key.val == 0) {
map->buckets[idx].key.val = inode;
map->buckets[idx].hash = hash;
map->buckets[idx].path = path;
map->len++;
break;
} else {
idx++;
if (idx == map->capacity)
idx = 0;
}
}
pthread_mutex_unlock(&map->mutex);
return target;