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


相关推荐

  • 微信开放平台:微信扫码登录功能

    微信开放平台:微信扫码登录功能文章目录微信开放平台:微信扫码登录功能1.授权流程说明2.授权流程代码3.用户登录和登出微信开放平台:微信扫码登录功能官方文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html1.授权流程说明微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(a

    2022年4月29日
    86
  • vue往数组中添加元素_vuejs给数组添加元素[通俗易懂]

    vue往数组中添加元素_vuejs给数组添加元素[通俗易懂]2016-09-13更新问题vuejs给数组添加元素代码是这样的:varvm=newVue({el:”#app”,data:{items:[{id:1,message:’Apple’,selected:false,num:1,price:5},{id:2,message:’Peach’,selected:true,num:1,price:10},{id:3,mes…

    2022年5月23日
    46
  • URL转发基础!_URL怎么用

    URL转发基础!_URL怎么用 1、什么是URL转发?所谓URL转发是当你访问一个域名时,将会自动跳转到您所指定的另一个网络地址(URL)。假设abc.com是您要访问的域名,则通过URL转发服务可以实现当访问http://www.abc.com时,自动转向访问另外一个URL,如:http://www.otherdomain.com/somedir/other.htm。URL转发服务尤其对于拥有一个主网站并同时拥有多个域

    2022年10月10日
    2
  • mysql修改用户密码命令_linux下mysql修改用户密码命令

    mysql修改用户密码命令_linux下mysql修改用户密码命令Linux下有时候想要修改用户密码用什么命令呢?下面由学习啦小编为大家整理了linux下mysql修改用户密码命令的相关知识,希望对大家有帮助!linux的mysql修改用户密码命令详解修改的用户都以root为列。分为两种情况:linux修改mysql用户密码情况一、拥有原来的myql的root的密码方法一:在mysql系统外,使用mysqladmin#mysqladmin-uroot-p…

    2022年6月17日
    35
  • 进程、线程、协程

    进程、线程、协程

    2021年10月14日
    45
  • Log:Spdlog初探(1)

    Log:Spdlog初探(1)文章目录Log:Spdlog初探简介spdlog简介安装/使用Headeronlyversion编译静态库Linux版本Windows版本代码说明设置日志输出样式Log:Spdlog初探简介公司需要开新项目,提议更换日志库,交给我让我调研一下spdlog库的使用。spdlog简介Github地址:Github地址官网介绍:Veryfast,header-only/compile…

    2022年6月23日
    45

发表回复

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

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