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. 记录C#错误日志工具

    在编程过程中,我们经常会用try...catch处理可能出错的代码块.如果程序出现错误,则直接show出错误信息. 当然,大型的系统都有错误日志处理模块,用数据库记录错误日志信息,有相应的写入错误日志 ...

  2. python中的exec()、eval()以及complie()

    参考博客:http://www.cnblogs.com/yyds/p/6276746.html 1.eval函数 函数的作用: 计算指定表达式的值.也就是说它要执行的python代码只能是单个表达式( ...

  3. php防止sql注入漏洞代码 && 几种常见攻击的正则表达式

    注入漏洞代码和分析                                                                                           ...

  4. JSON与XML

    XML——这种用于表示客户端与服务器间数据交换有效负载的格式,几乎已经成了Web services的同义词.我们知道AJAX技术能够使得每一次请求更加迅捷,对于每一次请求返回的不是整个页面,也仅仅是所 ...

  5. 下载RAD

    1.登录https://w3-103.ibm.com/software/xl/download/ticket.do 2.输入Intranet ID和pswd,然后选I Agree. 3.然后点Sear ...

  6. Matlab实现:图像边缘提取

    1. 边缘提取算法 方法一:一阶微分算子 Sobel算子 Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,Sobel算子对边缘定位不是很准确,图像的边缘不止一个像素. Roberts算子 ...

  7. Linux常用shell脚本

    在运维中,尤其是linux运维,都知道脚本的重要性,脚本会让我们的 运维事半功倍,所以学会写脚本是我们每个linux运维必须学会的一门功课,如何学好脚本,最关键的是就是大量的练习 和实践. 1.用Sh ...

  8. 用Postfix + Dovecot 搭建的邮件server被垃圾邮件其中转server的处理

    今天发邮件. 发送失败.然后到server上看日志, 发现硬盘被垃圾邮件的缓存队列和日志塞满了. tail    -f    /var/log/maillog   发现疯狂刷屏.部分日志例如以下 : ...

  9. DOS批处理高级教程

    转载-->http://blog.csdn.net/lanbing510/article/details/7461073 前言 本教程主要引用伤脑筋版主的系列文章,同时参考引用[英雄]教程等其他 ...

  10. ubuntu移植jsoncpp到Android平台(转)

    NDK开发模块的时候,如果涉及到网络请求,类似json数据传递的时候,有现成的第三方json库可以移植,后台C++开发中使用的比较多的是jsoncpp,今天记录一下jsoncpp移植到Android平 ...