文章目录
前言
本文将简单介绍KV引擎中的每个函数。
一、KV引擎介绍
本文将详细介绍使用数组、红黑树、哈希表作为底层数据存储结构来构建KV引擎。引擎这个名字看起来很厉害,但随着逐步的了解,会发现引擎原来这么简单。
该引擎由5 + 2组成,5个CRUD,2个资源管理函数。目前资源的分配和释放暂时由malloc和free组成。在下面这几节里主要介绍CRUD。
void *kvs_malloc(size_t size) {
return malloc(size);
}
void kvs_free(void *ptr) {
return free(ptr);
}
二、kvs_array
2.1 数据结构设计
typedef struct kvs_array_item_s {
char *key;
char *value;
} kvs_array_item_t;
typedef struct kvs_array_s {
kvs_array_item_t *table;
int idx;
int total;
} kvs_array_t;
第一个结构体存放键值对,第二个结构体存放数组的额外信息。采用这种方式可以比较好地表示数组信息,在未来需要扩充功能时可以在kvs_array_t中添加。
2.2 功能函数设计
// 根据数组大小分配资源,数组长度暂时取1024
int kvs_array_create(kvs_array_t *inst);
// 释放资源
void kvs_array_destory(kvs_array_t *inst);
//
int kvs_array_set(kvs_array_t *inst, char *key, char *value) {
if (inst == NULL || key == NULL || value == NULL) return -1;
if (inst->total == KVS_ARRAY_SIZE) return -1;
char *str = kvs_array_get(inst, key);
if (str) {
return 1;
}
char *kcopy = kvs_malloc(strlen(key) + 1);
if (kcopy == NULL) return -2;
memset(kcopy, 0, strlen(key) + 1);
strncpy(kcopy, key, strlen(key));
char *kvalue = kvs_malloc(strlen(value) + 1);
if (kvalue == NULL) return -2;
memset(kvalue, 0, strlen(value) + 1);
strncpy(kvalue, value, strlen(value));
int i = 0;
for (i = 0;i < inst->total;i ++) {
if (inst->table[i].key == NULL) {
inst->table[i].key = kcopy;
inst->table[i].value = kvalue;
inst->total ++;
return 0;
}
}
// 如果全满可直接开新的数组
if (i == inst->total && i < KVS_ARRAY_SIZE) {
inst->table[i].key = kcopy;
inst->table[i].value = kvalue;
inst->total ++;
}
return 0;
}
// 遍历数组找到是否存在键值为key的
char* kvs_array_get(kvs_array_t *inst, char *key);
// 先找后删除即可
int kvs_array_del(kvs_array_t *inst, char *key);
// 先找后修改
int kvs_array_mod(kvs_array_t *inst, char *key, char *value);
// 调用get即可
int kvs_array_exist(kvs_array_t *inst, char *key);
三、kvs_rbtree
3.1 数据结构设计
typedef struct _rbtree_node {
unsigned char color;
struct _rbtree_node *right;
struct _rbtree_node *left;
struct _rbtree_node *parent;
KEY_TYPE key;
void *value;
} rbtree_node;
typedef struct _rbtree {
rbtree_node *root;
rbtree_node *nil;
} rbtree;
该数据结构基本采用红黑树的设计,对于红黑树中的增删改查操作需要稍作修改,因为我们通常是使用字符串来进行存储的。
3.2 功能函数设计
// 采用红黑树存储不需要限定节点数量,当然这也意味着在每次有新节点加入时需要开辟内存
int kvs_rbtree_create(kvs_rbtree_t *inst);
// 每次找到红黑树中的最小值进行删除,时间复杂度低
void kvs_rbtree_destory(kvs_rbtree_t *inst);
// 调用rbtree_insert
int kvs_rbtree_set(kvs_rbtree_t *inst, char *key, char *value) {
if (!inst || !key || !value) return -1;
rbtree_node *node = (rbtree_node*)kvs_malloc(sizeof(rbtree_node));
node->key = kvs_malloc(strlen(key) + 1);
if (!node->key) return -2;
memset(node->key, 0, strlen(key) + 1);
strcpy(node->key, key);
node->value = kvs_malloc(strlen(value) + 1);
if (!node->value) return -2;
memset(node->value, 0, strlen(value) + 1);
strcpy(node->value, value);
rbtree_insert(inst, node);
return 0;
}
// 调用rbtree_search
char* kvs_rbtree_get(kvs_rbtree_t *inst, char *key);
// 先搜索在删除
int kvs_rbtree_del(kvs_rbtree_t *inst, char *key);
// 先所属再修改
int kvs_rbtree_mod(kvs_rbtree_t *inst, char *key, char *value);
// 调用rbtree_search
int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key);
四、kvs_hash
4.1 数据结构设计
typedef struct hashnode_s {
char key[MAX_KEY_LEN];
char value[MAX_VALUE_LEN];
struct hashnode_s *next;
} hashnode_t;
typedef struct hashtable_s {
hashnode_t **nodes; //* change *
int max_slots;
int count;
pthread_mutex_t lock;
} hashtable_t;
本哈希表采用拉链法来解决哈希冲突。
4.2 功能函数设计
// 需要分配哈希表长的空间
int kvs_hash_create(kvs_hash_t *hash);
// 逐个删除每个节点的链表
void kvs_hash_destory(kvs_hash_t *hash);
int kvs_hash_set(kvs_hash_t *hash, char *key, char *value) {
if (!hash || !key || !value) return -1;
int idx = _hash(key, MAX_TABLE_SIZE);
hashnode_t *node = hash->nodes[idx];
// 找到该节点的链表上是否已经存在key
while (node != NULL) {
if (strcmp(node->key, key) == 0) { // exist
return 1;
}
node = node->next;
}
// 新建节点
hashnode_t *new_node = _create_node(key, value);
new_node->next = hash->nodes[idx];
hash->nodes[idx] = new_node;
hash->count ++;
return 0;
}
// 先计算哈希值,再从链表中找
char * kvs_hash_get(kvs_hash_t *hash, char *key);
// 先找后改
int kvs_hash_mod(kvs_hash_t *hash, char *key, char *value);
// 先找后删
int kvs_hash_del(kvs_hash_t *hash, char *key);
// 调用get
int kvs_hash_exist(kvs_hash_t *hash, char *key);
总结
本文简单介绍了KV引擎中的每个函数,这些函数都依赖着底层数据结构。对于每个业务功能的设计通常不会有太大的性能阻碍,所以在选型时了解各个底层数据结构的性能和特点时必要的。
参考链接:
https://github.com/0voice
1166

被折叠的 条评论
为什么被折叠?



