Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 49 additions & 43 deletions hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#include <stdio.h>

// DJB2 hash function
size_t hash_function(unsigned char *key, size_t key_len, size_t table_size)
size_t hash_function(const unsigned char *key, const size_t key_len,
const size_t table_size)
{
size_t hash = 5381;
for (size_t i = 0; i < key_len; i++) {
Expand All @@ -12,55 +13,59 @@ size_t hash_function(unsigned char *key, size_t key_len, size_t table_size)
}

// Create a new hash table
HashTable *create_hash_table(size_t size)
HashTable *create_hash_table(size_t capacity)
{
HashTable *table = malloc(sizeof(HashTable));
table->buckets = calloc(size, sizeof(HashTableEntry *));
table->size = size;
table->entries = calloc(capacity, sizeof(HashTableEntry));
table->metadata = calloc(capacity, sizeof(uint8_t));
table->capacity = capacity;
table->count = 0;
return table;
}

void free_hash_table(HashTable *table)
{
for (size_t i = 0; i < table->size; i++) {
HashTableEntry *entry = table->buckets[i];
while (entry) {
HashTableEntry *next = entry->next;
free(entry->key);
free(entry->value);
free(entry);
entry = next;
for (size_t i = 0; i < table->capacity; i++) {
if (table->metadata[i] && table->entries[i].occupied) {
free(table->entries[i].key);
free(table->entries[i].value);
}
}
free(table->buckets);
free(table->entries);
free(table->metadata);
free(table);
}

bool set_value(HashTable *table, unsigned char *key, size_t key_len,
unsigned char *value, size_t value_len)
{
size_t index = hash_function(key, key_len, table->size);
HashTableEntry *current = table->buckets[index];
while (current != NULL && (current->key_len != key_len ||
memcmp(current->key, key, key_len) != 0)) {
current = current->next;
if (table->count >= table->capacity * 0.75) {
// TODO: The function to resize and rehash can be implemented here
}
if (current == NULL) {
// New entry
current = malloc(sizeof(HashTableEntry));
current->key = malloc(key_len);
memcpy(current->key, key, key_len);
current->key_len = key_len;
current->next = table->buckets[index];
table->buckets[index] = current;
} else {
// Update existing entry
free(current->value);

const size_t index = hash_function(key, key_len, table->capacity);
for (size_t i = 0; i < table->capacity; i++) {
const size_t pos = (index + i) % table->capacity;
if (!table->metadata[pos] ||
(table->entries[pos].key_len == key_len &&
memcmp(table->entries[pos].key, key, key_len) == 0)) {
if (!table->metadata[pos]) {
table->entries[pos].key = malloc(key_len);
memcpy(table->entries[pos].key, key, key_len);
table->entries[pos].key_len = key_len;
table->metadata[pos] = 1;
table->count++;
} else {
free(table->entries[pos].value);
}
table->entries[pos].value = malloc(value_len);
memcpy(table->entries[pos].value, value, value_len);
table->entries[pos].value_len = value_len;
table->entries[pos].occupied = true;
return true;
}
}
current->value = malloc(value_len);
memcpy(current->value, value, value_len);
current->value_len = value_len;
return true;
return false; // Table is at capacity and needs resizing
}

bool get_value(HashTable *table, unsigned char *key, size_t key_len,
Expand All @@ -69,20 +74,21 @@ bool get_value(HashTable *table, unsigned char *key, size_t key_len,
if (!table || !key || !value || !value_len)
return false;

size_t index = hash_function(key, key_len, table->size);
for (HashTableEntry *current = table->buckets[index]; current;
current = current->next) {
if (current->key_len == key_len &&
memcmp(current->key, key, key_len) == 0) {
unsigned char *out = malloc(current->value_len);
if (!out)
const size_t index = hash_function(key, key_len, table->capacity);
for (size_t i = 0; i < table->capacity; i++) {
const size_t pos = (index + i) % table->capacity;
if (table->metadata[pos] && table->entries[pos].key_len == key_len &&
memcmp(table->entries[pos].key, key, key_len) == 0) {
*value = malloc(table->entries[pos].value_len);
if (!*value)
return false; // allocation failed

memcpy(out, current->value, current->value_len);
*value = out;
*value_len = current->value_len;
memcpy(*value, table->entries[pos].value, table->entries[pos].value_len);
*value_len = table->entries[pos].value_len;
return true;
}
if (!table->metadata[pos])
break; // Stop if a slot is empty (no key here)
}

// not found
Expand Down
10 changes: 6 additions & 4 deletions hashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ typedef struct HashTableEntry {
size_t key_len;
unsigned char *value;
size_t value_len;
struct HashTableEntry *next;
bool occupied; // Indicate if this slot is occupied
} HashTableEntry;

typedef struct HashTable {
HashTableEntry **buckets;
size_t size;
HashTableEntry *entries; // Array of entries
uint8_t *metadata; // Metadata array for occupancy
size_t capacity; // Current capacity of the table
size_t count; // Number of elements in the table
} HashTable;

HashTable *create_hash_table(size_t size);
Expand All @@ -24,6 +26,6 @@ bool set_value(HashTable *table, unsigned char *key, size_t key_len,
unsigned char *value, size_t value_len);
bool get_value(HashTable *table, unsigned char *key, size_t key_len,
unsigned char **value, size_t *value_len);
size_t hash_function(unsigned char *key, size_t key_len, size_t table_size);
size_t hash_function(const unsigned char *key, size_t key_len, size_t table_size);

#endif // HASHTABLE_H
4 changes: 2 additions & 2 deletions server.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Server configuration
port 5995
# port 5995
logs-enabled true
verbose false
daemonize false
show-logo true
# unixsocket /tmp/fkvs.sock
unixsocket /tmp/fkvs.sock
3 changes: 3 additions & 0 deletions tests/test_command_parser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "../command_parser.h"


Binary file added tests/test_hashtable
Binary file not shown.
29 changes: 29 additions & 0 deletions tests/test_hashtable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../hashtable.h"

void test_set_and_get() {
HashTable *table = create_hash_table(10);
unsigned char key[] = "testkey";
unsigned char value[] = "testvalue";

bool set_result = set_value(table, key, strlen((char *)key), value, strlen((char *)value));
assert(set_result);

unsigned char *retrieved_value;
size_t retrieved_value_len;
bool get_result = get_value(table, key, strlen((char *)key), &retrieved_value, &retrieved_value_len);
assert(get_result);
assert(memcmp(retrieved_value, value, retrieved_value_len) == 0);

free(retrieved_value);
free_hash_table(table);
}

int main() {
test_set_and_get();
printf("All tests passed.\n");
return 0;
}
Loading