Mercurial
changeset 5:3e12bf044589
Fixed Dowa hashmap to recursively add files into memory.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sat, 27 Sep 2025 16:23:04 -0700 |
| parents | 0b3b4f5887bb |
| children | 1e61008b9980 |
| files | dowa/BUILD dowa/d_memory.c dowa/dowa.h dowa/dowa_test.c dowa/test_folder/bar/bar.txt dowa/test_folder/foo.txt seobeo/main.c seobeo/seobeo.h |
| diffstat | 8 files changed, 227 insertions(+), 127 deletions(-) [+] |
line wrap: on
line diff
--- a/dowa/BUILD Fri Sep 26 15:14:46 2025 -0700 +++ b/dowa/BUILD Sat Sep 27 16:23:04 2025 -0700 @@ -20,4 +20,7 @@ srcs = ["dowa_test.c"], deps = [":dowa"], args = [], + data = glob([ + "test_folder/**", + ]), )
--- a/dowa/d_memory.c Fri Sep 26 15:14:46 2025 -0700 +++ b/dowa/d_memory.c Sat Sep 27 16:23:04 2025 -0700 @@ -1,15 +1,15 @@ #include "dowa.h" // --- Arena --- // -Dowa_PArena Dowa_Arena_Initialize(size_t capacity) +Dowa_PArena Dowa_Arena_Create(size_t capacity) { - Dowa_PArena p_arena; - p_arena = malloc(capacity); + Dowa_PArena p_arena = malloc(sizeof(Dowa_Arena)); if (p_arena == NULL) { perror("malloc"); return NULL; } + p_arena->buffer = malloc(capacity); p_arena->offset = 0; p_arena->capacity = capacity; return p_arena; @@ -28,8 +28,10 @@ void Dowa_Arena_Free(Dowa_PArena p_arena) { - if (p_arena) { - free(p_arena->buffer); + if (p_arena) + { + if (p_arena->buffer) + free(p_arena->buffer); free(p_arena); } } @@ -43,7 +45,7 @@ { return NULL; } - p_hash_map->entries = calloc(capacity, sizeof *p_hash_map->entries); + p_hash_map->entries = calloc(capacity, sizeof(*p_hash_map->entries)); if (p_hash_map->entries == NULL) { free(p_hash_map); @@ -54,6 +56,29 @@ return p_hash_map; } +void Dowa_HashMap_Free(Dowa_PHashMap p_hash_map) +{ + if (p_hash_map) + { + Dowa_PHashEntry entry; + if (p_hash_map->entries) + { + for (int idx=0; idx<p_hash_map->capacity; idx++) + { + entry = p_hash_map->entries[idx]; + if (entry) + { + free(entry->key); + free(entry->buffer); + free(entry); + } + } + free(p_hash_map->entries); + } + } + free(p_hash_map); +} + int32 Dowa_HashMap_GetPosition(Dowa_PHashMap p_hash_map, char *key) { int32 hash_val = HASH_KEY_NUMBER; @@ -65,41 +90,64 @@ return hash_val % p_hash_map->capacity; } -void Dowa_HashMap_PushValueWithType(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_ValueType type) +void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, char *key) +{ + int idx_foo = Dowa_HashMap_GetPosition(p_hash_map, key); + void *value = p_hash_map->entries[idx_foo]; + if (strcmp(((Dowa_PHashEntry) value)->key, key) != 0) + { + return NULL; + } + return ((Dowa_PHashEntry) value)->buffer; +} + +int32 Dowa_HashMap_PushValueWithTypeNoCopy(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type) { int idx = Dowa_HashMap_GetPosition(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; if (entry) - { - free(entry->key); free(entry->buffer); - } else { entry = malloc(sizeof(Dowa_HashEntry)); - if (entry == NULL) - { - perror("malloc"); - return; - } + if (entry == NULL) { perror("malloc"); return -1; } + p_hash_map->entries[idx] = entry; + p_hash_map->current_capacity++; + entry->key = strdup(key); } - entry->key = strdup(key); - entry->buffer = malloc(value_size); - if (entry->buffer == NULL) + entry->buffer = value; + entry->capacity = value_size; + entry->type = type; + return 0; +} + +int32 Dowa_HashMap_PushValueWithType(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type) +{ + int idx = Dowa_HashMap_GetPosition(p_hash_map, key); + Dowa_PHashEntry entry = p_hash_map->entries[idx]; + if (entry) + free(entry->buffer); + else { - perror("malloc"); - return; + entry = malloc(sizeof(Dowa_HashEntry)); + if (entry == NULL) { perror("malloc"); return -1; } + + p_hash_map->entries[idx] = entry; + p_hash_map->current_capacity++; + entry->key = strdup(key); } + entry->buffer = malloc(value_size); + if (entry->buffer == NULL) { perror("malloc"); return -1; } entry->capacity = value_size; entry->type = type; memcpy(entry->buffer, value, value_size); - p_hash_map->current_capacity++; + return 0; } void Dowa_HashMap_PushValue(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size) { - Dowa_HashMap_PushValueWithType(p_hash_map, key, value, value_size, DOWA_TYPE_BUFFER); + Dowa_HashMap_PushValueWithType(p_hash_map, key, value, value_size, DOWA_HASH_MAP_TYPE_BUFFER); } void Dowa_HashMap_PopKey(Dowa_PHashMap p_hash_map, char *key) @@ -119,10 +167,9 @@ } } -#include <stdio.h> - void Dowa_HashMap_Print(Dowa_PHashMap map) { + printf("\n-----------\n\n"); for (size_t i = 0; i < map->capacity; ++i) { Dowa_PHashEntry e = map->entries[i]; @@ -130,23 +177,29 @@ printf("%s: ", e->key); switch (e->type) { - case DOWA_TYPE_BUFFER: + case DOWA_HASH_MAP_TYPE_BUFFER: { unsigned char *p = e->buffer; - for (size_t j = 0; j < e->capacity; ++j) { + for (size_t j = 0; j < e->capacity; ++j) + { printf("%02x", p[j]); } printf("\n"); } break; - case DOWA_TYPE_STRING: + case DOWA_HASH_MAP_TYPE_STRING: { printf("%s\n", (char*)e->buffer); } break; - case DOWA_TYPE_INT: + case DOWA_HASH_MAP_TYPE_HASHMAP: { - printf("%d\n", *(int32_t*)e->buffer); + printf("This is a hashmap with size of %zu, and pointer %p\n", (Dowa_PHashMap)e->capacity, (void *)e); + } + break; + case DOWA_HASH_MAP_TYPE_INT: + { + printf("%d\n", *(int32*)e->buffer); } break; default: @@ -155,20 +208,17 @@ } } } + printf("-----------\n"); } - - -int Dowa_Cache_Folder(Dowa_PHashMap map, const char *folder_path) +int Dowa_HashMap_Cache_Folder(Dowa_PHashMap map, const char *folder_path) { DIR *dir = opendir(folder_path); - if (!dir) { - perror("opendir"); - return -1; - } + if (!dir) { perror("opendir"); return -1; } struct dirent *entry; - while ((entry = readdir(dir))) { + while ((entry = readdir(dir))) + { // skip "." and ".." if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || @@ -179,41 +229,53 @@ snprintf(fullpath, sizeof fullpath, "%s/%s", folder_path, entry->d_name); struct stat st; - if (stat(fullpath, &st) < 0 || !S_ISREG(st.st_mode)) - continue; // skip non-files or errors + if (stat(fullpath, &st) < 0) { perror("stat"); continue; } - size_t size = (size_t)st.st_size; - FILE *f = fopen(fullpath, "rb"); - if (!f) + if (S_ISREG(st.st_mode)) { - perror("fopen"); - continue; - } + size_t size = (size_t)st.st_size; + FILE *f = fopen(fullpath, "rb"); + if (!f) { perror("fopen"); continue; } + + void *buf = malloc(size); + if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; } - void *buf = malloc(size); - if (!buf) - { - perror("malloc"); + if (fread(buf, 1, size, f) != size) + { + perror("fread"); + free(buf); + fclose(f); + continue; + } fclose(f); - closedir(dir); - return -1; + + Dowa_HashMap_PushValueWithType(map, entry->d_name, buf, size, DOWA_HASH_MAP_TYPE_STRING); + free(buf); // Dowa_HashMap_PushValue made its own copy } - - if (fread(buf, 1, size, f) != size) + else if (S_ISDIR(st.st_mode)) { - perror("fread"); - free(buf); - fclose(f); - continue; - } - fclose(f); + Dowa_PHashMap p_child_map = Dowa_HashMap_Create(100); + if (!p_child_map) + { + perror("Dowa_HashMap_Create"); + return -1; + } + if (Dowa_HashMap_Cache_Folder(p_child_map, fullpath) == -1) + { + perror("Dowa_HashMap_Cache_Folder"); + return -1; + } + void *value = Dowa_HashMap_Get(p_child_map, "bar.txt"); - // key = filename (d_name), value = file contents - Dowa_HashMap_PushValueWithType(map, entry->d_name, buf, size, DOWA_TYPE_STRING); - - free(buf); // Dowa_HashMap_PushValue made its own copy + // Should not copy as we malloced alredy. + if (Dowa_HashMap_PushValueWithTypeNoCopy(map, entry->d_name, p_child_map, + sizeof(p_child_map), DOWA_HASH_MAP_TYPE_HASHMAP) == -1) + { + Dowa_HashMap_Free(map); + return -1; + } + } } - closedir(dir); return 0; }
--- a/dowa/dowa.h Fri Sep 26 15:14:46 2025 -0700 +++ b/dowa/dowa.h Sat Sep 27 16:23:04 2025 -0700 @@ -13,7 +13,7 @@ #include "dowa_internal.h" #define HASH_KEY_NUMBER 5381 // DJD hash number - +#define ONE_MEGA_BYTE 1048576 typedef unsigned int uint32; typedef int int32; typedef unsigned short uint16; @@ -30,24 +30,25 @@ char *buffer; size_t offset; size_t capacity; -} Dowa_Areana, *Dowa_PArena; +} Dowa_Arena, *Dowa_PArena; -extern Dowa_PArena Dowa_Arena_Initialize(size_t capacity); +extern Dowa_PArena Dowa_Arena_Create(size_t capacity); extern void *Dowa_Arena_Allocate(Dowa_PArena p_arena, size_t size); extern void Dowa_Arena_Free(Dowa_PArena p_arena); -// --- Map --- // +// --- HashMap --- // typedef enum { - DOWA_TYPE_BUFFER, - DOWA_TYPE_STRING, - DOWA_TYPE_INT, -} Dowa_ValueType; + DOWA_HASH_MAP_TYPE_BUFFER, + DOWA_HASH_MAP_TYPE_STRING, + DOWA_HASH_MAP_TYPE_HASHMAP, + DOWA_HASH_MAP_TYPE_INT, +} Dowa_HashMap_ValueType; typedef struct { char *key; void *buffer; size_t capacity; - Dowa_ValueType type; + Dowa_HashMap_ValueType type; } Dowa_HashEntry, *Dowa_PHashEntry; typedef struct { @@ -56,16 +57,19 @@ uint32 current_capacity; } Dowa_HashMap, *Dowa_PHashMap; -extern Dowa_PHashMap Dowa_HashMap_Create(size_t capacity); -extern int32 Dowa_HashMap_GetPosition(Dowa_PHashMap p_hash_map, char *key); -extern void Dowa_HashMap_PushValue(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size); -extern void Dowa_HashMap_PushValueWithType(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_ValueType type); -extern void Dowa_HashMap_PopKey(Dowa_PHashMap p_hash_map, char *key); +extern Dowa_PHashMap Dowa_HashMap_Create(size_t capacity); +extern void Dowa_HashMap_Free(Dowa_PHashMap p_hash_map); +extern int32 Dowa_HashMap_GetPosition(Dowa_PHashMap p_hash_map, char *key); +extern void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, char *key); +extern void Dowa_HashMap_PushValue(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size); +extern int32 Dowa_HashMap_PushValueWithTypeNoCopy(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type); +extern int32 Dowa_HashMap_PushValueWithType(Dowa_PHashMap p_hash_map, char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type); +extern void Dowa_HashMap_PopKey(Dowa_PHashMap p_hash_map, char *key); // --- Maybe Useful --- // extern void Dowa_HashMap_Print(Dowa_PHashMap map); -// 0 for success, -1 for failure. -extern int Dowa_Cache_Folder(Dowa_PHashMap map, const char *folder_path); +// 0 for success, -1 for failure. Get all files in the folder into key and vlaues. +extern int Dowa_HashMap_Cache_Folder(Dowa_PHashMap map, const char *folder_path); #endif
--- a/dowa/dowa_test.c Fri Sep 26 15:14:46 2025 -0700 +++ b/dowa/dowa_test.c Sat Sep 27 16:23:04 2025 -0700 @@ -1,16 +1,19 @@ #include "dowa.h" -static void TestArena() { +static void TestArena() +{ const size_t capacity = 64; - Dowa_PArena arena = Dowa_Arena_Initialize(capacity); + Dowa_PArena arena = Dowa_Arena_Create(capacity); assert(arena != NULL); assert(arena->offset == 0); assert(arena->capacity == capacity); // Allocate within capacity void *p1 = Dowa_Arena_Allocate(arena, 16); - // assert(p1 != NULL); + assert(p1 != NULL); assert(arena->offset == 16); + sprintf((char *)p1, "%i", 10); + assert(strcmp(p1, "10") == 0); // Allocate more void *p2 = Dowa_Arena_Allocate(arena, 32); @@ -25,7 +28,8 @@ Dowa_Arena_Free(arena); } -static void TestHashMap() { +static void TestHashMap() +{ const size_t capacity = 10; Dowa_PHashMap map = Dowa_HashMap_Create(capacity); assert(map != NULL); @@ -43,21 +47,20 @@ assert(strcmp(e_foo->key, "foo") == 0); assert(*(int*)e_foo->buffer == 42); - // Overwrite "foo" -> 100 + // Overwrite "foo" -> 100 (capacity should not change) int val2 = 100; Dowa_HashMap_PushValue(map, "foo", &val2, sizeof(val2)); - // current_capacity increments again according to your implementation - assert(map->current_capacity == 2); + assert(map->current_capacity == 1); - Dowa_PHashEntry e_foo2 = map->entries[idx_foo]; - assert(e_foo2 != NULL); - assert(strcmp(e_foo2->key, "foo") == 0); - assert(*(int*)e_foo2->buffer == 100); + e_foo = map->entries[idx_foo]; + assert(e_foo != NULL); + assert(strcmp(e_foo->key, "foo") == 0); + assert(*(int*)e_foo->buffer == 100); // Insert "bar" -> -7 int val3 = -7; Dowa_HashMap_PushValue(map, "bar", &val3, sizeof(val3)); - assert(map->current_capacity == 3); + assert(map->current_capacity == 2); int idx_bar = Dowa_HashMap_GetPosition(map, "bar"); Dowa_PHashEntry e_bar = map->entries[idx_bar]; @@ -68,24 +71,35 @@ // Pop "foo" Dowa_HashMap_PopKey(map, "foo"); assert(map->entries[idx_foo] == NULL); - assert(map->current_capacity == 2); + assert(map->current_capacity == 1); // Pop "bar" Dowa_HashMap_PopKey(map, "bar"); assert(map->entries[idx_bar] == NULL); - assert(map->current_capacity == 1); + assert(map->current_capacity == 0); + + // Clean up map + Dowa_HashMap_Free(map); +} + +void Test_Dowa_HashMap_Cache_Folder() +{ + Dowa_PHashMap map = Dowa_HashMap_Create(100); - // Clean up remaining entries and the map itself - for (size_t i = 0; i < map->capacity; ++i) { - Dowa_PHashEntry ent = map->entries[i]; - if (ent) { - free(ent->key); - free(ent->buffer); - free(ent); - } - } - free(map->entries); - free(map); + int res = Dowa_HashMap_Cache_Folder(map, "dowa/test_folder"); + assert(res == 0 && "Folder caching should succeed"); + + const char *foo_val = (const char *)Dowa_HashMap_Get(map, "foo.txt"); + assert(foo_val != NULL); + assert(strcmp("this is foo\n", foo_val)==0); + + Dowa_HashMap_Print(map); + + Dowa_PHashMap p_bar_map = (Dowa_PHashMap)Dowa_HashMap_Get(map, "bar"); + assert(p_bar_map != NULL); + assert(strcmp("this is bar\n", (const char *)Dowa_HashMap_Get(p_bar_map, "bar.txt"))==0); + + Dowa_HashMap_Free(map); } int main(void) { @@ -95,6 +109,8 @@ TestHashMap(); printf("HashMap tests passed.\n"); + Test_Dowa_HashMap_Cache_Folder(); + printf("Test_Dowa_HashMap_Cache_Folder passed\n"); return 0; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dowa/test_folder/bar/bar.txt Sat Sep 27 16:23:04 2025 -0700 @@ -0,0 +1,1 @@ +this is bar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dowa/test_folder/foo.txt Sat Sep 27 16:23:04 2025 -0700 @@ -0,0 +1,1 @@ +this is foo
--- a/seobeo/main.c Fri Sep 26 15:14:46 2025 -0700 +++ b/seobeo/main.c Sat Sep 27 16:23:04 2025 -0700 @@ -20,25 +20,31 @@ void HandleClientRequest(Seobeo_PHandle cli) { + Dowa_PArena response_arena = Dowa_Arena_Create(8192); + if (!response_arena) + { + perror("Dowa_Arena_Initialize"); + goto clean_up; + } + size_t idx = Dowa_HashMap_GetPosition(cache, "index.html"); Dowa_PHashEntry entry = cache->entries[idx]; - - if (!entry) { + if (!entry) + { // 404 response if missing const char *not_found = - "HTTP/1.1 404 Not Found\r\n" + "HTTP/2.0 404 Not Found\r\n" "Content-Length: 0\r\n" "Connection: close\r\n" "\r\n"; send(cli->socket, not_found, strlen(not_found), 0); - Seobeo_Handle_Destroy(cli); - return; + goto clean_up; } // 3) Prepare header with the correct contentālength size_t body_size = entry->capacity; const char *template = - "HTTP/1.1 200 OK\r\n" + "HTTP/2.0 200 OK\r\n" "Content-Type: text/html\r\n" "Content-Length: %zu\r\n" "Connection: close\r\n" @@ -46,26 +52,27 @@ // Compute how large the header is and allocate just enough space int header_len = snprintf(NULL, 0, template, body_size); - char *header = malloc(header_len + 1); - if (!header) { - perror("malloc"); - return; + void *header = Dowa_Arena_Allocate(response_arena, (size_t)(header_len+1)); + if (header == NULL) + { + perror("Dowa_Arena_Allocate"); + goto clean_up; } - snprintf(header, header_len + 1, template, body_size); + snprintf((char *)header, header_len + 1, template, body_size); Seobeo_Handle_QueueData(cli, (const uint8*)header, (uint32)(header_len + 1)); - free(header); - Seobeo_Handle_QueueData(cli, (const uint8*)entry->buffer, (uint32)body_size); - + Seobeo_Handle_Flush(cli); + goto clean_up; - Seobeo_Handle_Flush(cli); - +clean_up: Seobeo_Handle_Destroy(cli); + Dowa_Arena_Free(response_arena); + return ; } int main(void) @@ -84,21 +91,26 @@ if (srv->socket < 0) return 1; printf("Listening on port 8080\n"); - sa.sa_handler = SigchildHandler; // reap all dead processes + // TODO: Use epoll or something else. + // Code from Beej's book + // Handling child processes + sa.sa_handler = SigchildHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL) == -1) { + if (sigaction(SIGCHLD, &sa, NULL) == -1) + { perror("sigaction"); exit(1); } - while (1) { + while (1) + { Seobeo_PHandle cli = Seobeo_Stream_Handle_Accept(srv); if (cli == NULL) { continue; } - printf("connected to %s\n", cli->host); + printf("client connected from %s\n", cli->host); if (!fork()) {
--- a/seobeo/seobeo.h Fri Sep 26 15:14:46 2025 -0700 +++ b/seobeo/seobeo.h Sat Sep 27 16:23:04 2025 -0700 @@ -43,16 +43,17 @@ } Sebeo_Handle, *Seobeo_PHandle; -// --- Internal? --- // +// --- Socket, IP related --- // extern int Seobeo_CreateSocket(int32 stream, const char *host, const char* port, int32 backlog); extern void *Seobeo_GetIP4OrIP6(struct sockaddr *sa); // --- TCP --- // extern Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host, const char* port); extern Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle server_h); + +// --- Helper functions --- // extern void Seobeo_Handle_Destroy(Seobeo_PHandle h); extern int Seobeo_Handle_Flush(Seobeo_PHandle h); extern int Seobeo_Handle_QueueData(Seobeo_PHandle h, const uint8_t *data, uint32_t data_size); - #endif