LevelDB 源码层次上看读取过程

2023-12-01 04:18

本文主要是介绍LevelDB 源码层次上看读取过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 读取流程
    • 1)memtable查找
    • 2) immutable查找
    • 3)SSTable查找
  • 参考文献

读取流程

LevelDB的读取流程相对简单,从其中读取一个数据,会按照从上而下memtable->immutable->sstable的顺序读取,读不到就从下一个层级读取,因此LevelDB更适合读取新写入的数据。流程如下图:
在这里插入图片描述
Level0中的文件直接由Immutable通过dump产生,所以说,这一level的文件之中的key可能会相互重叠,所以需要对level0的每个文件依次查找。对于其他层次,LevelDB的归并过程保证了其中的key互相不重叠并且有序,因此可以直接使用二分方式进行数据查找。下面我们来通过代码看看这个过程:

所有发生的这一切过程,我们都可以在DBImpl::Get方法中看到,其原型如下:

Status DBImpl::Get(const ReadOptions& options, const Slice& key,std::string* value);

而读取的过程如下:

  {mutex_.Unlock();LookupKey lkey(key, snapshot);//首先在memtable查找if (mem->Get(lkey, value, &s)) {//如果没有找到就在immutable查找} else if (imm != nullptr && imm->Get(lkey, value, &s)) {} else {//最后在SSTable查找s = current->Get(options, lkey, value, &stats);have_stat_update = true;}mutex_.Lock();}

1)memtable查找

我们看到这里用来查找的key都是LookupKey这个实例化类的对象,这个类的构造函数传入一个Slice类对象key和一个SequenceNumber类的对象seq序列号。而其主要作用就是对key进行封装,让这个key带上序列号seq信息。

/*** @brief 将序列号信息s封装到user_key后面* * @param user_key key* @param s 序列号信息*/
LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {size_t usize = user_key.size();size_t needed = usize + 13;  // A conservative estimatechar* dst;//空间够用if (needed <= sizeof(space_)) {dst = space_;} else {dst = new char[needed];}//dst = [Varint32](usize+8) + [string](user_key) + [Varint64]((s<<8)|ValueType)start_ = dst;//(usize+8)dst = EncodeVarint32(dst, usize + 8);kstart_ = dst;//dst = user_keystd::memcpy(dst, user_key.data(), usize);dst += usize;//(s<<8)|ValueTypeEncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));dst += 8;end_ = dst;
}

而memtable本质上是一个跳表,所以这里再memtable上查找就是一个查找跳表的过程。查找到之后,由于跳表存储从value实际上是一个聚合怪,其格式如下:
在这里插入图片描述
我们的目标只是其中的value,所以这里的另一个主要工作就是反解析出这个value。

bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {//取出封装好的keySlice memkey = key.memtable_key();Table::Iterator iter(&table_);//memtable 搜寻key,这里其实是跳表的查找过程iter.Seek(memkey.data());if (iter.Valid()) {//找到了,格式中反解析出key的value,赋值给value// entry format is://    klength  varint32//    userkey  char[klength]//    tag      uint64//    vlength  varint32//    value    char[vlength]const char* entry = iter.key();uint32_t key_length;const char* key_ptr = GetVarint32Ptr(entry, entry + 5, &key_length);if (comparator_.comparator.user_comparator()->Compare(Slice(key_ptr, key_length - 8), key.user_key()) == 0) {// Correct user keyconst uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);switch (static_cast<ValueType>(tag & 0xff)) {case kTypeValue: {Slice v = GetLengthPrefixedSlice(key_ptr + key_length);value->assign(v.data(), v.size());return true;}case kTypeDeletion:*s = Status::NotFound(Slice());return true;}}}return false;
}

2) immutable查找

这一步和上一步其实一模一样,就不多bb了

3)SSTable查找

SSTable查找,表面上调用了Version::Get,实际上真正的逻辑在Version::ForEachOverlapping,其逻辑描述也跟我们刚刚说的查找过程一样:
在这里插入图片描述

void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,bool (*func)(void*, int, FileMetaData*)) {const Comparator* ucmp = vset_->icmp_.user_comparator();//在第0层寻找std::vector<FileMetaData*> tmp;tmp.reserve(files_[0].size());for (uint32_t i = 0; i < files_[0].size(); i++) {FileMetaData* f = files_[0][i];//这里是通过FileMetaData里面存储的每一层最大key和最小key,通过对比就知道key在不在这个文件之中if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&ucmp->Compare(user_key, f->largest.user_key()) <= 0) {//符合条件就push_backtmp.push_back(f);}}//比较所有符合条件的if (!tmp.empty()) {//这里排序的目的是找到最新的,找到就返回,后面不找了std::sort(tmp.begin(), tmp.end(), NewestFirst);for (uint32_t i = 0; i < tmp.size(); i++) {//这里调用State::Match函数,每次都会把磁盘上的SSTable打开,加载到table_cache,之后查找if (!(*func)(arg, 0, tmp[i])) {return;}}}// Search other levels.for (int level = 1; level < config::kNumLevels; level++) {size_t num_files = files_[level].size();  //获取这一层的文件数量if (num_files == 0) continue;//FindFile这里采用二分查找,找到符合条件范围的keyuint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);if (index < num_files) {FileMetaData* f = files_[level][index];if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {// All of "f" is past any data for user_key} else {//查找 返回if (!(*func)(arg, level, f)) {return;}}}}
}

参考文献

[1] LevelDB 原理解析:数据的读写与合并是怎样发生的?(在原文基础上增添内容)

这篇关于LevelDB 源码层次上看读取过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/439771

相关文章

PyInstaller打包selenium-wire过程中常见问题和解决指南

《PyInstaller打包selenium-wire过程中常见问题和解决指南》常用的打包工具PyInstaller能将Python项目打包成单个可执行文件,但也会因为兼容性问题和路径管理而出现各种运... 目录前言1. 背景2. 可能遇到的问题概述3. PyInstaller 打包步骤及参数配置4. 依赖

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

解决Java中基于GeoTools的Shapefile读取乱码的问题

《解决Java中基于GeoTools的Shapefile读取乱码的问题》本文主要讨论了在使用Java编程语言进行地理信息数据解析时遇到的Shapefile属性信息乱码问题,以及根据不同的编码设置进行属... 目录前言1、Shapefile属性字段编码的情况:一、Shp文件常见的字符集编码1、System编码

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.