#include #include #include // #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(const hash packet_hash) { char filename[ 128 ]; sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(packet_hash)); FILE* file = fopen(filename, "rb"); if (!file) { return NULL; } fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); if (file_size != PACKET_SIZE) { fclose(file); return NULL; } byte* buffer = malloc(file_size); if (!buffer) { fclose(file); return NULL; } size_t r = fread(buffer, 1, file_size, file); fclose(file); if (r != file_size) { free(buffer); return NULL; } bool success; struct data_packet* packet = malloc(sizeof(struct data_packet)); if (!packet) { free(buffer); return NULL; } *packet = s2data_packet(file_size, buffer, &success); free(buffer); 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(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); struct data_packet* packet = load_packet(_hash); if (packet) { uint64_t add_idx = set_data_packet(packet); if (add_idx != minus_one) { free(packet); return &packet_storage[ add_idx ]; } else { __thread static 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; }