Leveldb源码分析--10
来源:互联网 发布:java 多张图片合成pdf 编辑:程序博客网 时间:2024/05/29 14:09
6 SSTable之4
6.6 遍历Table
6.6.1 遍历接口
- Iterator* NewIterator(const ReadOptions&options) const;
- {
- return NewTwoLevelIterator(
- rep_->index_block->NewIterator(rep_->options.comparator),
- &Table::BlockReader,const_cast<Table*>(this), options);
- }
- // 函数NewTwoLevelIterator创建了一个TwoLevelIterator对象:
- Iterator* NewTwoLevelIterator(
- Iterator* index_iter,BlockFunction block_function,
- void* arg, constReadOptions& options) {
- return newTwoLevelIterator(index_iter, block_function, arg, options);
- }
typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, constSlice&);
为什么叫TwoLevelIterator呢,下面就来看看。
6.6.2 TwoLevelIterator
我们已经知道各种Block的存储格式都是相同的,但是各自block data存储的k/v又互不相同,于是我们就需要一个途径,能够在使用同一个方式遍历不同的block时,又能解析这些k/v。这就是BlockFunction,它又返回了一个针对block data的Iterator。Block和block data存储的k/v对的key是统一的。
先来看类的主要成员变量:
- BlockFunction block_function_; // block操作函数
- void* arg_; // BlockFunction的自定义参数
- const ReadOptions options_; // BlockFunction的read option参数
- Status status_; // 当前状态
- IteratorWrapper index_iter_; // 遍历block的迭代器
- IteratorWrapper data_iter_; // May be NULL-遍历block data的迭代器
- // 如果data_iter_ != NULL,data_block_handle_保存的是传递给
- // block_function_的index value,以用来创建data_iter_
- std::string data_block_handle_;
S1 对于其Key和Value接口都是返回的data_iter_对应的key和value:
- virtual bool Valid() const {
- return data_iter_.Valid();
- }
- virtual Slice key() const {
- assert(Valid());
- return data_iter_.key();
- }
- virtual Slice value() const {
- assert(Valid());
- return data_iter_.value();
- }
- void InitDataBlock();
- void SetDataIterator(Iterator*data_iter); //设置date_iter_ = data_iter
- voidSkipEmptyDataBlocksForward();
- voidSkipEmptyDataBlocksBackward();
- if (!index_iter_.Valid()) SetDataIterator(NULL);// index_iter非法
- else {
- Slice handle =index_iter_.value();
- if (data_iter_.iter() != NULL&& handle.compare(data_block_handle_) == 0) {
- //data_iter已经在该block data上了,无须改变
- } else { // 根据handle数据定位data iter
- Iterator* iter =(*block_function_)(arg_, options_, handle);
- data_block_handle_.assign(handle.data(), handle.size());
- SetDataIterator(iter);
- }
- }
- while (data_iter_.iter() == NULL|| !data_iter_.Valid()) { // 跳到下一个block
- if (!index_iter_.Valid()) { // 如果index iter非法,设置data iteration为NULL
- SetDataIterator(NULL);
- return;
- }
- index_iter_.Next();
- InitDataBlock();
- if (data_iter_.iter() != NULL)data_iter_.SeekToFirst(); // 跳转到开始
- }
- while (data_iter_.iter() == NULL|| !data_iter_.Valid()) { // 跳到前一个block
- if (!index_iter_.Valid()) { // 如果index iter非法,设置data iteration为NULL
- SetDataIterator(NULL);
- return;
- }
- index_iter_.Prev();
- InitDataBlock();
- if (data_iter_.iter() != NULL)data_iter_.SeekToLast();// 跳转到开始
- }
- void TwoLevelIterator::Seek(const Slice& target) {
- index_iter_.Seek(target);
- InitDataBlock(); // 根据index iter设置data iter
- if (data_iter_.iter() != NULL)data_iter_.Seek(target); // 调整data iter跳转到target
- SkipEmptyDataBlocksForward(); // 调整iter,跳过空的block
- }
- void TwoLevelIterator::SeekToFirst() {
- index_iter_.SeekToFirst();
- InitDataBlock();// 根据index iter设置data iter
- if (data_iter_.iter() != NULL)data_iter_.SeekToFirst();
- SkipEmptyDataBlocksForward();// 调整iter,跳过空的block
- }
- void TwoLevelIterator::SeekToLast() {
- index_iter_.SeekToLast();
- InitDataBlock();// 根据index iter设置data iter
- if (data_iter_.iter() != NULL)data_iter_.SeekToLast();
- SkipEmptyDataBlocksBackward();// 调整iter,跳过空的block
- }
- void TwoLevelIterator::Next() {
- assert(Valid());
- data_iter_.Next();
- SkipEmptyDataBlocksForward();// 调整iter,跳过空的block
- }
- void TwoLevelIterator::Prev() {
- assert(Valid());
- data_iter_.Prev();
- SkipEmptyDataBlocksBackward();// 调整iter,跳过空的block
- }
6.6.3 BlockReader()
static Iterator* Table::BlockReader(void* arg, const ReadOptions&options,
constSlice& index_value);
它根据参数指明的blockdata,返回一个iterator对象,调用者就可以通过这个iterator对象遍历blockdata存储的k/v对,这其中用到了LRUCache。
函数实现逻辑如下:
S1 从参数中解析出BlockHandle对象,其中arg就是Table对象,index_value存储的是BlockHandle对象,读取Block的索引。
- Table* table =reinterpret_cast<Table*>(arg);
- Block* block = NULL;
- Cache::Handle* cache_handle =NULL;
- BlockHandle handle;
- Slice input = index_value;
- Status s =handle.DecodeFrom(&input);
- Cache* block_cache =table->rep_->options.block_cache;
- BlockContents contents;
- if (block_cache != NULL) {
- char cache_key_buffer[16]; // cache key的格式为table.cache_id + offset
- EncodeFixed64(cache_key_buffer, table->rep_->cache_id);
- EncodeFixed64(cache_key_buffer+8, handle.offset());
- Slice key(cache_key_buffer,sizeof(cache_key_buffer));
- cache_handle =block_cache->Lookup(key); // 尝试从LRU cache中查找
- if (cache_handle != NULL) { // 找到则直接取值
- block =reinterpret_cast<Block*>(block_cache->Value(cache_handle));
- } else { // 否则直接从文件读取
- s =ReadBlock(table->rep_->file, options, handle, &contents);
- if (s.ok()) {
- block = new Block(contents);
- if (contents.cachable&& options.fill_cache) // 尝试加到cache中
- cache_handle =block_cache->Insert(
- key, block,block->size(), &DeleteCachedBlock);
- }
- }
- } else {
- s =ReadBlock(table->rep_->file, options, handle, &contents);
- if (s.ok()) block = newBlock(contents);
- }
- Iterator* iter;
- if (block != NULL) {
- iter =block->NewIterator(table->rep_->options.comparator);
- if (cache_handle == NULL) iter->RegisterCleanup(&DeleteBlock,block, NULL);
- else iter->RegisterCleanup(&ReleaseBlock,block_cache, cache_handle);
- } else iter = NewErrorIterator(s);
- static void DeleteBlock(void* arg, void* ignored) { deletereinterpret_cast<Block*>(arg);}
- static void DeleteCachedBlock(const Slice& key, void* value) {
- Block* block =reinterpret_cast<Block*>(value);
- delete block;
- }
- static void ReleaseBlock(void* arg, void* h) {
- Cache* cache =reinterpret_cast<Cache*>(arg);
- Cache::Handle* handle =reinterpret_cast<Cache::Handle*>(h);
- cache->Release(handle);
- }
6.7 定位key
uint64_t ApproximateOffsetOf(const Slice& key) const;
函数实现比较简单:
S1 调用Block::Iter的Seek函数定位
- Iterator* index_iter=rep_->index_block->NewIterator(rep_->options.comparator);
- index_iter->Seek(key);
- uint64_t result;
- BlockHandle handle;
- handle.DecodeFrom(&index_iter->value());
- result = handle.offset();
6.8 获取Key—InternalGet()
Status Table::InternalGet(const ReadOptions& options, constSlice& k,
void*arg, void (*saver)(void*, const Slice&, const Slice&))
其中又有函数指针,在找到数据后,就调用传入的函数指针saver执行调用者的自定义处理逻辑,并且TableCache可能会做缓存。
函数逻辑如下:
S1 首先根据传入的key定位数据,这需要indexblock的Iterator。
- Iterator* iiter =rep_->index_block->NewIterator(rep_->options.comparator);
- iiter->Seek(k);
- Status s;
- Slice handle_value =iiter->value();
- FilterBlockReader* filter = rep_->filter;
- BlockHandle handle;
- if (filter != NULL && handle.DecodeFrom(&handle_value).ok()
- && !filter->KeyMayMatch(handle.offset(),k)) { // key不存在
- } else{// 否则就要读取block,并查找其k/v对
- Slice handle = iiter->value();
- Iterator* block_iter =BlockReader(this, options, iiter->value());
- block_iter->Seek(k);
- if (block_iter->Valid())(*saver)(arg, block_iter->key(), block_iter->value());
- s = block_iter->status();
- delete block_iter;
- }
- if (s.ok()) s =iiter->status();
- delete iiter;
- return s;
0 0
- Leveldb源码分析--10
- Leveldb源码分析--10
- LevelDB源码分析10-比较函数
- levelDB源码分析-提纲
- levelDB源码分析-Slice
- levelDB源码分析-Status
- levelDB源码分析-Arena
- levelDB源码分析-Skiplist
- levelDB源码分析-Memtable
- levelDB源码分析-SSTable
- levelDB源码分析-TableCache
- Leveldb源码分析--1
- Leveldb源码分析--2
- Leveldb源码分析--3
- Leveldb源码分析--4
- Leveldb源码分析--5
- Leveldb源码分析
- Leveldb源码分析--6
- [ectouch 调试必备] 显示出错误信息
- <12> go panic
- C++指针与引用(一):函数传参,是该传对象,还是传指针,抑或是引用
- 如何在网页中打开一个本地桌面程序
- 使用delete []出现的堆栈调试错误
- Leveldb源码分析--10
- 链表保存学生信息
- LintCode_数组剔除元素后的乘积
- PHP中正则表达式的用法
- <13> go collection-func
- Leveldb源码分析--11
- 杭电ACM1241(dfs)
- Hibernate.cfg.xml文件的配置
- nyoj--1009--So Easy[Ⅰ](数学)