【KV存储(3)】KV引擎详细设计


前言

本文将简单介绍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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值