[Golang]K-V存储引擎的学习 从零实现 (RoseDB mini版本)

文章目录

  • 项目的简单介绍
    • 详情
  • 代码分析
    • 项目结构
    • db.go
    • db_file.go
    • entry.go

项目的简单介绍

mini-bitcask的学习,从零实现一个k-v存储引擎
原项目的github地址,感谢Rose大佬
mini-bitcaskrosedbmini版本,博主借此了解k-v存储,该项目通过对一个数据文件进行读写以进行简单示意,而非rosedb多个数据文件的机制,这里也提供rosedb的github地址

详情

此处为rose大佬提供的项目的相关知识的介绍,可供查阅

简而言之的话,minidb设计了数据在内存、磁盘二者中的存放,使用类似LSM的存储结构。
实现了数据PUT、GET、DELETE的功能
核心思想为利用顺序IO来提升性能。

代码分析

这里博主为了学习,由于原main.go固定流程,将其改为可自定义的流程,这里附学习项目的github地址,只对main.go进行了修改,并将数据文件的地址改到项目根目录中。

项目结构

.
├── db_file.go
├── db.go
├── db_test.go
├── entry.go
├── errors.go
├── example
│   └── main.go
├── go.mod
├── minidb.iml
└── README.md

接下来对主要部分进行注释和分析
db_file.go

db.go

定义了MiniBitcask结构体,index使用map在内存中进行key-value的存储,dbfile和dirpath是数据文件的相关信息,mu则用来进行并发的保护

type MiniBitcask struct {
	indexes map[string]int64 // 内存中的索引信息
	dbFile  *DBFile          // 数据文件
	dirPath string           // 数据目录
	mu      sync.RWMutex
}

db.go主要功能为提供数据库的集成功能创建数据库实例OPEN

实现方法写入数据PUT、取出数据GET、删除数据DEL、合并数据文件merge、关闭db实例CLOSE,也是我们主要使用的功能

实现过程从内存中获取索引exist从数据文件加载索引loadIndexesFromFile

这一部分在原文和源文件中就有代码的分析,这里不再赘述

db_file.go

该部分有关数据文件定义
DBFile结构体包括对应数据文件的句柄,以及下次写入的偏移量、

// DBFile 数据文件定义
type DBFile struct {
	File          *os.File
	Offset        int64
	HeaderBufPool *sync.Pool
}

newInternal函数创建一个DBFile实例NewDBFile创建一个新的数据文件NewMergeDBFile新建一个合并时的数据文件

func newInternal(fileName string) (*DBFile, error) {
    // 打开文件,如果不存在则创建
    file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0644)
    if err != nil {
        return nil, err
    }

    // 获取文件的状态信息,这里目的是为了获取文件的大小,以设置偏移量offset
    stat, err := os.Stat(fileName)
    if err != nil {
        return nil, err
    }

    // 创建一个对象池,用于存储 Entry 头部数据的缓冲区
    pool := &sync.Pool{New: func() interface{} {
        return make([]byte, entryHeaderSize)
    }}

    // 返回一个新的 DBFile 对象,其中包括文件的偏移量、打开的文件句柄和对象池
    return &DBFile{Offset: stat.Size(), File: file, HeaderBufPool: pool}, nil
}

DBFile实现以下方法,Read读取数据Write写入Entry

// Read 从 offset 处开始读取,在引擎初始化时,这里被循环调用
func (df *DBFile) Read(offset int64) (e *Entry, err error) {
    // 从对象池中获取一个用于存储数据的缓冲区
    buf := df.HeaderBufPool.Get().([]byte)
    defer df.HeaderBufPool.Put(buf) // 确保在函数返回时将缓冲区归还给对象池

    // 从文件中读取数据到缓冲区
    if _, err = df.File.ReadAt(buf, offset); err != nil {
        return
    }

    // 解码缓冲区中的数据为 Entry 对象
    if e, err = Decode(buf); err != nil {
        return
    }

    // 计算键和值在文件中的偏移量,并读取键和值的数据
    offset += entryHeaderSize // 将偏移量移到键值对数据开始的位置

    // 如果键的大小大于 0,则读取键的数据
    if e.KeySize > 0 {
        key := make([]byte, e.KeySize) // 创建一个存储键数据的切片
        if _, err = df.File.ReadAt(key, offset); err != nil {
            return
        }
        e.Key = key // 将读取的键数据赋值给 Entry 对象
    }

    // 更新偏移量,准备读取值的数据
    offset += int64(e.KeySize) // 将偏移量移到值数据开始的位置

    // 如果值的大小大于 0,则读取值的数据
    if e.ValueSize > 0 {
        value := make([]byte, e.ValueSize) // 创建一个存储值数据的切片
        if _, err = df.File.ReadAt(value, offset); err != nil {
            return
        }
        e.Value = value // 将读取的值数据赋值给 Entry 对象
    }

    // 返回读取的 Entry 对象及可能的错误
    return
}

