levaldb写入数据(6)

来源:互联网 发布:白夜追凶剧情分析知乎 编辑:程序博客网 时间:2024/06/09 20:30

前言

数据库只有增删改查,我们在以前写了很多废话,这里就不一一叙述,进入增加数据库内容的代码部分,这里依赖上一篇的初始化,不过我们需要的数据结构,再来提示一下,

正文

这里主要介绍增删改查的一些操作,可是这里有一些奇怪的问题,比如数据过长时候灰产生的bug等等,这里暂时不介绍,主要关注主要流程,具体参数等以后一一介绍。
先看增加,

db_->Put(leveldb::WriteOptions(),"love","life");

这个是增加,我们可以很简单的找到是DBIMP中的write()函数实现了写入操作,具体代码如下:

Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {  Writer w(&mutex_);  w.batch = my_batch;  w.sync = options.sync;  w.done = false;  MutexLock l(&mutex_);  writers_.push_back(&w);  while (!w.done && &w != writers_.front()) {   //一直等到w加入成功,或者w是对列的第一个。就不在等待,这存储过程是同步的。    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;  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_.    {      mutex_.Unlock();      status = log_->AddRecord(WriteBatchInternal::Contents(updates));      bool sync_error = false;      if (status.ok() && options.sync) {        status = logfile_->Sync();        if (!status.ok()) {          sync_error = true;        }      }  //写到log文件中,      if (status.ok()) {        status = WriteBatchInternal::InsertInto(updates, mem_);  //写入到内存中mem_      }      mutex_.Lock();      if (sync_error) {        // The state of the log file is indeterminate: the log record we        // just added may or may not show up when the DB is re-opened.        // So we force the DB into a mode where all future writes fail.        RecordBackgroundError(status);      }    }    if (updates == tmp_batch_) tmp_batch_->Clear();    versions_->SetLastSequence(last_sequence);  }

这里写入操作为了实现异步,也是费尽了心机,这里稍加解释,吧所有要写入的内容写入到一个list中,等待前面没内容或者这条内容已经写入(其他线程给写入了),就不在等待。MakeRoomForWrite()这个其实内容挺多的,但是这里写入少量数据,基本不会出错的,这里就暂时不用搞出空间,开始真正的写入,

log_->AddRecord(WriteBatchInternal::Contents(updates));

这个是写入到log文件中,其实也就是特定的一个文件,用来下次恢复内容,这里设计有点奇怪,但是我也说不清楚,不想深入研究这个东东,写入内存是

WriteBatchInternal::InsertInto(updates, mem_);Status WriteBatchInternal::InsertInto(const WriteBatch* b,                                      MemTable* memtable) {  MemTableInserter inserter;  inserter.sequence_ = WriteBatchInternal::Sequence(b);  inserter.mem_ = memtable;  return b->Iterate(&inserter);}Status WriteBatch::Iterate(Handler* handler) const {......handler->Put(key, value);....}  virtual void Put(const Slice& key, const Slice& value) {    mem_->Add(sequence_, kTypeValue, key, value);  //其实这里才是添加到内存中。    sequence_++;  }  void MemTable::Add(SequenceNumber s, ValueType type,                   const Slice& key,                   const Slice& value) {  // Format of an entry is concatenation of:  //  key_size     : varint32 of internal_key.size()  //  key bytes    : char[internal_key.size()]  //  value_size   : varint32 of value.size()  //  value bytes  : char[value.size()]  size_t key_size = key.size();  size_t val_size = value.size();  size_t internal_key_size = key_size + 8;  const size_t encoded_len =      VarintLength(internal_key_size) + internal_key_size +      VarintLength(val_size) + val_size;  char* buf = arena_.Allocate(encoded_len);  char* p = EncodeVarint32(buf, internal_key_size);  memcpy(p, key.data(), key_size);  p += key_size;  EncodeFixed64(p, (s << 8) | type);  p += 8;  p = EncodeVarint32(p, val_size);  memcpy(p, value.data(), val_size);  assert((p + val_size) - buf == encoded_len);  table_.Insert(buf);}typedef SkipList<const char*, KeyComparator> Table;Table table_;

这里废了好大劲,就是这种,关于SKipList,到底是啥,这里暂时不去介绍,我们现在默认他是一个list即可。

Status DBImpl::Get(const ReadOptions& options,                   const Slice& key,                   std::string* value) {                   ...                   mem->Get(lkey, value, &s)                   ...}

关于MemberTable的Get这里暂时也不详细介绍,主要流程大概就是这样,所有的数据都保存在mem_中
关于删除

Status DB::Delete(const WriteOptions& opt, const Slice& key) {  WriteBatch batch;  batch.Delete(key);  return Write(opt, &batch);Status WriteBatch::Iterate(Handler* handler) const {  ......      case kTypeDeletion:        if (GetLengthPrefixedSlice(&input, &key)) {          handler->Delete(key);        ......}  virtual void Delete(const Slice& key) {    mem_->Add(sequence_, kTypeDeletion, key, Slice());    sequence_++;  }

其他部分这里不介绍了,等着下一篇完全解析mem_的结构,好好看看增删改查如何实现,

后记

这里等了好久,终于读完了DBIMP的主要流程,发现又遇到一个坑,这里我们慢慢踩,这些代码,我总有一天,可以啃完,以后可以慢慢分析一下指针和引用等一些知识,

原创粉丝点击