1.DBImpl::Open

 1 Status DB::Open(const Options& options, const std::string& dbname,
 2                 DB** dbptr) {
 3   *dbptr = NULL;
 4 
 5   DBImpl* impl = new DBImpl(options, dbname);
 6   impl->mutex_.Lock();
 7   VersionEdit edit;
 8   Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists
 9   if (s.ok()) {
     uint64_t new_log_number = impl->versions_->NewFileNumber();
     WritableFile* lfile;
     s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
                                      &lfile);
     if (s.ok()) {
       edit.SetLogNumber(new_log_number);
       impl->logfile_ = lfile;
       impl->logfile_number_ = new_log_number;
       impl->log_ = new log::Writer(lfile);
       s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
     }
     if (s.ok()) {
       impl->DeleteObsoleteFiles();
       impl->MaybeScheduleCompaction();
     }
   }
   impl->mutex_.Unlock();
   if (s.ok()) {
     *dbptr = impl;
   } else {
     delete impl;
   }
   return s;
 }

2.DBImpl::Get

 1 Status DBImpl::Get(const ReadOptions& options,
 2                    const Slice& key,
 3                    std::string* value) {
 4   Status s;
 5   MutexLock l(&mutex_);
 6   SequenceNumber snapshot;
 7   if (options.snapshot != NULL) {
 8     snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
 9   } else {
     snapshot = versions_->LastSequence();
   }
 
   MemTable* mem = mem_;
   MemTable* imm = imm_;
   Version* current = versions_->current();
   mem->Ref();
   if (imm != NULL) imm->Ref();
   current->Ref();
 
   bool have_stat_update = false;
   Version::GetStats stats;
 
   // 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 != NULL && imm->Get(lkey, value, &s)) {
       // Done
     } else {
       s = current->Get(options, lkey, value, &stats);
       have_stat_update = true;
     }
     mutex_.Lock();
   }
 
   if (have_stat_update && current->UpdateStats(stats)) {
     MaybeScheduleCompaction();
   }
   mem->Unref();
   if (imm != NULL) imm->Unref();
   current->Unref();
   return s;
 }

3.DBImpl::RecordReadSample

 void DBImpl::RecordReadSample(Slice key) {
   MutexLock l(&mutex_);
   if (versions_->current()->RecordReadSample(key)) {
     MaybeScheduleCompaction();
   }
 }

