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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Lua

    Lua

    2021年9月10日
    55
  • Java的常用开发工具

    Java的常用开发工具Java开发人员的常用工具java常用的开发工具。都说工欲善其事必先利其器,要想学好java这门语言,选择一款好用顺手的开发工具是必不可少的。另外面试java工作时开发工具的使用也是一个重要的考核点。要想全面了解java开发工具,我们首先需要先了解一下java程序的开发过程,通过这个过程我们能够了解到java开发都需要用到那些工具。首先我们先了解完整项目开发过程,如图所示:

    2022年5月11日
    45
  • CardView_cardminder是什么软件

    CardView_cardminder是什么软件本文介绍CardView这个控件的使用,CardView继承至FrameLayout类,是support-v7包下的一个类,使用时必须引入cardview依赖包,可在下载的sdk文件夹中找到。。。使用CardView可以实现卡片式布局效果,非常好看,卡片还可以包含圆角、阴影、背景。CardView是一个ViewGroup,布局时包含其它的View从而实现优雅界面效果。首先来看看个界面效果:…

    2022年10月11日
    4
  • elf文件解析器_elf文件下载

    elf文件解析器_elf文件下载前两天网上投递了简历,面试了一家C++公司,然后对面负责人给我发了一份笔试题,题目是:请写出一个ELF文件解析器,需要能打印出所有segments和sections,并列出每个section和segment的映射关系。首先了解elf是什么,它的结构是怎么样的,然后去读一下别人的源码,读懂之后,自己开始编码。源码如下(”elf.h”头文件见后文),它会报warning,但是貌似不太影…

    2025年7月3日
    2
  • mysql有关运维的面试题_mysql数据库运维面试题「建议收藏」

    mysql有关运维的面试题_mysql数据库运维面试题「建议收藏」1.登陆数据库(1)单实例mysql-uroot-poldboy(2)多实例mysql-uroot-poldboy-S/data/3306/mysql.sock2.查看数据库版本及当前登录用户是什么mysql>selectversion();查看版本+————+|version()|+————+|5.5.22-log|+——-…

    2022年6月8日
    91
  • 达梦数据库_达梦的数据库什么水平

    达梦数据库_达梦的数据库什么水平达梦(DM8)数据库由实例和数据库共同组成。实例由一组正在运行的后台进程及其所fork出的一系列线程和分配内存组成。数据库是由一系列存放在操作系统上的文件组成。体系结构图大致为:本文只要针对体系结构中的实例,也就是达梦(DM8)数据库中内存结构与线程结构进行介绍。1.内存池达梦(DM8)实例内存池包括运行时内存和共享内存池组成,可以通过查询动态视图V$MEM_POOL查看当前数据库系统中所有内存池的状态:1.1共享内存池数据库运行时的主要内存池,由数据库参数文件dm.ini中的参数MEMO

    2022年10月19日
    2

发表回复

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

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