301 lines
6.7 KiB
C
Executable File
301 lines
6.7 KiB
C
Executable File
|
||
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <pthread.h>
|
||
|
||
|
||
#include "kvstore.h"
|
||
|
||
|
||
// Key, Value -->
|
||
// Modify
|
||
|
||
|
||
|
||
kvs_hash_t global_hash;
|
||
|
||
|
||
//Connection
|
||
// 'C' + 'o' + 'n'
|
||
static int _hash(const void *key, size_t key_len, int size) {
|
||
if (!key || size <= 0) return -1;
|
||
|
||
const uint8_t *p = (const uint8_t *)key;
|
||
uint32_t sum = 0;
|
||
for (size_t i = 0; i < key_len; i++) {
|
||
sum += p[i];
|
||
}
|
||
return sum % size;
|
||
}
|
||
|
||
static int _key_equal(const hashnode_t *node, const void *key, size_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, size_t key_len,
|
||
const void *value, size_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, size_t key_len, const void *value, size_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)) { // 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, size_t key_len, size_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, size_t key_len, const void *value, size_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 success; <0 error/noexist
|
||
*/
|
||
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, size_t key_len) {
|
||
if (!hash || !key || key_len == 0) return -2;
|
||
|
||
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
|
||
if (idx < 0) return -2;
|
||
|
||
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, size_t key_len) {
|
||
size_t vlen = 0;
|
||
void *value = kvs_hash_get_bin(hash, key, key_len, &vlen);
|
||
return value ? 0 : 1;
|
||
}
|
||
|
||
#if 0
|
||
int main() {
|
||
|
||
kvs_hash_create(&hash);
|
||
|
||
kvs_hash_set(&hash, "Teacher1", "King");
|
||
kvs_hash_set(&hash, "Teacher2", "Darren");
|
||
kvs_hash_set(&hash, "Teacher3", "Mark");
|
||
kvs_hash_set(&hash, "Teacher4", "Vico");
|
||
kvs_hash_set(&hash, "Teacher5", "Nick");
|
||
|
||
char *value1 = kvs_hash_get(&hash, "Teacher1");
|
||
printf("Teacher1 : %s\n", value1);
|
||
|
||
int ret = kvs_hash_mod(&hash, "Teacher1", "King1");
|
||
printf("mode Teacher1 ret : %d\n", ret);
|
||
|
||
char *value2 = kvs_hash_get(&hash, "Teacher1");
|
||
printf("Teacher2 : %s\n", value1);
|
||
|
||
ret = kvs_hash_del(&hash, "Teacher1");
|
||
printf("delete Teacher1 ret : %d\n", ret);
|
||
|
||
ret = kvs_hash_exist(&hash, "Teacher1");
|
||
printf("Exist Teacher1 ret : %d\n", ret);
|
||
|
||
kvs_hash_destroy(&hash);
|
||
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
|