4.DBImpl::MakeRoomForWrite

 1 Status DBImpl::MakeRoomForWrite(bool force) {
 2   mutex_.AssertHeld();
 3   assert(!writers_.empty());
 4   bool allow_delay = !force;
 5   Status s;
 6   while (true) {
 7     if (!bg_error_.ok()) {
 8       // Yield previous error
 9       s = bg_error_;
       break;
     } else if (
         allow_delay &&
         versions_->NumLevelFiles() >= config::kL0_SlowdownWritesTrigger) {
       // We are getting close to hitting a hard limit on the number of
       // L0 files.  Rather than delaying a single write by several
       // seconds when we hit the hard limit, start delaying each
       // individual write by 1ms to reduce latency variance.  Also,
       // this delay hands over some CPU to the compaction thread in
       // case it is sharing the same core as the writer.
       mutex_.Unlock();
       env_->SleepForMicroseconds();
       allow_delay = false;  // Do not delay a single write more than once
       mutex_.Lock();
     } else if (!force &&
                (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {
       // There is room in current memtable
       break;
     } else if (imm_ != NULL) {
       // We have filled up the current memtable, but the previous
       // one is still being compacted, so we wait.
       Log(options_.info_log, "Current memtable full; waiting...\n");
       bg_cv_.Wait();
     } else if (versions_->NumLevelFiles() >= config::kL0_StopWritesTrigger) {
       // There are too many level-0 files.
       Log(options_.info_log, "Too many L0 files; waiting...\n");
       bg_cv_.Wait();
     } else {
       // Attempt to switch to a new memtable and trigger compaction of old
       assert(versions_->PrevLogNumber() == );
       uint64_t new_log_number = versions_->NewFileNumber();
       WritableFile* lfile = NULL;
       s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
       if (!s.ok()) {
         // Avoid chewing through file number space in a tight loop.
         versions_->ReuseFileNumber(new_log_number);
         break;
       }
       delete log_;
       delete logfile_;
       logfile_ = lfile;
       logfile_number_ = new_log_number;
       log_ = new log::Writer(lfile);
       imm_ = mem_;
       has_imm_.Release_Store(imm_);
       mem_ = new MemTable(internal_comparator_);
       mem_->Ref();
       force = false;   // Do not force another compaction if have room
       MaybeScheduleCompaction();
     }
   }
   return s;
 }

1-4均会调用MaybeScheduleCompaction()从而调用BackgroundCompaction来完成compact。

以下是核心Compact的过程

BackgroundCompaction

 1 void DBImpl::BackgroundCompaction() {
 2   mutex_.AssertHeld();
 3 
 4   if (imm_ != NULL) {
 5     CompactMemTable();
 6     return;
 7   }
 8 
 9   Compaction* c;
   bool is_manual = (manual_compaction_ != NULL); // 正常情况下为false,因为初始化时为空
   InternalKey manual_end;
   if (is_manual) {
     ManualCompaction* m = manual_compaction_;
     c = versions_->CompactRange(m->level, m->begin, m->end);
     m->done = (c == NULL);
     if (c != NULL) {
       manual_end = c->input(, c->num_input_files() - )->largest;
     }
     Log(options_.info_log,
         "Manual compaction at level-%d from %s .. %s; will stop at %s\n",
         m->level,
         (m->begin ? m->begin->DebugString().c_str() : "(begin)"),
         (m->end ? m->end->DebugString().c_str() : "(end)"),
         (m->done ? "(end)" : manual_end.DebugString().c_str()));
   } else {
     c = versions_->PickCompaction(); // 找出应该合并的 level 及 level + 1层的FileMetaData*
   }
 
   Status status;
   if (c == NULL) {
     // Nothing to do
   } else if (!is_manual && c->IsTrivialMove()) {
     // Move file to next level
     assert(c->num_input_files() == );
     FileMetaData* f = c->input(, );
     c->edit()->DeleteFile(c->level(), f->number);
     c->edit()->AddFile(c->level() + , f->number, f->file_size,
                        f->smallest, f->largest);
     status = versions_->LogAndApply(c->edit(), &mutex_);
     if (!status.ok()) {
       RecordBackgroundError(status);
     }
     VersionSet::LevelSummaryStorage tmp;
     Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n",
         static_cast<unsigned long long>(f->number),
         c->level() + ,
         static_cast<unsigned long long>(f->file_size),
         status.ToString().c_str(),
         versions_->LevelSummary(&tmp));
   } else {
     CompactionState* compact = new CompactionState(c);
     status = DoCompactionWork(compact); // 核心Compact
     if (!status.ok()) {
       RecordBackgroundError(status);
     }
     CleanupCompaction(compact);
     c->ReleaseInputs();
     DeleteObsoleteFiles();
   }
   delete c;
 
   if (status.ok()) {
     // Done
   } else if (shutting_down_.Acquire_Load()) {
     // Ignore compaction errors found during shutting down
   } else {
     Log(options_.info_log,
         "Compaction error: %s", status.ToString().c_str());
   }
 
   if (is_manual) {
     ManualCompaction* m = manual_compaction_;
     if (!status.ok()) {
       m->done = true;
     }
     if (!m->done) {
       // We only compacted part of the requested range.  Update *m
       // to the range that is left to be compacted.
       m->tmp_storage = manual_end;
       m->begin = &m->tmp_storage;
     }
     manual_compaction_ = NULL;
   }
 }

LevelDB场景分析4--BackgroundCompaction的更多相关文章

  1. LevelDB场景分析1--整体结构分析

    基本用法 数据结构 class DBImpl : public DB { private:     struct CompactionState;     struct Writer;// Infor ...

  2. LevelDB场景分析2--Open

    1.源码 1 Status DB::Open(const Options& options, const std::string& dbname,      uint64_t new_ ...

  3. TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析

    TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...

  4. Oracle dbms_lock.sleep()存储过程使用技巧-场景-分析-实例

    <Oracle dbms_lock.sleep()存储过程使用技巧>-场景-分析-实例 摘要:今天是2014年3月10日,北京,雾霾,下午组织相关部门开会.会议的结尾一名开发工程师找到了我 ...

  5. 理解 python metaclass使用技巧与应用场景分析

    理解python metaclass使用技巧与应用场景分析       参考: decorator与metaclass:http://jfine-python-classes.readthedocs. ...

  6. 数据结构之链表C语言实现以及使用场景分析

    牢骚:本篇博客两个星期前已经存为草稿,鉴于发生一些糟糕的事情,今天才基本完成.本人6月份应届毕业生一枚,毕业后当天来到帝都,之后也非常顺利,面试了俩家公司都成功了.一家做C++方面电商ERP,一家做w ...

  7. mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法

    mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法 官方mysql一个slave只能对应一个master,mariadb 10开始支持多源 ...

  8. ThreadLocal的理解与应用场景分析

    对于Java ThreadLocal的理解与应用场景分析 一.对ThreadLocal理解 ThreadLocal提供一个方便的方式,可以根据不同的线程存放一些不同的特征属性,可以方便的在线程中进行存 ...

  9. Java 常用List集合使用场景分析

    Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让 ...

随机推荐

  1. iOS开发-舒尔特表

    周末闲来无事,看一个概念,挺有意思的,舒尔特表,网上也有很多人写过类似的Demo,本人闲来无事也写了一下,舒尔特表听起来很高大上的样子,不过本人的理解就是一个正方形的矩阵中放的各种小格子,可以是字母, ...

  2. 11个JavaScript颜色选择器插件

    几年前,很难找到一个合适的颜色选择器.正好看到很多不错的JavaScript颜色选择器插件,故而把这些编译汇总.在本文,Web设计师和开发人员 Kevin Liew 选取了11个相应插件,有些会比较复 ...

  3. ComboBoxEdit 数据绑定 使用模板

    1)定义模板资源 <UserControl.Resources> <local:StatusConvertor x:Key="StatusConvertor"&g ...

  4. 怎样在Ubuntu中修改默认程序

    这个新手指南会向你展示如何在 Ubuntu Linux 中修改默认程序.对于我来说,安装 VLC 多媒体播放器是安装完 Ubuntu 16.04 该做的事中最先做的几件事之一.为了能够使我双击一个视频 ...

  5. XGBoost:在Python中使用XGBoost

    原文:http://blog.csdn.net/zc02051126/article/details/46771793 在Python中使用XGBoost 下面将介绍XGBoost的Python模块, ...

  6. iOS-数据库sqlite的使用

    .数据库的增删查改的方法 sqlite3_exec(db, [sql UTF8String], NULL, NULL, &erro); 数据库的使用 步骤:01.导入框架<sqlite3 ...

  7. HDU 2178.猜数字【分析能力练习】【读题能力练习】【8月10】

    猜数字 Problem Description A有1数m.B来猜.B每猜一次,A就说"太大"."太小"或"对了" . 问B猜n次能够猜到的 ...

  8. Smack 结合 Openfire服务器,建立IM通信,发送聊天消息

    在文章开始,请你了解和熟悉openfire方面的相关知识,这样对你理解下面代码以及下面代码的用途有很好的了解.同时,你可能需要安装一个简单的CS聊天工具,来测试你的代码是否成功的在openfire服务 ...

  9. 上传的文件放在SVN服务器的哪个目录下

    SVN服务器版本库有两种格式,一种为FSFS,一种为BDB 把文件上传到SVN版本库后,上传的文件不再以文件原来的格式存储,而是被svn以它自定义的格式压缩成版本库数据,存放在版本库中. 如果是FSF ...

  10. Servlet一(web基础学习笔记二十)

    一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向 ...