美文网首页
从leveldb中学编码技巧

从leveldb中学编码技巧

作者: wangjie_yy | 来源:发表于2019-05-23 15:58 被阅读0次

    leveldb是一个C++写的kv存储引擎, 作者是google的大神程序员Jeff Dean。leveldb的源码写的非常漂亮,干净整洁,通俗易懂。可以从中学到很多有用coding的技巧,这篇笔记通过讲解批量更新(WriteBatch)的实现来学习一下大神的代码设计思路。

    leveldb支持多个write操作的原子更新,本质上是一个批量操作,使用起来大概是这样的:

    #include "leveldb/write_batch.h"
    ...
    leveldb::WriteBatch batch;
    batch.Delete(key1);
    batch.Put(key2, value);
    s = db->Write(leveldb::WriteOptions(), &batch);
    

    简单地说,就是将一批数据写入到内存中的memtable中。如果要实现这个批量操作,很容易想到的思路是:定义一个WriteBatch类,它的内部记录所有的写操作的数据,同时给这个类定义一些方法,可能包括两大类:

    • 用于操作内部的数据,比如Delete(), Put(), Clear(), Content()等
    • 用于查看及操作内部数据的元信息的方法,比如Count()返回内部写操作的个数,Size()返回这些操作写入数据的大小,SetSequence()用于设置此次操作的编号等

    然后,在db->Write()方法中,实现具体写入到memtable的逻辑:

    • 调用WriteBatch的Content()方法获取需要写入的数据
    • 将数据依次写入到memtable中

    从功能上看,这样做没有特别大的问题,能够实现我们需要的逻辑。但是leveldb的代码不是这样写的,跟上面这个思路相比,leveldb的实现体现了两个额外的考虑:

    1. 由于WriteBatch类需要暴露给用户代码使用,最好只提供必需的,核心的方法,即Delete, Put, Clear。其他方法不需要给用户调用,可以隐藏起来。
    2. 将WriteBatch的数据写入到memtable中,这个逻辑可以抽象出来,做成容易替换的模式。这样如果后续需要将WriteBatch的数据写入到其他存储中,可以比较方便的改动代码。

    看下leveldb是怎么做的:针对第一点,WriteBatch只提供了三个公有方法Put(), Delete(), Clear(),给用户代码使用。同时额外定义了一个WriteBatchInternal类,这个类的说明如下:

    // WriteBatchInternal provides static methods for manipulating a
    // WriteBatch that we don't want in the public WriteBatch interface.
    

    对于第二点,在WriteBatch内部又定义了一个类,以及一个Iterate()方法,如下:

    class WriteBatch {
    public:
        ...
        class Handler {
        public:
            virtual ~Handler();
            virtual void Put(const Slice& key, const Slice& value) = 0;
            virtual void Delete(const Slice& key) = 0;    
        }
        Status Iterate(Handler* handler) const;
    };
    

    Iterate(handler)的逻辑是,遍历WriteBatch内部的数据,对每一条数据,调用Handler的Put或者Delete方法(只有这两种操作)来处理。这样的话,就把实际写入的逻辑拆分为了两部分:

    • 一部分是通用的遍历iterate
    • 另外一部分是一个抽象处理接口Handler,可以使用不同的逻辑来实现这个接口

    leveldb的单测代码中,实现了另外一个WriteBatch::Handler,用于将数据写入到一个测试用的存储中。定义一个接口,然后在这个接口之下使用不同的实现,这种做法类似策略模式(stragtegy),根据GOF上面的介绍,strategy的意图如下:

    定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。本模式使得算法可以独立使用它们的客户而变化。

    可以看出来,leveldb的实现很注意封装和抽象,这正是面向对象设计的核心原则。按照这种方式写的代码,更容易进行维护和升级,也可以极大的避免后续代码变得臃肿冗长,杂乱无章。最重要的是,这样的代码相比一个大几百行的函数,更容易理解。

    相关文章

      网友评论

          本文标题:从leveldb中学编码技巧

          本文链接:https://www.haomeiwen.com/subject/kicbzqtx.html