Files
ldb/kvs_hash_bin.c
2026-01-25 10:07:11 +00:00

381 lines
8.7 KiB
C
Executable File

#include "kvstore.h"
#include "kvs_rw_tools.h"
#include "memory/alloc_dispatch.h"
#include "diskuring/diskuring.h"
// Key, Value -->
// Modify
kvs_hash_t global_hash;
//Connection
// 'C' + 'o' + 'n'
static int _hash(const void *key, uint32_t key_len, int size) {
if (!key || size <= 0) return -1;
const uint8_t *p = (const uint8_t *)key;
uint32_t sum = 0;
for (uint32_t i = 0; i < key_len; i++) {
sum += p[i];
}
return sum % size;
}
static int _key_equal(const hashnode_t *node, const void *key, uint32_t key_len) {
if (!node || !key) return 0;
if (!node->key) return 0;
if (node->key_len != key_len) return 0;
return memcmp(node->key, key, key_len) == 0;
}
static hashnode_t *_create_node(const void *key, uint32_t key_len,
const void *value, uint32_t value_len) {
hashnode_t *node = (hashnode_t*)kvs_malloc(sizeof(hashnode_t));
if (!node) return NULL;
memset(node, 0, sizeof(*node));
if (key_len > 0) {
node->key = (uint8_t*)kvs_malloc(key_len);
if (!node->key) { kvs_free(node); return NULL; }
memcpy(node->key, key, key_len);
node->key_len = key_len;
}
if (value_len > 0) {
node->value = (uint8_t*)kvs_malloc(value_len);
if (!node->value) {
kvs_free(node->key);
kvs_free(node);
return NULL;
}
memcpy(node->value, value, value_len);
node->value_len = value_len;
} else {
node->value = NULL;
node->value_len = 0;
}
node->next = NULL;
return node;
}
//
int kvs_hash_create(kvs_hash_t *hash) {
if (!hash) return -1;
hash->nodes = (hashnode_t**)kvs_malloc(sizeof(hashnode_t*) * MAX_TABLE_SIZE);
if (!hash->nodes) return -1;
memset(hash->nodes, 0, sizeof(hashnode_t*) * MAX_TABLE_SIZE);
hash->max_slots = MAX_TABLE_SIZE;
hash->count = 0;
return 0;
}
//
void kvs_hash_destroy(kvs_hash_t *hash) {
if (!hash || !hash->nodes) return;
for (int i = 0; i < hash->max_slots; i++) {
hashnode_t *node = hash->nodes[i];
while (node != NULL) {
hashnode_t *tmp = node;
node = node->next;
if (tmp->key) kvs_free(tmp->key);
if (tmp->value) kvs_free(tmp->value);
kvs_free(tmp);
}
hash->nodes[i] = NULL;
}
kvs_free(hash->nodes);
hash->nodes = NULL;
hash->max_slots = 0;
hash->count = 0;
}
// 5 + 2
// mp
/*
* @return: <0 error; 0 success; 1 exist
*/
int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
if (!hash || !hash->nodes || !key || key_len == 0) return -1;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -1;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) { // exist
return 1;
}
node = node->next;
}
hashnode_t *new_node = _create_node(key, key_len, value, value_len);
if (!new_node) return -2;
new_node->next = hash->nodes[idx];
hash->nodes[idx] = new_node;
hash->count ++;
return 0;
}
/*
* @return: NULL notexist, NOTNULL exist。out_value_len 是长度。
*/
void *kvs_hash_get_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, uint32_t *out_value_len) {
if (!hash || !hash->nodes || !key || key_len == 0 || !out_value_len) return NULL;
*out_value_len = 0;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return NULL;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) {
*out_value_len = node->value_len;
return node->value;
}
node = node->next;
}
return NULL;
}
/*
* @return <0 error; =0 success; >0 no exist
*/
int kvs_hash_mod_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -1;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) {
break;
}
node = node->next;
}
if (node == NULL) {
return 1;
}
// node -->
if (node->value) kvs_free(node->value);
node->value = NULL;
node->value_len = 0;
if (value_len > 0) {
uint8_t *vcopy = (uint8_t*)kvs_malloc(value_len);
if (!vcopy) return -2;
memcpy(vcopy, value, value_len);
node->value = vcopy;
node->value_len = value_len;
}
return 0;
}
int kvs_hash_count(kvs_hash_t *hash) {
return hash->count;
}
/*
* @return <0 error; =0 success; >0 no exist
*/
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
if (!hash || !key || key_len == 0) return -1;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -1;
hashnode_t *head = hash->nodes[idx];
if (head == NULL) return 1; // noexist
// head node
if (_key_equal(head, key, key_len)) {
hashnode_t *tmp = head->next;
hash->nodes[idx] = tmp;
if (head->key) kvs_free(head->key);
if (head->value) kvs_free(head->value);
kvs_free(head);
hash->count --;
return 0;
}
hashnode_t *cur = head;
while (cur->next != NULL) {
if (_key_equal(cur->next, key, key_len)) break; // search node
cur = cur->next;
}
if (cur->next == NULL) {
return 1;
}
hashnode_t *tmp = cur->next;
cur->next = tmp->next;
if (tmp->key) kvs_free(tmp->key);
if (tmp->value) kvs_free(tmp->value);
kvs_free(tmp);
hash->count --;
return 0;
}
/*
* @return =0 exist, =1 no exist
*/
int kvs_hash_exist_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
uint32_t vlen = 0;
void *value = kvs_hash_get_bin(hash, key, key_len, &vlen);
return value ? 0 : 1;
}
// 0 suc, <0 error
int kvs_hash_save(kvs_hash_t *inst, const char* filename){
if(!inst || !filename) return -1;
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if(fd < 0) return -2;
off_t current_off = 0;
for(int i = 0;i < inst->max_slots; ++ i){
for (hashnode_t *n = inst->nodes[i]; n != NULL; n = n->next) {
if (!n->key || n->key_len == 0) continue;
if (n->value_len > 0 && !n->value) { close(fd); return -3; }
uint32_t klen = htonl((uint32_t)n->key_len);
uint32_t vlen = htonl((uint32_t)n->value_len);
void *bufs[4];
size_t lens[4];
int count = 0;
bufs[count] = &klen;
lens[count] = sizeof(klen);
count++;
bufs[count] = &vlen;
lens[count] = sizeof(vlen);
count++;
if (n->key_len > 0){
bufs[count] = n->key;
lens[count] = n->key_len;
count++;
}
if (n->value_len > 0) {
bufs[count] = n->value;
lens[count] = n->value_len;
count++;
}
size_t total = 0;
for (int i = 0; i < count; i++) total += lens[i];
task_t *t = submit_write(&global_uring_ctx, fd, bufs, lens, count, current_off);
if (!t) { close(fd); return -4; }
int res = task_wait(t);
task_destroy(t);
if (res < 0) {
close(fd);
return -5;
}
current_off += (off_t) total;
}
}
close(fd);
return 0;
}
int kvs_hash_load(kvs_hash_t *inst, const char* filename){
if (!inst || !filename) return -1;
if (!inst->nodes || inst->max_slots <= 0) return -1;
FILE *fp = fopen(filename, "rb");
if (!fp) return -2;
while(1){
uint32_t klen_n = 0, vlen_n = 0;
if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; }
if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; }
uint32_t klen = ntohl(klen_n);
uint32_t vlen = ntohl(vlen_n);
if (klen == 0) { fclose(fp); return -3; }
uint8_t *keybuf = (uint8_t*)kvs_malloc((size_t)klen);
if (!keybuf) { fclose(fp); return -4; }
if (kvs_read_file(fp, keybuf, (size_t)klen) < 0) {
kvs_free(keybuf);
fclose(fp);
return -3;
}
uint8_t *valbuf = NULL;
if (vlen > 0) {
valbuf = (uint8_t*)kvs_malloc((size_t)vlen);
if (!valbuf) {
kvs_free(keybuf);
fclose(fp);
return -4;
}
if (kvs_read_file(fp, valbuf, (size_t)vlen) < 0) {
kvs_free(valbuf);
kvs_free(keybuf);
fclose(fp);
return -3;
}
}
int rc = kvs_hash_set_bin(inst, keybuf, klen, valbuf, vlen);
kvs_free(keybuf);
if (vlen > 0) kvs_free(valbuf);
if (rc < 0) { // error
fclose(fp);
return -5;
}
}
fclose(fp);
return 0;
}