write方法的实现可以参考read

entry.go

Entry定义这里的一条记录,该包即为如何包装一条记录
一条entry包括key、value的值和大小标志位mark

// Entry 写入文件的记录
type Entry struct {
	Key       []byte
	Value     []byte
	KeySize   uint32
	ValueSize uint32
	Mark      uint16
}

NewEntry根据传入的参数返回一条Entry实例
并实现了Entry的编码Encode解码Decode 方法
encode定义了entry编码的顺序,decode可以参考这部分

// Encode 编码 Entry,返回字节数组
func (e *Entry) Encode() ([]byte, error) {
	buf := make([]byte, e.GetSize())
	binary.BigEndian.PutUint32(buf[0:4], e.KeySize)
	binary.BigEndian.PutUint32(buf[4:8], e.ValueSize)
	binary.BigEndian.PutUint16(buf[8:10], e.Mark)
	copy(buf[entryHeaderSize:entryHeaderSize+e.KeySize], e.Key)
	copy(buf[entryHeaderSize+e.KeySize:], e.Value)
	return buf, nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/464432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫与数据可视化源码免费领取

引言 作为一名在软件技术领域深耕多年的专业人士,我不仅在软件开发和项目部署方面积累了丰富的实践经验,更以卓越的技术实力获得了🏅30项软件著作权证书的殊荣。这些成就不仅是对我的技术专长的肯定,也是对我的创新精神和专业承诺…

腾讯云2核2G免费服务器申请流程,2024免费服务器入口

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM,轻量配置可选2核2G3M、2核8G7M和4核8G12M,CVM云服务器可选2核2G3M和2核4G3M配置,腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

深度学习 精选笔记(13.2)深度卷积神经网络-AlexNet模型

学习参考: 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增),以达到集多方教程的精华于一文的目的。 ③非常推荐上面(学习参考&#x…

【C++刷题】优选算法——动态规划第一辑

1.状态表示是什么?简答理解是dp表里的值所表示的含义怎么来的?题目要求经验题目要求分析问题的过程中,发现重复子问题 2.状态转移方程dp[i]......细节问题:3.初始化控制填表的时候不越界4.填表顺序控制在填写当前状态的时候&#…

【S5PV210_视频编解码项目】裸机开发:实现按键的外部中断处理

加粗样式本文所作内容: 基于S5PV210芯片实现按键的外部中断处理程序,搭建中断处理流程框架 S5PV210对于中断处理的操作流程 1 外部中断得到触发: 1)外部中断在初始化阶段得到使能 2)外界达到了外部中断的触发条件 …

手机网络连接性能API接口:查询手机网络连接性能状态

手机在网状态查询服务是一项非常方便的服务,可以帮助我们随时了解一个手机号码的在网状态。不论是查询自己的手机号码,还是查询他人的手机号码,这个服务都可以帮助我们获取准确的信息。今天,我想和大家介绍一个非常好用的手机在网…

运用html相关知识编写导航栏和二级菜单

相关代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

30.HarmonyOS App(JAVA)鸿蒙系统app多线程任务分发器

HarmonyOS App(JAVA)多线程任务分发器 打印时间&#xff0c;记录到编辑框textfield信息显示 同步分发&#xff0c;异步分发&#xff0c;异步延迟分发&#xff0c;分组任务分发&#xff0c;屏蔽任务分发&#xff0c;多次任务分发 参考代码注释 场景介绍 如果应用的业务逻辑比…

