Get

LevelDB提供了Get接口用于给定key的查找:

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

Get操作可以指定在某个snapshot的情况下进行,如果指定了snapshot,则获取该snapshot的sequencenumber,如果没有指定snapshot,就取当前最新的sequencenumber:

    Status s;
    MutexLock l(&mutex_);
    SequenceNumber snapshot;
    if (options.snapshot != nullptr)
    {
        snapshot =
            static_cast<const SnapshotImpl *>(options.snapshot)->sequence_number();
    }
    else
    {
        snapshot = versions_->LastSequence();
    }

    MemTable *mem = mem_;
    MemTable *imm = imm_;
    Version *current = versions_->current();
    mem->Ref();
    if (imm != nullptr)
        imm->Ref();
    current->Ref();

首先在memtable里找,如果找到了就结束查找,然后再immutable memtable里找(如果immutable memtable存在),如果找到了就结束查找,在这两个地方查找使用的都是MemTable类提供的Get接口函数(在这里有分析https://www.cnblogs.com/YuNanlong/p/9426795.html)。最后使用Version类提供的Get接口函数在sstable中查找:

    // Unlock while reading from files and memtables
    {
        mutex_.Unlock();
        // First look in the memtable, then in the immutable memtable (if any).
        LookupKey lkey(key, snapshot);
        if (mem->Get(lkey, value, &s))
        {
            // Done
        }
        else if (imm != nullptr && imm->Get(lkey, value, &s))
        {
            // Done
        }
        else
        {
            s = current->Get(options, lkey, value, &stats);
            have_stat_update = true;
        }
        mutex_.Lock();
    }

如果在sstable中查找了,会更新查找涉及到的sstable的seek次数,可能会触发compact条件,因此需要调用MaybeScheduleCompaction函数进行可能的compact操作(在这里有分析https://www.cnblogs.com/YuNanlong/p/9440548.html):

    if (have_stat_update && current->UpdateStats(stats))
    {
        MaybeScheduleCompaction();
    }
    mem->Unref();
    if (imm != nullptr)
        imm->Unref();
    current->Unref();
    return s;

接下来分析Version类封装的Get函数:

Status Version::Get(const ReadOptions &options,
                    const LookupKey &k,
                    std::string *value,
                    GetStats *stats)

首先是一些变量必要的初始化:

    Slice ikey = k.internal_key();
    Slice user_key = k.user_key();
    const Comparator *ucmp = vset_->icmp_.user_comparator();
    Status s;

    stats->seek_file = nullptr;
    stats->seek_file_level = -1;
    FileMetaData *last_file_read = nullptr;
    int last_file_read_level = -1;

    // We can search level-by-level since entries never hop across
    // levels.  Therefore we are guaranteed that if we find data
    // in an smaller level, later levels are irrelevant.
    std::vector<FileMetaData *> tmp;
    FileMetaData *tmp2;

在每一层中搜索:

    for (int level = 0; level < config::kNumLevels; level++)
    {

如果该level没有文件则直接跳过:

        size_t num_files = files_[level].size();
        if (num_files == 0)
            continue;

如果当前位于level0,将所有可能包含key的文件都加入files中:

        // Get the list of files to search in this level
        FileMetaData *const *files = &files_[level][0];
        if (level == 0)
        {
            // Level-0 files may overlap each other.  Find all files that
            // overlap user_key and process them in order from newest to oldest.
            tmp.reserve(num_files);
            for (uint32_t i = 0; i < num_files; i++)
            {
                FileMetaData *f = files[i];
                if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
                    ucmp->Compare(user_key, f->largest.user_key()) <= 0)
                {
                    tmp.push_back(f);
                }
            }
            if (tmp.empty())
                continue;

            std::sort(tmp.begin(), tmp.end(), NewestFirst);
            files = &tmp[0];
            num_files = tmp.size();
        }

如果当前不是level0,则调用FindFile进行二分查找,找到file后验证要找的key是不是在file中,如果是,加入files:

        else
        {
            // Binary search to find earliest index whose largest key >= ikey.
            uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);
            if (index >= num_files)
            {
                files = nullptr;
                num_files = 0;
            }
            else
            {
                tmp2 = files[index];
                if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0)
                {
                    // All of "tmp2" is past any data for user_key
                    files = nullptr;
                    num_files = 0;
                }
                else
                {
                    files = &tmp2;
                    num_files = 1;
                }
            }
        }

