leveldb多线程读写(大数据高并发解决方案)

在并发写入的时候,leveldb巧妙的利用一个时间窗口做batch写入,这部分代码值得一读:StatusDBImpl::Write(constWriteOptions&options,WriteBatch*my_batch){  //partA  Writerw(&mutex_);  w.batch=my_batch;  w.sync=options.syn…

大家好,又见面了,我是你们的朋友全栈君。

在并发写入的时候,leveldb巧妙的利用一个时间窗口做batch写入,这部分代码值得一读:

Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {
  
//part A
  Writer w(&mutex_);
  w.batch = my_batch;
  w.sync = options.sync;
  w.done = false;

  //part B
  MutexLock l(&mutex_);
  writers_.push_back(&w);
  while (!w.done && &w != writers_.front()) {
    w.cv.Wait();
  }
  if (w.done) {
    return w.status;
  }
   
  // May temporarily unlock and wait.
  Status status = MakeRoomForWrite(my_batch == NULL);
  uint64_t last_sequence = versions_->LastSequence();
  Writer* last_writer = &w;
    //part C
  if (status.ok() && my_batch != NULL) {  // NULL batch is for compactions
    WriteBatch* updates = BuildBatchGroup(&last_writer);
    WriteBatchInternal::SetSequence(updates, last_sequence + 1);
    last_sequence += WriteBatchInternal::Count(updates);

    // Add to log and apply to memtable.  We can release the lock
    // during this phase since &w is currently responsible for logging
    // and protects against concurrent loggers and concurrent writes
    // into mem_.

    //part D
    {
      mutex_.Unlock();
      status = log_->AddRecord(WriteBatchInternal::Contents(updates));
      if (status.ok() && options.sync) {
        status = logfile_->Sync();
      }
      if (status.ok()) {
        status = WriteBatchInternal::InsertInto(updates, mem_);
      }
      mutex_.Lock();
    }

    if (updates == tmp_batch_) tmp_batch_->Clear();

    versions_->SetLastSequence(last_sequence);
  }

//part E
  while (true) {
    Writer* ready = writers_.front();
    writers_.pop_front();
    if (ready != &w) {
      ready->status = status;
      ready->done = true;
      ready->cv.Signal();
    }
    if (ready == last_writer) break;
  }

   //part F
  // Notify new head of write queue
  if (!writers_.empty()) {
    writers_.front()->cv.Signal();
  }

  return status;
}

     假设同时有w1, w2, w3, w4, w5, w6 并发请求写入。
  B部分代码让竞争到mutex资源的w1获取了锁。w1将它要写的数据添加到了writers_队列里去,此时队列只有一个w1, 从而其顺利的进行buildbatchgroup。当运行到(
part C)时mutex_互斥锁释放,之所以这儿可以释放mutex_,是因为其它的写操作都不满足队首条件,进而不会进入log和memtable写入阶段。这时(w2, w3, w4, w5, w6)会竞争锁,由于B段代码中不满足队首条件,均等待并释放锁了。从而队列可能会如(w3, w5, w2, w4).
  继而w1进行log写入和memtable写入。 当w1完成log和memtable写入后,则mutex_又锁住,这时(PART B)代码中队列因为获取不到锁则队列不会修改。
  随后(
part E)开始,w1被pop出来,由于ready==w, 并且ready==last_writer,所以到(
part F),唤醒了此时处于队首的w3.
      w3唤醒时,发现自己是队首,可以顺利的进行进入buildbatchgroup,在BuildBatchGroup函数中,遍历了目前所有的队列元素,形成一个update的batch,即将w3, w5, w2, w4合并为一个batch. 并将last_writer置为此时处于队尾的最后一个元素w4,(
part D)运行后,因为释放了锁资源,队列可能随着dbimpl::write的调用而更改,如队列状况可能为(w3, w5, w2, w4, w6, w9, w8).
   (
part D)的代码将w3, w5, w2, w4整个的batch写入log和memtable. 到(
part E),分别对w5, w2, w4进行了一次cond signal.当判断到完w4 == lastwriter时,则退出循环。(
part F)则对队首的w6唤醒,从而按上述步骤依次进行下去。
  这样就形成了多个并发write 合并为一个batch写入log和memtable的机制。

转载于:
http://www.cnblogs.com/cobbliu/p/6193164.html 若存在版权问题,请联系。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/127413.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月16日 下午10:00
下一篇 2022年4月16日 下午10:00


相关推荐

  • 计算机考研调剂大概率,调剂经验分享:调剂成功概率太低了?过来人手把手教你如何调剂…[通俗易懂]

    计算机考研调剂大概率,调剂经验分享:调剂成功概率太低了?过来人手把手教你如何调剂…[通俗易懂]调剂经验分享:调剂成功概率太低了?过来人手把手教你如何调剂摘要:调剂变数太大了,所以聪明的同学一定会提前做点什么让调剂尽可能地和自己有关系,然后自己尽可能的被调剂院校看见,那么,关于调剂有什作者梦成真520次阅读2020-06-08摘要:调剂变数太大了,所以聪明的同学一定会提前做点什么让调剂尽可能地和自己有关系,然后自己尽可能的被调剂院校看见,那么,关于调剂有什么经验呢,下面看看是帮帮为大家搜集…

    2022年6月5日
    34
  • vue-router路由懒加载以及三种实现方式「建议收藏」

    vue-router路由懒加载以及三种实现方式「建议收藏」什么是路由懒加载?也叫延迟加载,即在需要的时候进行加载,随用随载。官方解释: 1:当打包构建应用时,JavaScript包会变得非常大,影响页面加载。 2:如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。官方在说什么呢?为什么需要懒加载? 1:首先,我们知道路由中通常会定义很多不同的页面。 2:这个页面这项目build打包后,一般情况下,会放在一个单独的js文件中 3:但是,如果很多的页面都放在同一个js文件.

    2022年10月6日
    6
  • C语言 –位运算

    C语言 –位运算总结一下 自己脑子短路时可以查看一下 一 位运算符 逻辑运算符 amp 位 与 位 异或 位 或 位 非 取反移位运算符 lt lt 左移 gt gt 右移逻辑位运算都是以 bit 为单位 二 非 取反位取反的操作符为 0 变成 1 1 变成 0 需要注意的是 位取反运算并不会改变操作数

    2026年3月19日
    3
  • Openclaw如何对接本地大模型?

    Openclaw如何对接本地大模型?

    2026年3月15日
    3
  • 从零開始学android<ImageSwitcher图片切换组件.二十六.>

    从零開始学android<ImageSwitcher图片切换组件.二十六.>

    2022年1月18日
    46
  • hashmap线程安全吗 什么解决方案_HashMap的底层实现原理

    hashmap线程安全吗 什么解决方案_HashMap的底层实现原理我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,应该使用ConcurrentHashMap,但是其线程不安全体现在什么地方,可能并没有深入理解,本文将对该问题进行解密。

    2025年7月1日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号