Files
ldb/kvs_hash_bin.c

351 lines
8.4 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include "kvstore.h"
#include "kvs_rw_tools.h"
#include "mem_pool/mem_pool.h"
#include <arpa/inet.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; >0 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;
}
/*
* get 返回value 指针(由 hash 持有),并通过 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;
FILE *fp = fopen(filename, "wb");
if(!fp) return -2;
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) { fclose(fp); return -3; }
uint32_t klen = htonl((uint32_t)n->key_len);
uint32_t vlen = htonl((uint32_t)n->value_len);
if (kvs_write_file(fp, &klen, 4) < 0) { fclose(fp); return -4; }
if (kvs_write_file(fp, &vlen, 4) < 0) { fclose(fp); return -4; }
if (kvs_write_file(fp, n->key, n->key_len) < 0) { fclose(fp); return -4; }
if (n->value_len > 0) {
if (kvs_write_file(fp, n->value, n->value_len) < 0) { fclose(fp); return -4; }
}
}
}
fclose(fp);
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;
}