遍历找到的files,如果seek的文件不止一个,则记录下第一个seek的文件,之后要将这个文件的seek减一(调用UpdateStats函数):

        for (uint32_t i = 0; i < num_files; ++i)
        {
            if (last_file_read != nullptr && stats->seek_file == nullptr)
            {
                // We have had more than one seek for this read.  Charge the 1st file.
                stats->seek_file = last_file_read;
                stats->seek_file_level = last_file_read_level;
            }

            FileMetaData *f = files[i];
            last_file_read = f;
            last_file_read_level = level;

调用table_cache_->Get函数在文件中搜索key值,如果没有找到,则继续搜索下一个file,如果找到了,不论是删除的还是过期的,都返回(因为之后就算找到了key,也比现在的key旧,被现在的key覆盖):

            Saver saver;
            saver.state = kNotFound;
            saver.ucmp = ucmp;
            saver.user_key = user_key;
            saver.value = value;
            s = vset_->table_cache_->Get(options, f->number, f->file_size,
                                         ikey, &saver, SaveValue);
            if (!s.ok())
            {
                return s;
            }
            switch (saver.state)
            {
            case kNotFound:
                break; // Keep searching in other files
            case kFound:
                return s;
            case kDeleted:
                s = Status::NotFound(Slice()); // Use empty error message for speed
                return s;
            case kCorrupt:
                s = Status::Corruption("corrupted key for ", user_key);
                return s;
            }
        }

230 Love u

LevelDB源码分析-Get的更多相关文章

  1. leveldb源码分析--SSTable之block

    在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...

  2. leveldb源码分析--WriteBatch

    从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批 ...

  3. leveldb源码分析--Key结构

    [注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...

  4. Leveldb源码分析--1

    coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...

  5. leveldb源码分析--日志

    我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析 ...

  6. leveldb源码分析之Slice

    转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...

  7. LevelDB源码分析--Cache及Get查找流程

    本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...

  8. leveldb源码分析--SSTable之TableBuilder

    上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...

  9. leveldb源码分析之内存池Arena

    转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...

  10. 【转】Leveldb源码分析——1

    先来看看Leveldb的基本框架,几大关键组件,如图1-1所示. Leveldb是一种基于operation log的文件系统,是Log-Structured-Merge Tree的典型实现.LSM源 ...

随机推荐

  1. 剑指Offer 37. 数字在排序数组中出现的次数 (数组)

    题目描述 统计一个数字在排序数组中出现的次数. 题目地址 https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId ...

  2. 关于使用JPA中@Query注解传递表名/视图名参数的问题

    因碰到需要动态查询不同视图的结果,自己尝试使用@Query注解中传递视图名称参数: @Query("select * from ?1") List<Object> ge ...

  3. 【数据库(一)】SQL语言-表定义、查询

    基本模式定义+ SQL支持许多不同的完整性约束. not null, 在该属性上不允许空值 primary key 是否是是主码,主码必须非空且唯一 foreign key check(P),P是谓词 ...

  4. JS 验证字符串是否为空

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Vue列表组件与弹窗组件示例

    列表组件 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <me ...

  6. openstack--9--深入理解虚拟机

    登录计算节点查看进程 [root@linux-node2 ~]# ps aux | grep kvm root 824 0.0 0.0 0 0 ? S< 10:19 0:00 [kvm-irqf ...

  7. JAVA AES CBC 加密 解密

    AES 256 , KEY 的长度为 32字节(32*8=256bit). AES 128 , KEY 的长度为 16字节(16*8=128bit) CBC 模式需要IV, IV的值是固定写死,还是当 ...

  8. Azure VMSS (2) 对VM执行Generalize操作

    <Windows Azure Platform 系列文章目录> 在本章中,笔者将介绍如何创建Azure Template镜像模板. 1.首先,我们先创建1台Windows Server 2 ...

  9. Java8-dateTimeFormatter

    时间格式化LocalDate,DateTimeFormatter--->parse,ofParttern 伴随lambda表达式.streams以及一系列小优化,Java 8 推出了全新的日期时 ...

  10. java基础-反射(细节)

    java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...