关于leveldb源码整理之三

来源:互联网 发布:python instance类型 编辑:程序博客网 时间:2024/06/16 06:25

前言

昨天写了一篇,本来想看点具体的关于真的数据中的源码的问题,可是发现,时间有限,昨天只是,看了下测试的代码,今天我们就搞真的关于数据中数据的编码问题。

正文

工欲善其事必先利其器,我们这里因为需要添加一些测试代码,所以编译机会比较多,我们在我们的makefile中加入一句:

.PHONY: testtest: $(STATIC_OUTDIR)/dbformat_test

以后每次阅读关于dbformatetest的代码时候,就可以直接make test了。
我们进入昨天一小段代码继续看

ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek),            ShortSuccessor(IKey("foo", 100, kTypeValue)));

这里我们知道这个ASSERT_TEST就是判断传入的参数是不是一样。我们可以进入本篇博客的问题空间了。这里我们可以了解到kMaxSequenceNumber是56个1,打小在这里毫无意义,就反正很大很大,kTypeValue 为1.
看下IKey函数到底干了啥,这里我们一一追踪。首先

static std::string IKey(const std::string& user_key,                        uint64_t seq,                        ValueType vt) {  std::string encoded;  AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt));  return encoded;}

这里我们先解决下ParsedInternalKey这个函数干了啥。这个函数其实干的事情很少,这是一个结构体的构造函数:

ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)      : user_key(u), sequence(seq), type(t) {            fprintf(stderr, "==== Test %s\n", "ParsedInternalKey");       }

这里有个问题,我们传入的是个std::string数据,但是最后变成Slice,因为我们会发现Slice有个string为参数的构造函数,这里很容易想到是编译器直接改变传入参数的。这里这个特性,大概就是这个道理,关于Slice的功能,这里就不详细介绍,很简单。这个构造函数,其实就是把传入的三个参数,都保存在三个变量中:

  Slice user_key;  SequenceNumber sequence;  ValueType type;

这里我们很容易的知道这里是干啥的,可以暂时记住,这里要作为参数传入关键的函数,进行编码,我们开始我们本次博客的正餐。

  void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {  result->append(key.user_key.data(), key.user_key.size()); //result = g   PutFixed64(result, PackSequenceAndType(key.sequence, key.type));  //result = g +上 (key.sequence << 8) | 1 转换成16进制数。编码格式是ASSIC.}

这里就是函数的追踪,其实没啥特殊的,这里也许你们会骂娘,可是事实上,只有这么多东西,
这里只是进行了一种编码方式,我们继续第二种:

static std::string ShortSuccessor(const std::string& s) {  std::string result = s;  InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result);  return result;}ShortSuccessor(IKey("foo", 100, kTypeValue)));

IKey("foo", 100, kTypeValue) 这个东西最后生成了“foo+后面的数字的特殊编码”,为11位。我们开始看我们的ShortSuccessor
BytewiseComparator()这个函数是个单例模式,线程安全,具体什么单利模式我也忘记了,反正就是线程安全的单例模式。最终生成了一个BytewiseComparatorImpl这个类,
InternalKeyComparator这个类的构造函数

  explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { }

是不是超级简单,那就不要多说了,总之就是持有一个BytewiseComparatorImpl,关键是最后的这个内部函数我们继续看

void InternalKeyComparator::FindShortSuccessor(std::string* key) const {  Slice user_key = ExtractUserKey(*key);  std::string tmp(user_key.data(), user_key.size());   std::cout<<user_key.ToString()<<"FindShortestSeparator"<<tmp<<std::endl;  user_comparator_->FindShortSuccessor(&tmp);   std::cout<<user_key.ToString()<<"FindShortestSeparator"<<tmp<<std::endl;  if (tmp.size() < user_key.size() &&      user_comparator_->Compare(user_key, tmp) < 0) {    // User key has become shorter physically, but larger logically.    // Tack on the earliest possible number to the shortened user key.    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));    assert(this->Compare(*key, tmp) < 0);    key->swap(tmp);  }}

其实这里用了代理者模式,吧关键人物交给刚才我们的那个IMPL类,具体处理的代码如下:

virtual void FindShortSuccessor(std::string* key) const {    // Find first character that can be incremented    size_t n = key->size();    for (size_t i = 0; i < n; i++) {      const uint8_t byte = (*key)[i];      if (byte != static_cast<uint8_t>(0xff)) {        (*key)[i] = byte + 1;        key->resize(i+1);        return;      }    }    // *key is a run of 0xffs.  Leave it alone.  }

这里处理比较奇怪,吧key作为一个数组,每个字符加1,然后去掉结尾,这里这种用法,很奇怪我暂时不能解释清楚,反正,就是这个指针的指向了一个g(f+1),
至此这个测试函数完全就通了,g==g为真。

后记

写这个系列的博客,也是费劲了心思,c++太多奇怪的特性,我也是醉了。不过总体来说收获还是挺大的,关于变量作用域和其他的一些问题,暂时我也说不清楚,因为这套代码,不是严格意义上的面相对象的代码。充斥着大量的c相关的代码,所以我们还是跟踪主要流程,一些语法细节,以后慢慢总结。

原创粉丝点击