diff options
Diffstat (limited to 'src/packet_storage.c')
| -rw-r--r-- | src/packet_storage.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/packet_storage.c b/src/packet_storage.c new file mode 100644 index 0000000..1094afd --- /dev/null +++ b/src/packet_storage.c @@ -0,0 +1,233 @@ +#include <pthread.h> +#include <stdint.h> +#include <stdlib.h> +// dependency: zlib +#include <zlib.h> +// +#include "common.c" + +const uint64_t max_storage = 1 << 16; + +#define hash_fmt \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + +#define hash_ref(_hash) \ + _hash[ 0 ], _hash[ 1 ], _hash[ 2 ], _hash[ 3 ], _hash[ 4 ], _hash[ 5 ], _hash[ 6 ], \ + _hash[ 7 ], _hash[ 8 ], _hash[ 9 ], _hash[ 10 ], _hash[ 11 ], _hash[ 12 ], _hash[ 13 ], \ + _hash[ 14 ], _hash[ 15 ], _hash[ 16 ], _hash[ 17 ], _hash[ 18 ], _hash[ 19 ], _hash[ 20 ], \ + _hash[ 21 ], _hash[ 22 ], _hash[ 23 ], _hash[ 24 ], _hash[ 25 ], _hash[ 26 ], _hash[ 27 ], \ + _hash[ 28 ], _hash[ 29 ], _hash[ 30 ], _hash[ 31 ] + +uint64_t current_packet_ptr = 0; +uint64_t packet_count = 0; +struct data_packet_entry { + struct data_packet packet; + uint64_t next; + uint64_t prev; + bool is_full; +}* packet_storage; + +// TODO: yes, i know it's weird, but this has to be zero +#define minus_one ((uint64_t) 0) + +struct data_packet* load_packet(FILE* file) { + if (!file) { return NULL; } + + fseek(file, 0, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (file_size == 0) { + fclose(file); + return NULL; + } + + byte comp_buf[ file_size ]; + + size_t r = fread(comp_buf, 1, file_size, file); + fclose(file); + if (r != file_size) { return NULL; } + + byte buffer[ PACKET_SIZE ]; + + uLongf dest_len = (uLongf) PACKET_SIZE; + int unres = uncompress(buffer, &dest_len, comp_buf, (uLongf) file_size); + + if (unres != Z_OK || dest_len != (uLongf) PACKET_SIZE) { return NULL; } + + bool success; + struct data_packet* packet = malloc(sizeof(struct data_packet)); + if (!packet) { return NULL; } + *packet = s2data_packet(PACKET_SIZE, buffer, &success); + + if (!success) { + free(packet); + return NULL; + } + + return packet; +} + +uint64_t set_data_packet(struct data_packet* new_packet); + +struct data_packet_entry* get_data_packet(const hash _hash) { + uint64_t hash_val; + memcpy(&hash_val, _hash, sizeof(uint64_t)); + uint64_t cur_index = hash_val % max_storage; + + pthread_mutex_lock(&packet_storage_mutex); + + struct data_packet_entry* current_entry = &packet_storage[ cur_index ]; + while (cur_index != minus_one) { + if (current_entry->is_full + && memcmp(current_entry->packet.hash, _hash, sizeof(hash)) == 0) { + pthread_mutex_unlock(&packet_storage_mutex); + return current_entry; + } + + cur_index = current_entry->next; + if (cur_index != minus_one) { current_entry = &packet_storage[ cur_index ]; } + } + + pthread_mutex_unlock(&packet_storage_mutex); + char filename[ 128 ]; + sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(_hash)); + FILE* file = fopen(filename, "rb"); + + struct data_packet* packet = load_packet(file); + + if (packet) { + uint64_t add_idx = set_data_packet(packet); + if (add_idx != minus_one) { + free(packet); + return &packet_storage[ add_idx ]; + } else { + static __thread struct data_packet_entry temp_entry; + temp_entry.packet = *packet; + free(packet); + return &temp_entry; + } + } + + return NULL; +} + +uint64_t set_data_packet(struct data_packet* new_packet) { + pthread_mutex_lock(&packet_storage_mutex); + + uint64_t hash_val; + memcpy(&hash_val, new_packet->hash, sizeof(uint64_t)); + uint64_t start_index = hash_val % max_storage; + uint64_t cur_index = start_index; + + struct data_packet_entry* current_entry = &packet_storage[ cur_index ]; + + while (true) { + if (current_entry->is_full + && memcmp(current_entry->packet.hash, new_packet->hash, sizeof(hash)) == 0) { + memcpy(¤t_entry->packet, new_packet, sizeof(struct data_packet)); + pthread_mutex_unlock(&packet_storage_mutex); + return cur_index; + } + + if (current_entry->next == minus_one) break; + cur_index = current_entry->next; + current_entry = &packet_storage[ cur_index ]; + } + + if (!current_entry->is_full) { + memcpy(¤t_entry->packet, new_packet, sizeof(struct data_packet)); + current_entry->is_full = true; + current_entry->next = minus_one; + current_entry->prev = minus_one; + packet_count++; + pthread_mutex_unlock(&packet_storage_mutex); + return cur_index; + } + + uint64_t probes = 0; + uint64_t linear_probe_index = (cur_index + 1) % max_storage; + + while (probes < max_storage) { + struct data_packet_entry* empty_slot = &packet_storage[ linear_probe_index ]; + + if (!empty_slot->is_full) { + memcpy(&empty_slot->packet, new_packet, sizeof(struct data_packet)); + empty_slot->is_full = true; + empty_slot->next = minus_one; + empty_slot->prev = cur_index; + current_entry->next = linear_probe_index; + packet_count++; + pthread_mutex_unlock(&packet_storage_mutex); + return linear_probe_index; + } + + linear_probe_index = (linear_probe_index + 1) % max_storage; + probes++; + } + + // table full + pthread_mutex_unlock(&packet_storage_mutex); + return minus_one; +} + +#define overload __attribute__((overloadable)) + +bool _delete_at_index(uint64_t index); + +overload void delete_data_packet(hash _hash) { + pthread_mutex_lock(&packet_storage_mutex); + + uint64_t hash_val; + memcpy(&hash_val, _hash, sizeof(uint64_t)); + uint64_t start_index = hash_val % max_storage; + uint64_t cur_index = start_index; + + while (cur_index != minus_one) { + struct data_packet_entry* current_entry = &packet_storage[ cur_index ]; + if (current_entry->is_full + && memcmp(current_entry->packet.hash, _hash, sizeof(hash)) == 0) { + _delete_at_index(cur_index); + pthread_mutex_unlock(&packet_storage_mutex); + return; + } + + if (current_entry->next == minus_one) { + pthread_mutex_unlock(&packet_storage_mutex); + return; + } + cur_index = current_entry->next; + } + + pthread_mutex_unlock(&packet_storage_mutex); +} + +overload void delete_data_packet(uint64_t index) { + pthread_mutex_lock(&packet_storage_mutex); + _delete_at_index(index); + pthread_mutex_unlock(&packet_storage_mutex); +} + +// caller must already have a lock! +bool _delete_at_index(uint64_t index) { + if (index >= max_storage) return false; + struct data_packet_entry* current_entry = &packet_storage[ index ]; + if (!current_entry->is_full) return false; + + if (current_entry->prev != minus_one) { + struct data_packet_entry* prev_entry = &packet_storage[ current_entry->prev ]; + prev_entry->next = current_entry->next; + } + + if (current_entry->next != minus_one) { + struct data_packet_entry* next_entry = &packet_storage[ current_entry->next ]; + next_entry->prev = current_entry->prev; + } + + current_entry->is_full = false; + current_entry->next = minus_one; + current_entry->prev = minus_one; + + return true; +} |
