分布式KV存储的实现

目录

一、KV 存储的核心设计哲学

1. 键值对的本质

2. 存储引擎的黑魔法

3. 分布式扩展的奥秘

二、KV 存储的核心模块

1.reactor/ntyco/io_uring

2.协议层kv-store

3.数据结构rbtree/array/hash

4.内存池mp_pool

5.测试用例test_case

三、部分源码细究


一、KV 存储的核心设计哲学

1. 键值对的本质

KV 存储的核心是将数据抽象为键值对(Key-Value Pair)。键作为唯一标识符,值则承载任意格式的数据。这种设计摒弃了传统关系型数据库的复杂表结构,将数据存储简化为 “键→值” 的映射,从而实现了 O (1) 级别的读写效率。

2. 存储引擎的黑魔法

主流 KV 存储(如 Redis、RocksDB)采用哈希表或跳表等数据结构,结合内存与磁盘分层存储:

内存型(如 Redis):将数据常驻内存,通过异步持久化保证可靠性。

持久化型(如 LevelDB):数据写入磁盘,利用 LSM-Tree 结构优化读写性能。

3. 分布式扩展的奥秘

分布式 KV 存储(如 DynamoDB)通过一致性哈希、分片(Sharding)和复制(Replication)实现水平扩展:

分片:将数据分散到多个节点,避免单点瓶颈。

复制:每个分片保留多个副本,确保高可用性。

二、KV 存储的核心模块

1.reactor/ntyco/io_uring

2.协议层kv-store

3.数据结构rbtree/array/hash

4.内存池mp_pool

5.测试用例test_case

三、部分源码细究


#include"kvstore.h"

#define KVSTORE_MAX_TOKEN 128

const char*commands[]={
    "SET","GET","DEL","MOD","COUNT",
    "RSET","RGET","RDEL","RMOD","RCOUNT",
    "HSET","HGET","HDEL","HMOD","HCOUNT",
    
};

enum{
    KV_CMD_START= 0,
    KV_CMD_SET=KV_CMD_START,
    KV_CMD_GET,
    KV_CMD_DEL,
    KV_CMD_MOD,
    KV_CMD_COUNT,

    KV_CMD_RSET,
    KV_CMD_RGET,
    KV_CMD_RDEL,
    KV_CMD_RMOD,
    KV_CMD_RCOUNT,

    KV_CMD_HSET,
    KV_CMD_HGET,
    KV_CMD_HDEL,
    KV_CMD_HMOD,
    KV_CMD_HCOUNT,
    KV_CMD_SIZE,
};


void  *kvstore_malloc(size_t size){
    #if ENABLE_MEM_POOL
    char *ptr = mp_allock(&M);
    #else
    return malloc(size);
    #endif
}

void kvstore_free(void *ptr){
    #if ENABLE_MEM_POOL

    #else
    return free(ptr);
    #endif
}

#if ENABLE_RBTREE_KVENGINE
int kvstore_rbtree_set(char *key, char *value){
    return kvs_rbtree_set(&Tree, key, value);
}
char* kvstore_rbtree_get( char *key){
    return kvs_rbtree_get(&Tree,key);

}
int kvstore_rbtree_delete( char *key){
    return kvs_rbtree_delete(&Tree,key);
}
int kvstore_rbtree_modify( char *key, char *value){
    return kvs_rbtree_modify(&Tree,key,value);
}

int kvstore_rbtree_count(){
    return kvs_rbtree_count(&Tree);
}
#endif


#if ENABLE_ARRAY_KVENGINE
int kvstore_array_set(char *key,char *value){
    return kvs_array_set(&Array,key,value);
}

char *kvstore_array_get(char*key){
    return kvs_array_get(&Array,key);
}

int kvstore_array_del(char*key){
   return kvs_array_del(&Array,key);
}

int kvstore_array_mod(char*key,char*value){
    return kvs_array_mod(&Array,key,value);
}

int kvstore_array_count(){
    return kvs_array_count(&Array);
}

#endif


#if ENABLE_HASH_KVENGINE
int kvstore_hash_set(char *key,char *value){
    return kvs_hash_set(&Hash,key,value);
}

char *kvstore_hash_get(char*key){
    return kvs_hash_get(&Hash,key);
}

int kvstore_hash_del(char*key){
   return kvs_hash_delete(&Hash,key);
}

int kvstore_hash_mod(char*key,char*value){
    return kvs_hash_modify(&Hash,key,value);
}

