必威体育Betway必威体育官网
当前位置:首页 > IT技术

LevelDB compact 过程

时间:2019-10-29 02:45:55来源:IT技术作者:seo实验室小编阅读:72次「手机版」
 

leveldb

leveldb的一个重要特性就是数据的分层,由于数据的分层, 越旧的数据处在越大的层级,越新的数据在越小的层级。

在查询数据的时候, 最先读取MemTable里面的数据, 然后是L0的SSTable里面, 接着是L1, L2直到最大的层级。在分层设计中, 越往上层,数据的容量越大, 大约Ln是Ln-1层数据的10倍。 在各个层级的SSTable文件, 只有L0层的数据是有MemTable直接flush到磁盘上, 其它层的数据是经过compaction过程进行排序整理产生的。这意味着L0层以上的数据, 各个SSTable文件内的数据是有序且不会重叠的。

因此, compaction的过程是产生SSTable的过程, 分为2中情况:

  • 由MemTable到SSTable的flush过程, 也被成为Minor Compaction;
  • 由Ln层的SSTable到Ln+1层的SSTable的数据重排过程, 也被称为Major Compaction;

Minor Compaction

LevelDB设定了L0的容量, 以及触发L0 compaction的条件:

// Level-0 compaction is started when we hit this many files.
static const int kL0_CompactionTrigger = 4;
      
// Soft limit on number of level-0 files.  We slow down writes at this point.
static const int kL0_SlowdownWritesTrigger = 8;                                                                                                                                              
      
// Maximum number of level-0 files.  We stop writes at this point.
static const int kL0_StopWritesTrigger = 12;

默认情况下, L0的SSTable的文件个数是4个, 大于4个就可能开始compaction, 当L0文件的个数大于8个, 应用层的写入速度会降下来, 以避免L0文件数太多, 当L0文件数大于12个, 前端的写入停止。

在LevelDB中, 不管是Put, 还是Delete, 都是调用Write来进行写入, 在写入之前, 都会调用MakeRoomForWrite来判断如何进行处理, 是直接写入还是slowdown, 还是送至前端写入?

其实现过程如下图:

写入控制过程

从上图可以看到, Minor Compaction发生在前面4个判断失败之后, 它会把当前正在用作写入的MemTable转换为一个只读的内存数据, 同时产生一个新的MemTable以及与其对应的log文件, 后续的新的写入都转移到新产生的MemTable文件内。 同时, 它会产生一个Compact Schedule, 来触发后台的线程来将im-memTable

写入磁盘。

Major Compaction

LevelDB 在数据库启动的时候, 会指定Env, 比如linux系统下会产生一个PosixEnv对象,它定义了一个schedule函数来构成函数队列, 所有的后端执行的函数, 会放进该队列里面来一个一个地执行:

void PosixEnv::Schedule(void (*function)(void*), void* arg) {
  PthreadCall("lock", pthread_mutex_lock(&mu_));

  // Start background thread if necessary
  if (!started_bgthread_) {
    started_bgthread_ = true;
    PthreadCall(
        "create thread",
        pthread_create(&bgthread_, NULL,  &PosixEnv::BGThreadWrAPPer, this));                                                                                                                
  }

  // If the queue is currently empty, the background thread may currently be
  // waiting.
  if (queue_.empty()) {
    PthreadCall("signal", pthread_cond_signal(&bgsignal_));
  }

  // add to priority queue
  queue_.push_back(BGItem());
  queue_.back().function = function;
  queue_.back().arg = arg;

  PthreadCall("unlock", pthread_mutex_unlock(&mu_));
}

// PosixEnv::BGThreadwrapper包装了PosixEnv::BGThread() 函数
// 该函数等待加入队列的函数, 逐个处理
void PosixEnv::BGThread() {                                                                                                                                                                  
  while (true) {
    // Wait until there is an item that is ready to run
    PthreadCall("lock", pthread_mutex_lock(&mu_));
    while (queue_.empty()) {
      PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_));
    }

    void (*function)(void*) = queue_.front().function;
    void* arg = queue_.front().arg;
    queue_.pop_front();

    PthreadCall("unlock", pthread_mutex_unlock(&mu_));
    (*function)(arg);  、、 根据注册的函数执行callback函数
  }
}

在这里, compaction指定的处理函数是DBImpl::BGWork(), 经过DBImpl::BackgroundCall(), 最终由DBImpl::BackgroundCompaction()来进行compaction的任务。

void DBImpl::BackgroundCompaction() {
    ...
    if (is_manual) {
    }
    else {
          c = versions_->PickCompaction();
    }
    CompactionState* compact = new CompactionState(c);
   status = DoCompactionWork(compact);
   if (!status.ok()) {
     RecordBackgroundERROR(status);
   }
   CleanupCompaction(compact);
   c->ReleaseInputs();
   DeleteObsoleteFiles();
}

可以看到, 通过VersionSet::PickCompaction()来搜集本次compaction的input集合,LevelDB中,Compaction操作有两种触发方式:

  • 某一level的文件数太多
  • 某一文件的查找次数超过允许值;

因此,在VersionSet::PickCompaction()中便有了代码中的size_compaction和seek_compaction的判断。在进行合并时,将优先考虑文件数过多的情况。

最后有DBImplement::DoCompactionWork()完成input集合数据的遍历以及写入新的SSTable文件里面。

如下我们给出一个简化版的compaction过程:

在这里插入图片描述

在这里插入图片描述

文章最后发布于: 2018-11-18 16:54:45

相关阅读

浅谈setInterval(aa,1000)与setInterval(aa(),1000)的

一直有个疑惑,在定时器上调用某个方法时,加括号和不加括号有什么区别。今天做了个实验,发现,不加括号定时器会每秒执行一次,加了括号只

做3年社群投入1000万,我都明白了什么?

图片来源图虫:已授站长之家使用声明:本文来自于微信公众号运营研究社公众号(ID:U_quan),作者:陈维贤,授权站长之家转载发布。文章整理自

leveldb学习:leveldb实现原理

LevelDb日知录之一:LevelDb  LevelDb由两位是Google公司重量级的工程师:Jeff Dean和Sanjay Ghemawa 发起。 Jeff Dean:Google大规

E1000 与 VMXNET3的 区别

与E1000E和E1000相比,VMXNET3的网络性能更好。本文将解释虚拟网络适配器和第2部分之间的区别,并将演示通过选择半虚拟化适配器可以

搭配黑科技降噪效果更出色 索尼真无线蓝牙降噪耳机WF-

我们生活中所说的真无线耳机其实就是两个“耳塞”,主体没有任何的可见线材,索尼真无线蓝牙降噪耳机WF-1000XM3就是如此

分享到:

栏目导航

推荐阅读

热门阅读