【技术类-04】python实现docx表格文字和段落文字的“手动换行符(软回车)”变成“段落标记(硬回车)”

作品展示&#xff1a; 背景需求&#xff1a; 把python实现docx表格文字和段落文字的“手动换行符&#xff08;软回车&#xff09;”变成“段落标记&#xff08;硬回车&#xff09;合并在一起统计数量 【技术类-02】python实现docx段落文字的“手动换行符&#xff08;软回车&a…

Prometheus 轻量化部署和使用

文章目录 说明Prometheus简介Grafana简介prometheus和Grafana的关系环境准备&#xff08;docker&#xff09;docker安装时间时区问题&#xff08;我的代码中&#xff09;dockers镜像加速和服务器时区设置 数据库准备(mysql、redis)mysql配置redis配置 Prometheus、grafana下载和…

4-如何进行细分市场分析-03 竞争者分析

任何一个行业肯定都是有很多竞争者&#xff0c;我们如何判断这些竞争者对我们有什么样的威胁、什么样的机会、什么样的影响&#xff0c;我们需要去分析这些竞争者。 行业竞争格局如何分析&#xff1f; 我们可以从一些基本指标来入手&#xff0c;如市场集中度、行业利润率。 竞…

Win10系统使用IIS服务搭建WebDAV网站结合内网穿透公网访问本地文件

文章目录 推荐1. 安装IIS必要WebDav组件2. 客户端测试3. cpolar内网穿透3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功总结&#xff1a; 推荐 前些天发现了一个巨牛的人工智能…

短剧小程序软件开发首页接口转发到Selectpage

工具&#xff1a;用的是uniapp开发 技术栈&#xff1a;vue、nide..js、云开发 用时&#xff1a;20工作天 软件&#xff1a;Hb、微信开发者工具 <?php namespace app\api\controller; use app\common\controller\Api; /** * 首页接口 */ class Index extends Api { …

算法思想总结:滑动窗口算法

创作不易&#xff0c;感谢三连 一.长度最小的数组 . - 力扣&#xff08;LeetCode&#xff09;长度最小的数组 class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {int lenINT_MAX,nnums.size(),sum0;//len必须要给一个很大的数&#xf…

【LeetCode每日一题】2684. 矩阵中移动的最大次数

文章目录 [2684. 矩阵中移动的最大次数](https://leetcode.cn/problems/maximum-number-of-moves-in-a-grid/)思虑&#xff1a;代码&#xff1a; 2684. 矩阵中移动的最大次数 思虑&#xff1a; 1.将第一列的所有行坐标&#xff0c;用IntStream 来生成一个范围 [0, m) 内的整数…

reloading,一个很实用的Python库!

Python是一门非常流行的编程语言&#xff0c;它的广泛应用和丰富的第三方库使得开发者们能够轻松完成各种任务。reloading是Python中一个强大的库&#xff0c;它能够在程序运行时重新加载修改过的模块&#xff0c;为开发者提供了便利和灵活性。本文将全面介绍reloading库&#…

警惕MKP勒索病毒,您需要知道的预防和恢复方法。

引言&#xff1a; 在网络世界中&#xff0c;.mkp勒索病毒是一股威胁不可小觑的黑暗势力。它以其毒辣的加密手段威胁着我们的数据安全。本文将深入介绍.mkp勒索病毒&#xff0c;揭示如何恢复被其加密的数据文件&#xff0c;并分享一些预防措施&#xff0c;助您在数字世界中安全…

整数和浮点数在内存中存储及题目

一、整数在内存中存储 整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码。三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&#xff0c;⽤1表⽰“负”&#xff0c;⽽数值位最⾼位的⼀位是被当做符号位&#xff0c;剩余的都是数值位 正整数…

使用ChatGPT高效完成简历制作[中篇]-有爱AI实战教程(五)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 导读&#xff1a;在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#xff0c;如果没…

【JS进阶】第一天

参考视频——黑马程序员 JavaScript 进阶 - 第 1 天 学习作用域、变量提升、闭包等语言特征&#xff0c;加深对 JavaScript 的理解&#xff0c;掌握变量赋值、函数声明的简洁语法&#xff0c;降低代码的冗余度。 理解作用域对程序执行的影响能够分析程序执行的作用域范围理解闭…
最新文章