<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>petermao的技术blog &#187; key</title>
	<atom:link href="http://www.petermao.com/tag/key/feed" rel="self" type="application/rss+xml" />
	<link>http://www.petermao.com</link>
	<description>欢迎探讨，共同进步</description>
	<lastBuildDate>Fri, 17 Feb 2017 07:03:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.1</generator>
		<item>
		<title>leveldb注释7–key与value</title>
		<link>http://www.petermao.com/leveldb/leveldb-7-key-value.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=leveldb-7-key-value</link>
		<comments>http://www.petermao.com/leveldb/leveldb-7-key-value.html#comments</comments>
		<pubDate>Sun, 14 Jul 2013 03:04:51 +0000</pubDate>
		<dc:creator>petermao</dc:creator>
				<category><![CDATA[leveldb]]></category>
		<category><![CDATA[key]]></category>
		<category><![CDATA[存储]]></category>
		<category><![CDATA[源码分析]]></category>

		<guid isPermaLink="false">http://www.petermao.com/?p=768</guid>
		<description><![CDATA[作为一个kv的系统，key的存储至关重要。在leveldb中，主要涉及到如下几个key，user_key、InternalKey与LookupKey(memtable_key)。 其关系构成如下图。user_key就是用户输入的key，而InternalKey在user_key的基础上封装了sequence_num+type。sequence_num是一个全局递增的序列号，每一次Put操作都会递增。这样，不同时间的写入操作会得到不一样的sequence_num。前面章节中提到的sstable单条record中的key，其内部其实就是一个InternalKey。sequence_num主要跟snapshot机制与version机制相关，对压缩会产生一定影响。这些我们在后续章节分析。根据type字段，可以获知本次写入操作是写还是删除（也就是说删除是一种特殊的写）。而LookupKey/memtable_key用于在memtable中，多了一个长度字段。代码主要在dbformat.cc/.h中。 static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { assert(seq &#60;= kMaxSequenceNumber); assert(t &#60;= kValueTypeForSeek); return (seq &#60;&#60; \8) &#124; t; } skiplist中的单个节点不仅存储了Key，也存储了value。格式如下图。尽管单个节点的开头部分是一个LookupKey，但其内部比较时，还是使用的InternalKey。也就是说，比较时，先使用InternalKey内部的user_key进行比较，再比较sequence_num。这样不管是memtable还是sstable文件，其内部都是按InternalKey有序的。 int InternalKeyComparator::Compare(const Slice&#38; akey, const Slice&#38; bkey) const { // Order by: // increasing user key (according &#8230; <a href="http://www.petermao.com/leveldb/leveldb-7-key-value.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>作为一个kv的系统，key的存储至关重要。在leveldb中，主要涉及到如下几个key，user_key、InternalKey与LookupKey(memtable_key)。<br />
其关系构成如下图。user_key就是用户输入的key，而InternalKey在user_key的基础上封装了sequence_num+type。sequence_num是一个全局递增的序列号，每一次Put操作都会递增。这样，不同时间的写入操作会得到不一样的sequence_num。前面章节中提到的sstable单条record中的key，其内部其实就是一个InternalKey。sequence_num主要跟snapshot机制与version机制相关，对压缩会产生一定影响。这些我们在后续章节分析。根据type字段，可以获知本次写入操作是写还是删除（也就是说删除是一种特殊的写）。而LookupKey/memtable_key用于在memtable中，多了一个长度字段。代码主要在dbformat.cc/.h中。<span id="more-768"></span><br />
<div id="attachment_797" class="wp-caption alignnone" style="width: 485px"><a href="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-lookup-key.png"><img src="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-lookup-key.png" alt="leveldb lookup key" title="leveldb lookup key" width="475" height="230" class="size-full wp-image-797" /></a><p class="wp-caption-text">leveldb lookup key</p></div></p>
<pre class="wp-code-highlight prettyprint">
static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
  assert(seq &lt;= kMaxSequenceNumber);
  assert(t &lt;= kValueTypeForSeek);
  return (seq &lt;&lt;  \8) | t;
}
</pre>
<p>skiplist中的单个节点不仅存储了Key，也存储了value。格式如下图。尽管单个节点的开头部分是一个LookupKey，但其内部比较时，还是使用的InternalKey。也就是说，比较时，先使用InternalKey内部的user_key进行比较，再比较sequence_num。这样不管是memtable还是sstable文件，其内部都是按InternalKey有序的。<br />
<div id="attachment_799" class="wp-caption alignnone" style="width: 631px"><a href="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-skiplist.png"><img src="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-skiplist.png" alt="leveldb skiplist node" title="leveldb skiplist node" width="621" height="72" class="size-full wp-image-799" /></a><p class="wp-caption-text">leveldb skiplist node</p></div></p>
<pre class="wp-code-highlight prettyprint">
int InternalKeyComparator::Compare(const Slice&amp; akey, const Slice&amp; bkey) const {
  // Order by:
  //    increasing user key (according to user-supplied comparator)
  //    decreasing sequence number
  //    decreasing type (though sequence# should be enough to disambiguate)
  int r = user_comparator_-&gt;Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
  if (r == 0) {
    const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
    const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
    if (anum &gt; bnum) {
      r = -1;
    } else if (anum &lt; bnum) {
      r = +1;
    }
  }
  return r;
}
</pre>
<p>在进行Get操作时，leveldb会使用用户传入的user_key与当前db最大的sequence_num进行合并，以得到LookupKey（实际还会受snapshot机制影响）。但在内部查找时还是使用的InternalKey。</p>
<p>Put操作会稍微复杂点。leveldb的3种写入操作最终都会封装成WriteBatch。这3种写入操作分别是Put(写入单条key<br />
/value)、Delete(删除单条key)、Write(批量进行Put与Delete操作)。WriteBath的内部格式如下图。WriteBatch所表示的多条记录最终会按SkipList所要求的格式1条条地顺序插入到memtable中。<br />
<div id="attachment_801" class="wp-caption alignnone" style="width: 631px"><a href="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-writebatch.png"><img src="http://www.petermao.com/wp-content/uploads/2013/11/leveldb-writebatch.png" alt="leveldb writebatch" title="leveldb writebatch" width="621" height="141" class="size-full wp-image-801" /></a><p class="wp-caption-text">leveldb writebatch</p></div></p>
<pre class="wp-code-highlight prettyprint">
Status WriteBatchInternal::InsertInto(const WriteBatch* b,
                                      MemTable* memtable) {
  MemTableInserter inserter;
  // memtable 的初始sequence为WriteBatchInternal中的seq
  inserter.sequence_ = WriteBatchInternal::Sequence(b);
  inserter.mem_ = memtable;
  return b-&gt;Iterate(&amp;inserter);
}

Status WriteBatch::Iterate(Handler* handler) const {
  Slice input(rep_);
  if (input.size() &lt; kHeader) {
    return Status::Corruption(&quot;malformed WriteBatch (too small)&quot;);
  }
  // kHeader=12 = seq(8字节) + count(4字节)
  input.remove_prefix(kHeader);
  Slice key, value;
  int found = 0;
  while (!input.empty()) {
    found++;
    char tag = input[0];
    // type:1字节
    input.remove_prefix(1);
    switch (tag) {
      case kTypeValue:
        if (GetLengthPrefixedSlice(&amp;input, &amp;key) &amp;&amp;
            GetLengthPrefixedSlice(&amp;input, &amp;value)) {
          handler-&gt;Put(key, value);
        } else {
          return Status::Corruption(&quot;bad WriteBatch Put&quot;);
        }
        break;
      case kTypeDeletion:
        if (GetLengthPrefixedSlice(&amp;input, &amp;key)) {
          handler-&gt;Delete(key);
        } else {
          return Status::Corruption(&quot;bad WriteBatch Delete&quot;);
        }
        break;
      default:
        return Status::Corruption(&quot;unknown WriteBatch tag&quot;);
    }
  }
  if (found != WriteBatchInternal::Count(this)) {
    return Status::Corruption(&quot;WriteBatch has wrong count&quot;);
  } else {
    return Status::OK();
  }
}
</pre>
<p>关于读写压缩等对key/value的具体操作，我们在后续章节进行分析，这里只需要了解大概。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.petermao.com/leveldb/leveldb-7-key-value.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
