Skip to content

Commit 3a8784f

Browse files
committed
increase index bucket count default, fix error-case memory leak
1 parent 27f8b36 commit 3a8784f

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

include/index.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,27 @@
1010
/// @struct inode_s
1111
/// @brief Individual file node in the index map.
1212
struct inode_s {
13-
char* fp; ///< File path (string duplicated)
14-
struct fsstat_s st; ///< File stat info structure
15-
struct inode_s* next; ///< Next node in the index map
13+
char* fp; ///< File path (string duplicated)
14+
struct fsstat_s st; ///< File stat info structure
15+
struct inode_s* next;///< Next node in the index map
1616
};
1717

1818
/// @def INDEXBUCKETS
1919
/// @brief The fixed number of buckets in the index map.
20-
#define INDEXBUCKETS 64
20+
/// @note This is a magic number, but via testing, performance is healthy around
21+
/// ~40 nodes per bucket, so this should roughly accommodate ~150k nodes.
22+
#define INDEXBUCKETS 4096
23+
24+
/// @def INDEXBUCKETSMASK
25+
/// @brief The bitmask used for deriving the bucket index from the hash value.
26+
/// @note This should correspond to the number of buckets defined in
27+
/// `INDEXBUCKETS` (0xFFF, 0b1111_1111_1111, 2^12-1 = 4095).
28+
#define INDEXBUCKETSMASK 0xFFF ///< Maximum bucket index mask
2129

2230
/// @struct index_s
2331
/// @brief Index map structure for storing file nodes.
2432
struct index_s {
25-
struct inode_s* buckets[INDEXBUCKETS]; ///< Array of index buckets
33+
struct inode_s* buckets[INDEXBUCKETS];///< Array of index buckets
2634
long size; ///< Number of sum nodes in the index
2735
};
2836

@@ -48,7 +56,8 @@ int indexwrite(struct index_s* idx, FILE* s);
4856
/// is set.
4957
int indexread(struct index_s* idx, FILE* s);
5058

51-
/// @brief Copies the node and inserts it into the index mapping.
59+
/// @brief Copies the node and inserts it into the index mapping. The copy is
60+
/// by assignment, so pointers within the node are retained (not duplicated).
5261
/// @param idx The index to insert into
5362
/// @param node The node to insert
5463
/// @return The pointer to the new node in the index map, otherwise NULL is

src/index.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,28 @@
1313
/// @brief The maximum filepath length of a file in the index.
1414
#define INDEXMAXFP 512
1515

16-
/// @brief Hashes the filepath string into an index bucket.
16+
/// @brief Hashes the filepath string.
17+
/// @note 64-bit FNV-1a implementation is used for hashing.
1718
/// @param fp The filepath string to hash
18-
/// @return The index bucket number.
19-
static int indexhash(const char* fp) {
20-
int h = 0;
21-
for (const char* p = fp; *p != '\0'; p++) h = (h << 5) - h + *p;
22-
if (h < 0) h = -h;
23-
return h % INDEXBUCKETS;
19+
/// @return The hashed value of the filepath.
20+
static uint64_t indexhash(const char* fp) {
21+
uint64_t hash = 14695981039346656037u;// FNV offset basis
22+
while (*fp) {
23+
hash ^= (uint8_t) *fp;// XOR byte into hash
24+
hash *= 1099511628211;// FNV prime
25+
fp++;
26+
}
27+
return hash;
2428
}
2529

30+
/// @def indexbucket
31+
/// @brief Maps and casts the hash value to a bucket index via the last N bits
32+
/// (where N is the number of buckets, `INDEXBUCKETS`).
33+
#define indexbucket(hash) ((int) (hash & INDEXBUCKETSMASK))
34+
2635
struct inode_s* indexfind(const struct index_s* idx, const char* fp) {
27-
struct inode_s* head = idx->buckets[indexhash(fp)];
36+
const uint64_t hash = indexhash(fp);
37+
struct inode_s* head = idx->buckets[indexbucket(hash)];
2838
while (head != NULL) {
2939
if (strcmp(head->fp, fp) == 0) return head;
3040
head = head->next;
@@ -72,8 +82,11 @@ int indexread(struct index_s* idx, FILE* s) {
7282
&b.st.fsze) == 3) {
7383
// duplicate the string onto the heap
7484
if ((b.fp = strdup(b.fp)) == NULL) return -1;
75-
if (indexput(idx, b) == NULL) return -1;
76-
b.fp = fp;
85+
if (indexput(idx, b) == NULL) {
86+
free(b.fp);
87+
return -1;
88+
}
89+
b.fp = fp;// reset to static buffer
7790
}
7891

7992
return 0;
@@ -93,10 +106,11 @@ static struct inode_s* indexprepend(struct inode_s* idx,
93106
}
94107

95108
struct inode_s* indexput(struct index_s* idx, const struct inode_s node) {
96-
struct inode_s* bucket = idx->buckets[indexhash(node.fp)];
109+
const int bi = indexbucket(indexhash(node.fp));
110+
struct inode_s* bucket = idx->buckets[bi];
97111
struct inode_s* head = indexprepend(bucket, node);
98112
if (head == NULL) return NULL;
99-
idx->buckets[indexhash(node.fp)] = head;
113+
idx->buckets[bi] = head;
100114
idx->size++;
101115
return head;
102116
}

0 commit comments

Comments
 (0)