我们先来参考来至使用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. 参数嗅探(Parameter Sniffing)(2/2)

    在参数嗅探(Parameter Sniffing)(1/2)里,我介绍了SQL Server里参数嗅探的基本概念和背后的问题.如你所见,当缓存的计划被SQL Server盲目重用时,会带来严重的性能问 ...

  2. WebGL on iOS8 终于等到了这一天

    WWDC2014刚结束,这次的大会是名符其实的开发者大会,更贴切的应该说的确是一次软件开发者的大会,对于OSX和iOS的更多功能特性让人兴奋,Swift新语言促成了如上图片 但我更感兴趣的是WebGL ...

  3. 100行JS实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  4. IOS开发UI基础UISegment属性

    UISegment属性 1.segmentedControlStyle设置segment的显示样式.typedef NS_ENUM(NSInteger, UISegmentedControlStyle ...

  5. Winform开发框架之权限管理系统的改进

    权限管理系统,一直是很多Mis系统和一些常见的管理系统所需要的,所以一般可以作为独立的模块进行开发,需要的时候进行整合即可,不需要每次从头开发,除非特殊的系统需求.我在Winform开发框架介绍中的随 ...

  6. Linux服务器时间同步方法

    一般稍微大点的项目都会部署到好几台服务器做集群,同一个应用可能部署到几台服务器上,而处理业务中必须让不同的服务器上时间保持一致,这就需要进行服务器间的时间同步.我的做法是: 1,选择其中一台对外网开放 ...

  7. 【poj 3167】Cow Patterns(字符串--KMP匹配+数据结构--树状数组)

    题意:给2个数字序列 a 和 b ,问按从小到达排序后,a中的哪些子串与b的名次匹配. a 的长度 N≤100,000,b的长度 M≤25,000,数字的大小 K≤25. 解法:[思考]1.X 暴力. ...

  8. [Xamarin.Android] 发布NuGet套件

    [Xamarin.Android] 发布NuGet套件 前言 在Xamarin中,可以将自己开发的项目包装成为NuGet套件发布至NuGet Server,来提供其他开发人员使用.本篇介绍如何封装并发 ...

  9. [js开源组件开发]js文本框计数组件

    js文本框计数组件 先上效果图: 样式可以自行调整 ,它的功能提供文本框的实时计数,并作出对应的操作,比如现在超出了,点击下面的按钮后,文本框会闪动两下,阻止提交.具体例子可以点击demo:http: ...

  10. 复杂表格的树形结构的添加删除行div实现

    公司倒闭,换了工作,无奈选择了做外包这个差事,大公司进不去,小公司工资太低,可能也只能如此了.但无奈之举,亦不可浪费时间,多多磨练自己吧! 众所周知,做外包项目,其实就是做一些大公司的内部系统,多以管 ...