int kvstore_hash_count(){
    return kvs_hash_count(&Hash);
}

#endif


int kvstore_split_token(char*msg,char**tokens){
    if(msg==NULL || tokens==NULL) return -1;

    int idx = 0;
    char *token = strtok(msg," ");
    while(token!=NULL){
        tokens[idx++]=token;
        token = strtok(NULL," ");
    }

    return idx;
}

int kvstore_parser_protocol(struct conn_item*item,char**tokens,int count){
    if(item==NULL||tokens[0]==NULL||count==0) return  -1;
    int cmd = KV_CMD_START;
    for(cmd=KV_CMD_START;cmd<KV_CMD_SIZE;cmd++){
        if(strcmp(commands[cmd],tokens[0])==0) break;
    }


    char*msg=item->wbuffer;
    char*key = tokens[1];
    char*value =tokens[2];
    
    memset(msg,0,BUFFER_LENGTH);

    switch(cmd){
        case KV_CMD_SET:{
        int res=kvstore_array_set(key,value);
        if(res==0){
            snprintf(msg,BUFFER_LENGTH,"SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"FAILED");
        }
        break;
    }

        case KV_CMD_GET:{
        char *values=kvstore_array_get(key);
        if(values!=NULL){
            snprintf(msg,BUFFER_LENGTH,"%s",values);
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }

        //printf("get:%s\n",values);
        break;
    }

        case KV_CMD_DEL:{
        //printf("del\n");
        int res =kvstore_array_del(key);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
    }

        case KV_CMD_MOD:{
        //printf("mod\n");
        int res =kvstore_array_mod(key,value);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
    }
      case KV_CMD_COUNT:{
        int count =kvs_array_count(&Array);
        if(count<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else{
            snprintf(msg,BUFFER_LENGTH,"%d",count);
        }
        break;
      }

      case KV_CMD_RSET:{
        int res=kvstore_rbtree_set(key,value);
        if(res==0){
            snprintf(msg,BUFFER_LENGTH,"SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"FAILED");
        }
        break;
      }

      case KV_CMD_RGET:{
        char*values=kvstore_rbtree_get(key);
        if(values!=NULL){
            snprintf(msg,BUFFER_LENGTH,"%s",values);
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
      }

      case KV_CMD_RDEL:{
        int res =kvstore_rbtree_delete(key);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
      }

      case KV_CMD_RMOD:{
        int res=kvstore_rbtree_modify(key,value);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
      }

      case KV_CMD_RCOUNT:{
        int count =kvstore_rbtree_count();
        if(count<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else{
            snprintf(msg,BUFFER_LENGTH,"%d",count);
        }
        break;
      }


      case KV_CMD_HSET:{
        int res=kvstore_hash_set(key,value);
        if(res==0){
            snprintf(msg,BUFFER_LENGTH,"SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"FAILED");
        }
        break;
      }

      case KV_CMD_HGET:{
        char*values=kvstore_hash_get(key);
        if(values!=NULL){
            snprintf(msg,BUFFER_LENGTH,"%s",values);
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
      }

      case KV_CMD_HDEL:{
        int res =kvstore_hash_del(key);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
      }

      case KV_CMD_HMOD:{
        int res=kvstore_hash_mod(key,value);
        if(res<0){
            snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
        }else if(res==0){
            snprintf(msg,BUFFER_LENGTH,"%s","SUCCESS");
        }else{
            snprintf(msg,BUFFER_LENGTH,"NO EXIST");
        }
        break;
    }
        

        case KV_CMD_HCOUNT:{
            int count =kvstore_hash_count();
            if(count<0){
                snprintf(msg,BUFFER_LENGTH,"%s","ERROR");
            }else{
                snprintf(msg,BUFFER_LENGTH,"%d",count);
            }
        
        break;
      }

        default:{
        //printf("cmd%s\n",commands[cmd]);
        assert(0);
        }
    }
    
}

int kvstore_requese(struct conn_item*item){
    //printf("recv: %s\n",item->rbuffer);

    char * msg = item->rbuffer;
    char *tockens[KVSTORE_MAX_TOKEN];

    int count = kvstore_split_token(msg,tockens);

    int idx;
    for(idx =0;idx<count;idx++){
        //printf("idx:%s\n",tockens[idx]);
    }

    kvstore_parser_protocol(item,tockens,count);

    return 0; 
}

int init_kvengine(void){
    #if  ENABLE_ARRAY_KVENGINE
    kvstore_array_create(&Array);
    #endif

    #if ENABLE_RBTREE_KVENGINE
    kvstore_rbtree_create(&Tree);
    #endif

    #if ENABLE_HASH_KVENGINE
    kvstore_hash_create(&Hash);
    #endif
}

int exit_kvengine(void){
    #if  ENABLE_ARRAY_KVENGINE
    kvstore_array_destory(&Array);
    #endif

    #if ENABLE_RBTREE_KVENGINE
    kvstore_rbtree_destory(&Tree);
    #endif

    #if ENABLE_HASH_KVENGINE
    kvstore_hash_destory(&Hash);
    #endif
}

int init_pool(void){
    #if ENABLE_MEM_POOL
    mp_init(&M,4096);
    #endif
}

int destory_pool(void){
    #if ENABLE_MEM_POOL
    mp_dest(&M);
    #endif
}


int main(){

    init_kvengine();
    init_pool();

#if (ENABLE_NETWORK_SELECT==NETWORK_EPOLL)
     epoll_entry();
#elif(ENABLE_NETWORK_SELECT==NETWORK_NTYCO)
     ntyco_enrty();
#elif(ENABLE_NETWORK_SELECT==NETWORK_IOURING)

#endif

    exit_kvengine();
    destory_pool();
    
}

这些是对外用户封装的接口

①设置命令对应

②开辟内存和释放内存的接口 可以兼容内存池

③对接红黑叔 数组 哈希的接口

④分割函数strtok的使用

⑤制定协议的接口

⑥接收数据的接口

⑦选择数据结构的接口

⑧释放资源的接口

⑨定义和销毁内存池的接口

⑩main函数一切的起点

内存池的介绍和复习

#include<stdlib.h>
#include<stdio.h>
#include"kvstore.h"
#define MEM_PAGE_SIZE 4096

typedef struct mempool_s{
	int block_size;
	int free_count;

	char*free_ptr;
	char*mem;
}mempool_t;

//内存池的初始化
int mp_init(mempool_t*m,int size){
	if(m==NULL) return -1;
	if(size<16) size=16;
	
	m->block_size=size;//固定大小的内存块
	m->mem=(char*)malloc(MEM_PAGE_SIZE);
	if(m->mem==NULL) return -2;

	m->free_ptr=m->mem;
	m->free_count=MEM_PAGE_SIZE/size;

	int i =0;
	char*ptr= m->free_ptr;
	for(i;i<m->free_count;i++){
		*(char**)ptr=ptr+size;//☆
		ptr+=size;
	}
	*(char**)ptr=NULL;
}

//内存池的销毁
void mp_dest(mempool_t*m){
	if(m==NULL||m->mem==NULL) return;
	free(m->mem);
}

//为内存块分配内存
void * mp_allock(mempool_t*m){
	if(m==NULL||m->free_count==0) return NULL;
	void*ptr =m->free_ptr;//ptr指向一块空闲的内存

	m->free_ptr=*(char**)ptr;//m->free_ptr指向下一块空闲的内存 ☆
	m->free_count--;
	
	return ptr;
}

//为内存块释放内存
void mp_free(mempool_t*m,void*ptr){
	*(char**)ptr=m->free_ptr;
	m->free_ptr=(char*)ptr;
	m->free_count++;
}

mempool_t M;


#if 0
int main(){
	mempool_t m;
    mp_init(&m,32);
	

	void *p1 =mp_allock(&m);
	printf("1:mp_alloc:%p\n",p1);

	void *p2 =mp_allock(&m);
	printf("2:mp_alloc:%p\n",p2);

	void *p3 =mp_allock(&m);
	printf("3:mp_alloc:%p\n",p3);

	void *p4 =mp_allock(&m);
	printf("4:mp_alloc:%p\n",p4);

	mp_free(&m,p2);

	void *p5 =mp_allock(&m);
	printf("5:mp_alloc:%p\n",p5);

}

#endif

//对内存块的管理
//1.避免频繁分配
//2.长期运行出现的内存碎片

①内存池结构体

block_size

内存块的大小

free_count

空闲的内存块

free_ptr

指向空闲内存块的指针

mem

开辟内存页的大小

②内存池的初始化

内存块大小设置为size

开辟的内存页大小设置为MEM_PAGE_SIZE

空闲指针free_ptr 指向开头

空闲内存块的数量为m->free_count=MEM_PAGE_SIZE/size

通过for循环生成一串链表

③内存池的销毁

④为内存块分配内存

⑤为内存块释放内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值