4. LevelDB源码剖析之基础部件-操作系统操作

LevelDB被设计成跨平台数据库,支持在windows、linux、Android等多个操作系统。除了port文件夹中的AtomicPointer、Mutex等编程基础部件,和操作系统相关的其他操作统统被塞进了Env类中。

4.1 Env类

Env类从功能上划分包括如下几个部分:

  • 文件相关操作。包括文件创建、删除文件目录,文件是否存在判定等。
  • 线程相关操作。包括启动线程,执行临时任务、Sleep操作等。
  • 其他操作。获取系统当前时间、创建logger文件等。

4.2 文件相关操作

文件相关操作接口定义如下:

class Env
{
  ......

  //创建顺序读文件 -- 文件同时只能被一个线程访问
  virtual Status NewSequentialFile(const std::string &fname,
                                   SequentialFile **result) = 0;

  //创建随机读文件 -- 文件同时只能被一个线程访问
  virtual Status NewRandomAccessFile(const std::string &fname,
                                     RandomAccessFile **result) = 0;

  //创建写文件 -- 文件同时只能被一个线程访问
  virtual Status NewWritableFile(const std::string &fname,
                                 WritableFile **result) = 0;

  //创建或打开写文件 -- 文件同时只能被一个线程访问
  virtual Status NewAppendableFile(const std::string &fname,
                                   WritableFile **result);

  // Returns true iff the named file exists.
  virtual bool FileExists(const std::string &fname) = 0;

  // Store in *result the names of the children of the specified directory.
  // The names are relative to "dir".
  // Original contents of *results are dropped.
  virtual Status GetChildren(const std::string &dir,
                             std::vector<std::string> *result) = 0;

  // Delete the named file.
  virtual Status DeleteFile(const std::string &fname) = 0;

  // Create the specified directory.
  virtual Status CreateDir(const std::string &dirname) = 0;

  // Delete the specified directory.
  virtual Status DeleteDir(const std::string &dirname) = 0;

  // Store the size of fname in *file_size.
  virtual Status GetFileSize(const std::string &fname, uint64_t *file_size) = 0;

  // Rename file src to target.
  virtual Status RenameFile(const std::string &src,
                            const std::string &target) = 0;

  // Lock the specified file.  Used to prevent concurrent access to
  // the same db by multiple processes.  On failure, stores NULL in
  // *lock and returns non-OK.
  //
  // On success, stores a pointer to the object that represents the
  // acquired lock in *lock and returns OK.  The caller should call
  // UnlockFile(*lock) to release the lock.  If the process exits,
  // the lock will be automatically released.
  //
  // If somebody else already holds the lock, finishes immediately
  // with a failure.  I.e., this call does not wait for existing locks
  // to go away.
  //
  // May create the named file if it does not already exist.
  virtual Status LockFile(const std::string &fname, FileLock **lock) = 0;

  // Release the lock acquired by a previous successful call to LockFile.
  // REQUIRES: lock was returned by a successful LockFile() call
  // REQUIRES: lock has not already been unlocked.
  virtual Status UnlockFile(FileLock *lock) = 0;
  ......
}

文件按操作方式分为顺序读文件(SequentialFile)、随机读文件(RandomAccessFile)及写文件(WritableFile)。
通用的文件操作包括删除文件、获取文件大小等;通用的目录操作包括创建、删除目录,获取目录的子目录或文件列表,逻辑简单此处不提。另外,有一组配对的文件锁操作LockFile、UnlockFile。

4.2.1 SequentialFile

顺序文件和随机文件实现都非常简单,二者最大的区别在于:顺序文件不提供基于offset的读操作接口。

顺序文件每次从当前位置读取指定大小的字节数,另外支持跳过中间部分内容,除此之外再无其他。

// A file abstraction for reading sequentially through a file
class SequentialFile
{
public:
  SequentialFile() {}
  virtual ~SequentialFile();

  // Read up to "n" bytes from the file.  "scratch[0..n-1]" may be
  // written by this routine.  Sets "*result" to the data that was
  // read (including if fewer than "n" bytes were successfully read).
  // May set "*result" to point at data in "scratch[0..n-1]", so
  // "scratch[0..n-1]" must be live when "*result" is used.
  // If an error was encountered, returns a non-OK status.
  //
  // REQUIRES: External synchronization
  virtual Status Read(size_t n, Slice *result, char *scratch) = 0;

