You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ffdb/hash_index.c

211 lines
4.8 KiB
C

#include "hash_index.h"
// Submodules
#include "collections/array.h"
#include "json/json.h"
#include "json/layout.h"
#include "sha256/sha256.h"
// Stdlib
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
//#define DEBUG
#ifdef DEBUG
#define DEBUG_printf printf
#define DEBUG_fflush fflush
#else
#define DEBUG_printf(...)
#define DEBUG_fflush(...)
#endif
struct hash_index_entry
{
char* key;
int val;
};
extern struct json_field_type hash_index_entry_type;
#define OBJ_TYPE struct hash_index_entry
static struct json_object_field hash_index_entry_layout[] = {
JSON_FIELD_STRING( key, true ),
JSON_FIELD_INTEGER( val, true ),
JSON_FIELD_END
};
#undef OBJ_TYPE
static void hash_index_entry_free( struct hash_index_entry* e )
{
if( !e ) { return; }
free(e->key);
free(e);
}
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( hash_index_entry );
struct hash_index
{
struct {
struct hash_index_entry** items;
int count;
} entries;
};
static void hash_index_free_composite( struct hash_index* hi )
{
for( int i = 0; i < hi->entries.count; ++i ) {
struct hash_index_entry* entry = hi->entries.items[i];
hash_index_entry_free(entry);
}
free(hi->entries.items);
}
#define OBJ_TYPE struct hash_index
static struct json_object_field hash_index_layout[] = {
JSON_FIELD_ARRAY_OF_TYPE( entries, true, hash_index_entry_type ),
JSON_FIELD_END,
};
#undef OBJ_TYPE
bool hash_index_set( const char* index, const char* key, int value )
{
char hash[65] = "";
sha256_easy_hash_hex( key, strlen(key), hash );
hash[5] = '\0';
char filename[512];
snprintf( filename, 512, "%s/%s.json", index, hash );
struct hash_index hi;
memset( &hi, 0, sizeof(hi) );
json_read_object_layout_from_file( filename, hash_index_layout, &hi );
// Overwrite existing entries
for( int i = 0; i < hi.entries.count; ++i ) {
struct hash_index_entry* entry = hi.entries.items[i];
DEBUG_printf( "\tentry[%d] = { .key = %s, .val = %d }\n", i, entry->key, entry->val );
if( 0 == strcmp( entry->key, key ) ) {
entry->val = value;
goto exists;
}
}
DEBUG_printf( "appending\n" );
struct hash_index_entry* new_entry = NULL;
new_entry = malloc(sizeof(*new_entry));
memset(new_entry,0,sizeof(*new_entry));
new_entry->key = strdup(key);
new_entry->val = value;
array_append( &hi.entries, sizeof(new_entry), &new_entry );
exists:
json_write_object_layout_to_file( filename, "\t", hash_index_layout, &hi );
hash_index_free_composite( &hi );
return true;
}
bool hash_index_remove( const char* index, const char* key )
{
char hash[65] = "";
sha256_easy_hash_hex( key, strlen(key), hash );
hash[5] = '\0';
char filename[512];
snprintf( filename, 512, "%s/%s.json", index, hash );
struct hash_index hi;
memset( &hi, 0, sizeof(hi) );
json_read_object_layout_from_file( filename, hash_index_layout, &hi );
// Remove entry if it already exists
for( int i = 0; i < hi.entries.count; ++i ) {
struct hash_index_entry* entry = hi.entries.items[i];
DEBUG_printf( "\tentry[%d] = { .key = %s, .val = %d }\n", i, entry->key, entry->val );
if( 0 == strcmp( entry->key, key ) ) {
hash_index_entry_free( hi.entries.items[i] );
hi.entries.items[i] = hi.entries.items[ hi.entries.count - 1 ];
hi.entries.count -= 1;
goto exists;
}
}
return false;
exists:
if( hi.entries.count == 0 ) {
unlink(filename);
return true;
}
json_write_object_layout_to_file( filename, "\t", hash_index_layout, &hi );
hash_index_free_composite( &hi );
return true;
}
bool hash_index_get( const char* index, const char* key, int* value )
{
char hash[65] = "";
sha256_easy_hash_hex( key, strlen(key), hash );
hash[5] = '\0';
char filename[512];
snprintf( filename, 512, "%s/%s.json", index, hash );
struct hash_index hi;
memset( &hi, 0, sizeof(hi) );
if( !json_read_object_layout_from_file( filename, hash_index_layout, &hi ) ) {
return false;
}
/*
for( int i = 0; i < hi.entries.count; ++i ) {
struct hash_index_entry* entry = hi.entries.items[i];
printf( "\tentry[%d] = %p{ .uri = %s, .account_id = %d }\n", i, entry, entry->key, entry->val );
}
//*/
bool found = false;
*value = -1;
for( int i = 0; i < hi.entries.count; ++i ) {
struct hash_index_entry* entry = hi.entries.items[i];
if( 0 == strcmp(entry->key,key) ) {
*value = entry->val;
found = true;
}
}
hash_index_free_composite(&hi);
return found;
}
char* ffdb_hash_get_key( const char* index, int slot, int offset )
{
char* result = NULL;
char filename[512];
snprintf( filename,512, "%s/%05x.json", index, slot );
struct hash_index hi;
memset( &hi, 0, sizeof(hi) );
if( !json_read_object_layout_from_file( filename, hash_index_layout, &hi ) ) {
goto failed;
}
if( offset >= hi.entries.count ) { goto failed; }
result = strdup( hi.entries.items[offset]->key );
cleanup:
hash_index_free_composite( &hi );
return result;
failed:
free(result);
result = NULL;
goto cleanup;
}