小明思考

          Just a software engineer
          posts - 124, comments - 36, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          leveldb研究11- 流程分析:讀數(shù)據(jù)

          Posted on 2012-03-21 17:30 小明 閱讀(2736) 評論(0)  編輯  收藏 所屬分類: 分布式計算
          leveldb讀數(shù)據(jù)

          先看看ReadOptions有哪些參數(shù)可以指定:
          // Options that control read operations
          struct ReadOptions {
            
          // 是否檢查checksum
            
          // Default: false
            bool verify_checksums;

            
          // 是否將此次結(jié)果放入cache
            
          // Default: true
            bool fill_cache;

            
          //是否指定snapshot,否則讀取當(dāng)前版本
            
          // Default: NULL
            const Snapshot* snapshot;

            ReadOptions()
                : verify_checksums(
          false),
                  fill_cache(
          true),
                  snapshot(NULL) {
            }
          };

          下面看看讀取的詳細過程:
          查詢memtable=>查詢previous memtable(imm_)=>查詢文件(緩沖)

          Status DBImpl::Get(const ReadOptions& options,
                             
          const Slice& key,
                             std::
          string* value) {
            Status s;
            MutexLock l(
          &mutex_);
            SequenceNumber snapshot;
            
          //設(shè)置snapshot
            if (options.snapshot != NULL) {
              snapshot 
          = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
            } 
          else {
              snapshot 
          = versions_->LastSequence();
            }

            MemTable
          * mem = mem_;
            MemTable
          * imm = imm_;
            Version
          * current = versions_->current();
            mem
          ->Ref();
            
          if (imm != NULL) imm->Ref();
            current
          ->Ref();

            
          bool have_stat_update = false;
            Version::GetStats stats;

            
          // Unlock while reading from files and memtables
            {
              mutex_.Unlock();
              LookupKey lkey(key, snapshot);
              
          //先查詢memtable
              if (mem->Get(lkey, value, &s)) {
                
          // Done
              } else if (imm != NULL && imm->Get(lkey, value, &s)) { //然后查詢previous memtable:imm_
                
          // Done
              } else {
                
          //從文件中讀取
                s = current->Get(options, lkey, value, &stats);
                have_stat_update 
          = true;
              }
              mutex_.Lock();
            }

            
          //是否有文件需要被compaction,參見allowed_seek
            if (have_stat_update && current->UpdateStats(stats)) {
              MaybeScheduleCompaction();
            }
            mem
          ->Unref();
            
          if (imm != NULL) imm->Unref();
            current
          ->Unref();
            
          return s;
          }


          重點來看看從version中讀取:
          Status Version::Get(const ReadOptions& options,
                              
          const LookupKey& k,
                              std::
          string* value,
                              GetStats
          * stats) {
            Slice ikey 
          = k.internal_key();
            Slice user_key 
          = k.user_key();
            
          const Comparator* ucmp = vset_->icmp_.user_comparator();
            Status s;

            stats
          ->seek_file = NULL;
            stats
          ->seek_file_level = -1;
            FileMetaData
          * last_file_read = NULL;
            
          int last_file_read_level = -1;

            
          //從level0向高層查找,如果再低級level中查到,則不再查詢
            std::vector<FileMetaData*> tmp;
            FileMetaData
          * tmp2;
            
          for (int level = 0; level < config::kNumLevels; level++) {
              size_t num_files 
          = files_[level].size();
              
          //本層文件數(shù)為空,則返回
              if (num_files == 0continue;

              
          // Get the list of files to search in this level
              FileMetaData* const* files = &files_[level][0];
              
          if (level == 0) {
                
          //level0特殊處理,因為key是重疊,所有符合條件的文件必須被查找
                tmp.reserve(num_files);
                
          for (uint32_t i = 0; i < num_files; i++) {
                  FileMetaData
          * f = files[i];
                  
          if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
                      ucmp
          ->Compare(user_key, f->largest.user_key()) <= 0) {
                    tmp.push_back(f);
                  }
                }
                
          if (tmp.empty()) continue;

                std::sort(tmp.begin(), tmp.end(), NewestFirst);
                files 
          = &tmp[0];
                num_files 
          = tmp.size();
              } 
          else {
                
          // 二分法查找,某個key只可能屬于一個文件
                uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);
                
          //沒有查到
                if (index >= num_files) {
                  files 
          = NULL;
                  num_files 
          = 0;
                } 
          else {
                  tmp2 
          = files[index];
                  
          if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) {
                    
          // All of "tmp2" is past any data for user_key
                    files = NULL;
                    num_files 
          = 0;
                  } 
          else {
                    files 
          = &tmp2;
                    num_files 
          = 1;
                  }
                }
              }

              
          for (uint32_t i = 0; i < num_files; ++i) { //遍歷本層符合條件的文件
                if (last_file_read != NULL && stats->seek_file == NULL) {
                  
          //seek_file只記錄第一個
                  stats->seek_file = last_file_read;
                  stats
          ->seek_file_level = last_file_read_level;
                }

                FileMetaData
          * f = files[i];
                last_file_read 
          = f;
                last_file_read_level 
          = level;
                
                
          //從table cache中讀取
                Iterator* iter = vset_->table_cache_->NewIterator(
                    options,
                    f
          ->number,
                    f
          ->file_size);
                iter
          ->Seek(ikey);
                
          const bool done = GetValue(ucmp, iter, user_key, value, &s);
                
          if (!iter->status().ok()) { //查找到
                  s = iter->status();
                  delete iter;
                  
          return s;
                } 
          else {
                  delete iter;
                  
          if (done) {
                    
          return s;
                  }
                }
              }
            }

            
          return Status::NotFound(Slice());  // Use an empty error message for speed
          }

          繼續(xù)跟蹤:TableCache

          Iterator* TableCache::NewIterator(const ReadOptions& options,
                                            uint64_t file_number,
                                            uint64_t file_size,
                                            Table
          ** tableptr) {
            
          if (tableptr != NULL) {
              
          *tableptr = NULL;
            }

            
          char buf[sizeof(file_number)];
            EncodeFixed64(buf, file_number);
            Slice key(buf, 
          sizeof(buf));

            
          //從LRU cache中查找
            Cache::Handle* handle = cache_->Lookup(key);
            
          if (handle == NULL) { 
              
          /加載文件
              std::
          string fname = TableFileName(dbname_, file_number);
              RandomAccessFile
          * file = NULL;
              Table
          * table = NULL;
              Status s 
          = env_->NewRandomAccessFile(fname, &file);
              
          if (s.ok()) {
                s 
          = Table::Open(*options_, file, file_size, &table);
              }

              
          if (!s.ok()) {
                assert(table 
          == NULL);
                delete file;
                
          // We do not cache error results so that if the error is transient,
                
          // or somebody repairs the file, we recover automatically.
                return NewErrorIterator(s);
              }

              
          //插入Cache
              TableAndFile* tf = new TableAndFile;
              tf
          ->file = file;
              tf
          ->table = table;
              handle 
          = cache_->Insert(key, tf, 1&DeleteEntry);
            }

            Table
          * table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
            
          //從Table對象中生成iterator
            Iterator* result = table->NewIterator(options);
            result
          ->RegisterCleanup(&UnrefEntry, cache_, handle);
            
          if (tableptr != NULL) {
              
          *tableptr = table;
            }
            
          return result;
          }


          主站蜘蛛池模板: 建水县| 江口县| 阳春市| 工布江达县| 专栏| 景宁| 平乐县| 海兴县| 禹州市| 玛曲县| 广灵县| 怀柔区| 绥化市| 闵行区| 宁津县| 东乡县| 铁力市| 深州市| 兴仁县| 宁陵县| 海门市| 武威市| 新密市| 河北区| 兴安县| 文安县| 徐闻县| 阜新| 凤台县| 彝良县| 喀喇沁旗| 崇州市| 邢台市| 沁阳市| 剑阁县| 黔西县| 黑水县| 尖扎县| 邻水| 西畴县| 德保县|