  // Skip "n" bytes from the file. This is guaranteed to be no
  // slower that reading the same data, but may be faster.
  //
  // If end of file is reached, skipping will stop at the end of the
  // file, and Skip will return OK.
  //
  // REQUIRES: External synchronization
  virtual Status Skip(uint64_t n) = 0;

private:
  // No copying allowed
  SequentialFile(const SequentialFile &);
  void operator=(const SequentialFile &);
};

4.2.2 RandomAccessFile

随机读文件只有一个基于offset读取指定大小字节数的接口,定义如下:

// A file abstraction for randomly reading the contents of a file.
class RandomAccessFile
{
public:
  RandomAccessFile() {}
  virtual ~RandomAccessFile();

  // Read up to "n" bytes from the file starting at "offset".
  // "scratch[0..n-1]" may be written by this routine.  Sets "*result"
  // to the data that was read (including if fewer than "n" bytes were
  // successfully read).  May set "*result" to point at data in
  // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
  // "*result" is used.  If an error was encountered, returns a non-OK
  // status.
  //
  // Safe for concurrent use by multiple threads.
  virtual Status Read(uint64_t offset, size_t n, Slice *result,
                      char *scratch) const = 0;

private:
  // No copying allowed
  RandomAccessFile(const RandomAccessFile &);
  void operator=(const RandomAccessFile &);
};

4.2.3 WritableFile

写文件的接口定义相对“复杂”,除了追加操作外,还包括了关闭(close)、刷新(flush)、同步(sync)操作。接口定义如下:

// A file abstraction for sequential writing.  The implementation
// must provide buffering since callers may append small fragments
// at a time to the file.
class WritableFile
{
public:
  WritableFile() {}
  virtual ~WritableFile();

  virtual Status Append(const Slice &data) = 0;
  virtual Status Close() = 0;
  virtual Status Flush() = 0;
  virtual Status Sync() = 0;

private:
  // No copying allowed
  WritableFile(const WritableFile &);
  void operator=(const WritableFile &);
};

Flush和Sync的差异在于:Flush讲数据从用户缓冲区刷新到内核缓冲区,而Sync则会将内核缓冲区数据刷新到磁盘。

4.3 线程相关操作

接口定义如下:

  // Arrange to run "(*function)(arg)" once in a background thread.
  //
  // "function" may run in an unspecified thread.  Multiple functions
  // added to the same Env may run concurrently in different threads.
  // I.e., the caller may not assume that background work items are
  // serialized.
  virtual void Schedule(
      void (*function)(void *arg),
      void *arg) = 0;

  // Start a new thread, invoking "function(arg)" within the new thread.
  // When "function(arg)" returns, the thread will be destroyed.
  virtual void StartThread(void (*function)(void *arg), void *arg) = 0;

  // Sleep/delay the thread for the prescribed number of micro-seconds.
  virtual void SleepForMicroseconds(int micros) = 0;

Schedule提供系统线程池,添加task后交由线程池调度,而无需用户创建线程池或者进行线程管理;StartThread负责创建单独线程。

4.4 其他操作

  // *path is set to a temporary directory that can be used for testing. It may
  // or many not have just been created. The directory may or may not differ
  // between runs of the same process, but subsequent calls will return the
  // same directory.
  virtual Status GetTestDirectory(std::string *path) = 0;

  // Create and return a log file for storing informational messages.
  virtual Status NewLogger(const std::string &fname, Logger **result) = 0;

  // Returns the number of micro-seconds since some fixed point in time. Only
  // useful for computing deltas of time.
  virtual uint64_t NowMicros() = 0;

4.5 总结

本节描述的是LevelDB系统构建基础,本身没有任何技术复杂度。作者设计遵循了单一职责、精简等基本设计原则,将接口做到最简,具有一定的借鉴意义。


转载请注明:【随安居士】http://www.jianshu.com/p/3c449af6fdac

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,128评论 2 34
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,648评论 0 3
  • No matter when you start, it is important that you do not...
    宁浙阅读 228评论 0 1
  • 1. 什么是决策树 决策树是基于树结构进行决策。决策树学习的目的是产生一棵泛化能力强,处理未见示例能力强的决策树。...
    Persistence2阅读 352评论 0 0