我们先来参考来至使用Iterator简化代码2-TwoLevelIterator的例子,略微修改希望能帮助更加容易立即,如果有不理解请各位看客阅读原文。

下面我们再来看一个例子,我们为一个书店写程序,书店里有许多书Book,每个书架(BookShelf)上有多本书。

类结构如下所示

class Book {
private:
string book_name_;
};
class Shelf {
private:
vector<Book> books_;
};

如何遍历书架上所有的书呢?一种实现方法是:

vector<Book>& GetBooks() const {
return books_;
}
 

这样的实现暴漏了内部太多的细节,调用者根本就不需要知道Shelf存储Book的方式,仅仅需要遍历所有的数据即可。而且这样当我们换用另外一种数据结构存储Book时,客户端的代码就需要进行修改。但是如果使用Iterator模式则没有这个问题。具体的我们需要遍历书店中所有的书,现在应该如何实现呢?

一种实现方式是,由BookStore负责保存中间状态,包括当前遍历到了哪个书架,遍历到了书架上的那本书。

// 书店类
class BookStore {
Iterator* NewIterator() const;
private:
vector<Shelf> shelf_;
vector<Shelf>::iterator shelf_iter_;
vector<Book>::iterator book_iter_;
};

这种实现方法对外是干净的,但是对于BookStore的维护者来说却是不友好的,Iterator的中间状态不是BookStore的成员,逻辑上不应该由BookStore维护。而且当两个甚至多个用户同时遍历书店时BookStore得同时维护多个中间状态,极其容易出错。更好的一种实现方式是,把遍历Iterator相关的代码和状态封装成一个类,有两个层级Shelf 和 Book,这个类的名字我们叫做TwoLevelIteator.

class TwoLevelIterator: public Iterator {
vector<Shelf>::iterator shelf_iter_;
vector<Book>::iterator book_iter_;
void SeekToFirst() {
shelf_iter_.SeekToFirst();
if (shelf_iter_.iter() != NULL) book_iter_.SeekToFirst();
}
void TwoLevelIterator::Next() {
if (book_iter_ == shelf_iter_.end())
{
shelf_iter_.Next();
book_iter_.SeekToFirst();
}else{
book_iter_.Next();
}
}

这里只是作一个简单的示例过程,具体代码暂时不列出,如果以后有空进行整理的时候可以列一个完整的代码。

了解了这个基本原理以后,我们来看leveldb 中的

class TwoLevelIterator: public Iterator {
BlockFunction block_function_; block内部迭代器的生成函数
void* arg_; //通常为TableCahe,供block_function_调用的参数
const ReadOptions options_;
Status status_;
IteratorWrapper index_iter_; //大致相当于shelf_iter_
IteratorWrapper data_iter_; // 大致相当于book_iter_
std::string data_block_handle_;
}; void TwoLevelIterator::SeekToFirst() {
index_iter_.SeekToFirst(); //跳到第一个block
InitDataBlock(); //根据当前block设置data_iter_
if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
SkipEmptyDataBlocksForward(); //跳过空block
}

leveldb中TwoLevelIterator也类似BookStore有一个block的遍历指针存放至TwoLevelIterator中而已,当一个block遍历完的时候使用该迭代器跳到下一个block,然后在设置对应的data_iter_。只是在过程中遍历下一层data_iter时内部结构可能尚未初始化需要调用BlockReader从磁盘读取文件进行初始化设置。

这里只是说明了使用TwoLevelIterator遍历SSTable时,当遍历db的时候也同样可以类似的对应SSTable层级的一个迭代器即可,而block_function_需要设置为GetFileIterator就可以遍历整个数据库了。

LevelDB源码分析--使用Iterator简化代码设计的更多相关文章

  1. leveldb源码分析--WriteBatch

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

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

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

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

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

  4. Leveldb源码分析--1

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

  5. netty源码分析 - Recycler 对象池的设计

    目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...

  6. leveldb源码分析--日志

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

  7. Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)

    一.基本概念 迭代器是一个对象,也是一种设计模式,Java有两个用来实实现迭代器的接口,分别是Iterator接口和继承自Iterator的ListIterator接口.实现迭代器接口的类的对象有遍历 ...

  8. 【JDK】JDK源码分析-List, Iterator, ListIterator

    List 是最常用的容器之一.之前提到过,分析源码时,优先分析接口的源码,因此这里先从 List 接口分析.List 方法列表如下: 由于上文「JDK源码分析-Collection」已对 Collec ...

  9. leveldb源码分析之Slice

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

随机推荐

  1. Mysql大量插入随机数据方法--存储过程

    创建测试表: mysql)); 创建存储过程: mysql> delimiter // mysql> create procedure rand_data(in num int) -> ...

  2. 基于GTID Replication主从数据不一致操作

    基本的M-S结构   现在master与slave主机数据一致:   mysql> select * from t1; +------+ | id   | +------+ |    1 | | ...

  3. [Solution] ASP.NET Identity(1) 快速入门

    本节将介绍: ASP.NET Identity简介 快速入门 扩展 ASP.NET Identity简介 身份管理在ASP.NET中存在很长世间了,ASP.NET 开发团队已经学会了很多从客户的反馈. ...

  4. 重新想象 Windows 8.1 Store Apps (91) - 后台任务的新特性: 下载和上传的新特性, 程序启动前预下载网络资源, 后台任务的其它新特性

    [源码下载] 重新想象 Windows 8.1 Store Apps (91) - 后台任务的新特性: 下载和上传的新特性, 程序启动前预下载网络资源, 后台任务的其它新特性 作者:webabcd 介 ...

  5. C# Web Forms - Using jQuery FullCalendar

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> ...

  6. php学习笔记:利用gd库生成图片,并实现随机验证码

    说明:一些基本的代码我都进行了注释,这里实现的验证码位数.需要用的字符串都可以再设置.有我的注释,大家应该很容易能看得懂. 基本思路: 1.用mt_rand()随机生成数字确定需要获取的字符串,对字符 ...

  7. velocity merge作为工具类从web上下文和jar加载模板的两种常见情形

    很多时候,处于各种便利性或折衷或者通用性亦或是限制的原因,会借助于模板生成结果,在此介绍两种使用velocity merge的情形,第一种是和spring mvc一样,将模板放在velocityCon ...

  8. 使用正则表达式获取Sql查询语句各项(表名、字段、条件、排序)

    string text = "select * from [admin] where aa=1 and cc='b' order by aa desc "; Regex reg = ...

  9. [iOS] 使用xib做为应用程序入口 with Code

    [iOS] 使用xib做为应用程序入口 with Code 前言 开发iOS APP的时候,使用storyboard能够快速并且直觉的建立用户界面.但在多人团队开发的情景中,因为storyboard是 ...

  10. echarts 地图图

    效果如下图: 1.下载echarts对应包: http://echarts.baidu.com/ 2.前端页面: <!DOCTYPE html> <html xmlns=" ...