Changeset View
Standalone View
swh/perfecthash/hash.c
- This file was added.
#include "swh/perfecthash/hash.h" | |||||||||||||||||||
#include <sys/mman.h> | |||||||||||||||||||
#include <sys/stat.h> | |||||||||||||||||||
#include <cmph_types.h> | |||||||||||||||||||
int shard_header_load(shard_header_t *header, int fd) { | |||||||||||||||||||
if (lseek(fd, 0, SEEK_SET) < 0) { | |||||||||||||||||||
perror("lseek"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
if (read(fd, (void*)header, sizeof(shard_header_t)) < 0) { | |||||||||||||||||||
perror("read"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
return 0; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_header_reset(shard_header_t* header) { | |||||||||||||||||||
douardda: why do we need 2 versions of the same function? | |||||||||||||||||||
Done Inline ActionsThis is not strictly necessary indeed but clarifies the intent and helps me with code reading. dachary: This is not strictly necessary indeed but clarifies the intent and helps me with code reading. | |||||||||||||||||||
memset((void*)header, '\0', sizeof(shard_header_t)); | |||||||||||||||||||
return 0; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_header_save(shard_header_t *header, int fd) { | |||||||||||||||||||
if (lseek(fd, 0, SEEK_SET) < 0) { | |||||||||||||||||||
perror("seek"); | |||||||||||||||||||
Done Inline Actions
I found this better but that's just an unblocking suggestion. ardumont: I found this better but that's just an unblocking suggestion. | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
if (write(fd, (void*)header, sizeof(shard_header_t)) < 0) { | |||||||||||||||||||
perror("write"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
return 0; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_init(shard_t *shard, int fd) | |||||||||||||||||||
{ | |||||||||||||||||||
struct stat sb; | |||||||||||||||||||
if (fstat(fd, &sb) == -1) { | |||||||||||||||||||
perror("fstat"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
shard->file_size = sb.st_size; | |||||||||||||||||||
shard->addr = mmap(NULL, shard->size, PROT_READ, MAP_PRIVATE, fd, 0); | |||||||||||||||||||
if (shard->addr == NULL) { | |||||||||||||||||||
perror("mmap"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
shard_header_load(&shard->header, fd); | |||||||||||||||||||
return 0; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_uninit(shard_t *shard) { | |||||||||||||||||||
return munmap(shard->addr, shard->file_size); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_object_write(shard_t *shard, const char* object, size_t object_size, const char* key) { | |||||||||||||||||||
// save key & index to later build the hash | |||||||||||||||||||
shard_index_t* index = &shard->index[shard->index_offset]; | |||||||||||||||||||
memcpy((void*)&index->key, key, SHARD_KEY_LEN); | |||||||||||||||||||
index->object_offset = shard->object_offset; | |||||||||||||||||||
shard->index_offset++; | |||||||||||||||||||
// write the object | |||||||||||||||||||
memcpy((void*)(shard->addr + shard->object_offset), (const void*)object, object_size); | |||||||||||||||||||
shard->object_offset += object_size; | |||||||||||||||||||
} | |||||||||||||||||||
static int io_read(void *data, char **key, cmph_uint32 *keylen) { | |||||||||||||||||||
shard_t *shard = (shard_t *)data; | |||||||||||||||||||
*key = shard->index[shard->index_offset].key; | |||||||||||||||||||
*keylen = SHARD_KEY_LEN; | |||||||||||||||||||
shard->key_offset += SHARD_KEY_LEN; | |||||||||||||||||||
} | |||||||||||||||||||
static void io_dispose(void* data, char* key, cmph_uint32 keylen) { | |||||||||||||||||||
} | |||||||||||||||||||
static void io_rewind(void *data) { | |||||||||||||||||||
shard_t* shard = (shard_t*)data; | |||||||||||||||||||
shard->key_offset = 0; | |||||||||||||||||||
} | |||||||||||||||||||
static cmph_io_adapter_t *io_adapter(shard_t* shard) { | |||||||||||||||||||
cmph_io_adapter_t* key_source = (cmph_io_adapter_t*)malloc(sizeof(cmph_io_adapter_t)); | |||||||||||||||||||
if (key_source == NULL) | |||||||||||||||||||
return NULL | |||||||||||||||||||
key_source->data = (void*)shard; | |||||||||||||||||||
key_source->nkeys = shard->header.objects_count; | |||||||||||||||||||
key_source->read = io_read; | |||||||||||||||||||
key_source->dispose = io_dispose; | |||||||||||||||||||
key_source->rewind = io_rewind; | |||||||||||||||||||
return key_source; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_lookup(shard_t* shard, const char* key, char** object, size_t* object_size) { | |||||||||||||||||||
cmph_uint32 h = cmph_search(shard->hash, key, SHARD_KEY_LEN); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_hash_create(shard_t *shard) { | |||||||||||||||||||
cmph_io_adapter_t* source = io_adapter(shard); | |||||||||||||||||||
cmph_config_t* config = cmph_config_new(source); | |||||||||||||||||||
cmph_config_set_algo(config, CMPH_CHD_PH); | |||||||||||||||||||
Done Inline Actionsindentation is off. I think we miss a call to make format, don't we? ardumont: indentation is off.
I think we miss a call to `make format`, don't we? | |||||||||||||||||||
Done Inline ActionsRight :-) dachary: Right :-) | |||||||||||||||||||
// cmph_config_set_keys_per_bin | |||||||||||||||||||
// cmph_config_set_b | |||||||||||||||||||
shard->hash = cmph_new(config); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_index_save(shard_t* shard) { | |||||||||||||||||||
shard->header.index_position = shard->header.objects_position + shard->header.objects_size; | |||||||||||||||||||
cmph_uint32 count = cmph_size(shard->hash); | |||||||||||||||||||
shard->header.index_size = count * sizeof(size_t); | |||||||||||||||||||
size_t *index = (size_t*)malloc(shard->header.index_size); | |||||||||||||||||||
for (i = 0; i < shard->index_offset; i++) { | |||||||||||||||||||
cmph_uint32 h = cmph_search(shard->hash, shard->index[i].key, SHARD_KEY_LEN); | |||||||||||||||||||
index[h] = shard->index[i].object_offset; | |||||||||||||||||||
} | |||||||||||||||||||
Done Inline ActionsAre those error log messages (i see those in all C functions) destined to say as is or Note: I gather those printf instructions with those checks are actually some kind of ardumont: Are those error log messages (i see those in all C functions) destined to say as is or
is there… | |||||||||||||||||||
Done Inline ActionsThe debug messags are for debug, the printf messages are here to stay. They are designed to uniquely identify the location of the error in the source code. When arguments are provided they are also printed: they are all the information that can be provided to the user, instead of just "fail error fail" :-) In the case of this line, arguments are hardcoded and there is no gain in printing them again. Does that make sense. dachary: The **debug** messags are for debug, the **printf** messages are here to stay.
They are… | |||||||||||||||||||
Done Inline Actionsyes, it does, thanks. ardumont: yes, it does, thanks. | |||||||||||||||||||
memcpy((void*)(shard->addr + shard->header.index_position), index, shard->header.index_size); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_hash_save(shard_t* shard) { | |||||||||||||||||||
shard->header.hash_position = shard->header.index_position + shard->header.index_size; | |||||||||||||||||||
FILE* fd = fopen(path, "r+"); | |||||||||||||||||||
fseek(fd, shard->header.hash_position, SEEK_SET); | |||||||||||||||||||
cmph_dump(shard->hash, fd); | |||||||||||||||||||
fclose(fd); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_hash_load(shard_t* shard) { | |||||||||||||||||||
FILE* fd = fopen(path, "r"); | |||||||||||||||||||
fseek(fd, shard->header.hash_position, SEEK_SET); | |||||||||||||||||||
shard->hash = cmph_load(fd); | |||||||||||||||||||
fclose(fd); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_save(shard_t* shard) { | |||||||||||||||||||
if (shard_header_save() < 0) | |||||||||||||||||||
return -1; | |||||||||||||||||||
if (shard_index_save() < 0) | |||||||||||||||||||
return -1; | |||||||||||||||||||
if (shard_hash_save(shard) < 0) | |||||||||||||||||||
return -1; | |||||||||||||||||||
return 0; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_destroy(shard_t* shard) { | |||||||||||||||||||
FILE* mphf_fd = fopen(path, "a"); | |||||||||||||||||||
fseek(mphf_fd, shard->header.offset_hash); | |||||||||||||||||||
cmph_config_destroy(config); | |||||||||||||||||||
cmph_dump(hash, mphf_fd); | |||||||||||||||||||
cmph_destroy(hash); | |||||||||||||||||||
fclose(mphf_fd); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_read(shard_t *shard, char **key, cmph_uint32 *keylen) { | |||||||||||||||||||
*key = (char *)(shard->data); | |||||||||||||||||||
*keylen = (cmph_uint32)SHARD_KEY_LEN; | |||||||||||||||||||
size_t size = *(size_t *)(shard->data + SHARD_KEY_LEN); | |||||||||||||||||||
shard->offset += SHARD_KEY_LEN + sizeof(size_t) + size; | |||||||||||||||||||
} | |||||||||||||||||||
void shard_hash_rewind(shard_t *shard) { | |||||||||||||||||||
shard->offset = shard->header.hash_offset; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_keys_create(shard_t* shard, size_t keys_count) { | |||||||||||||||||||
shard->keys = (shard_key_t*)malloc(keys_count * sizeof(shard_key_t)); | |||||||||||||||||||
} | |||||||||||||||||||
int shard_keys_destroy(shard_t* shard, size_t keys_count) { | |||||||||||||||||||
free((void*)shard->keys); | |||||||||||||||||||
} | |||||||||||||||||||
shard_t* shard_load_base(char *path) { | |||||||||||||||||||
int fd = open(path, "r"); | |||||||||||||||||||
if (fd < 0) { | |||||||||||||||||||
perror("open"); | |||||||||||||||||||
return -1; | |||||||||||||||||||
} | |||||||||||||||||||
shard_t* shard = (shard_t*)malloc(sizeof(shard_t)); | |||||||||||||||||||
if (shard == NULL) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
if (shard_init(shard, fd) < 0) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
return shard; | |||||||||||||||||||
} | |||||||||||||||||||
int shard_reset(shard_t* shard) { | |||||||||||||||||||
return shard_header_reset(&shard->header); | |||||||||||||||||||
} | |||||||||||||||||||
shard_t* shard_create(char *path) { | |||||||||||||||||||
shard_t* shard = shard_load(path); | |||||||||||||||||||
if (shard == NULL) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
if (shard_reset(shard) < 0) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
return shard; | |||||||||||||||||||
} | |||||||||||||||||||
shard_t* shard_load(char *path) { | |||||||||||||||||||
shard_t* shard = shard_load(path); | |||||||||||||||||||
if (shard == NULL) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
if (shard_hash_load() < 0) | |||||||||||||||||||
return NULL; | |||||||||||||||||||
return shard; | |||||||||||||||||||
} | |||||||||||||||||||
Done Inline Actions
? ardumont: ? | |||||||||||||||||||
Done Inline ActionsI used yours 👍 dachary: I used yours 👍 | |||||||||||||||||||
Done Inline ActionsI'm rusty in c. I've only read it superficially for now. I guess that's part of "let's document it" in the earlier comment? ardumont: I'm rusty in c. I've only read it superficially for now.
That source code would definitely be… | |||||||||||||||||||
Done Inline ActionsThat looks like an unreachable statement. ardumont: That looks like an unreachable statement. | |||||||||||||||||||
Done Inline ActionsIt does :-D dachary: It does :-D |
why do we need 2 versions of the same function?