美文网首页
Protocol Buffer Varint编码简介 与Lua

Protocol Buffer Varint编码简介 与Lua

作者: _SHIZI | 来源:发表于2016-11-05 18:28 被阅读0次

    1.Protocol Buffer编码

    什么是Protocol Buffer(下称pb),这边也就不介绍了,通常要求不是特别严格的时候Json,甚至XML就能满足要求。
    如需了解这边传送门:

    https://developers.google.com/protocol-buffers/

    message Test1 { required int32 a = 1; }
    pb以二进制形式存储,以Base 128 Varints进行编码,Test1的存储内容仅为3个字节:

    08 96 01

    这是什么意思呢?

    Varints are a method of serializing integers using one or more bytes. Smaller numbers take a smaller number of bytes.
    Each byte in a varint, except the last byte, has the most significant bit (msb) set – this indicates that there are further bytes to come. The lower 7 bits of each byte are used to store the two's complement representation of the number in groups of 7 bits, least significant group first.

    在Varints中,每个Byte的取低7位进行存储实际内容。最高位用1来表示most significant bit,既表示下一个Byte跟当前Byte存储的是同一个Varint;用0来表示least significant bit看完这里,相信大家知道,对于一个完全的int64,其实用varints真实物理存储会超过64位

    那么接下来解释Test1的存储,首先先一张表

    Type Meaning Used For
    0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
    1 64-bit fixed64, sfixed64, double
    2 Length-delimited string, bytes, embedded messages, packed repeated fields
    3 Start group groups (deprecated)
    4 End group groups (deprecated)
    5 32-bit fixed32, sfixed32, float

    当一个Message被encode的时候,message的key其实只存了filed number以及一个wire type,filed number被你定义在.proto文件中,wire type即上面的表格中对应的。
    每一个varint key 为 field_number << 3 | wire_type,言下之意,一个varint key的某三位存的是wire type,后4位存的是filed number。
    以Test1为例,我们知道第一Byte通常就是varint key,Test1的内容是 08,也就是:
    000 1000
    于是我们有filed number = 0001,wire type = 0。因此我们也得到了如下信息,在filed number = 1的地方 存储着一个varint。
    然后我们接下去读
    96 01 = 1001 00110 0000 0001
    基于varint的存储表示: 000 0001 001 00110 -> 10010110 = 150
    所以我们知道存储的值为150。

    2.Lua PB 与int_64

    情景是这样的,我们有一个server用的是openresty,语言用的是lua,lua的解释器是luajit。至于为什么是luajit,我就不展开了,我们直奔主题,luajit是不支持int_64。但是可以通过ffi,间接的操作int_64。
    lua本身也没有官方支持的pb解释器,我们用的是下面这个库:

    https://github.com/Neopallium/lua-pb
    但是之前这个库在pack int_64的时候有一个BUG(在我们同事提了issue后,刚刚上去看了一下已修复,囧rz。。。)

    但我还是把老代码翻出来吧(要不然就写不下去了- -,只能怪自己手慢,再他没更新的时候写就多好啊)

    Bug.jpeg
    先稍微解释一下这个方法,h存的是高32位,l则是低32位。
    每次取7位,然后第八位补1,进行一个递归(如有不懂见上部分)。
    理想的是递归4次后,再处理高位。但是有一个问题,就是如果地位是一个比较小的值,于是就可以递归1-3三次后就开始处理高位了,于是就值就出错了。
    我们最终的实现是加了一个标志位,记录地位处理次数,强制转4个B。不过还是推荐这个作者最后的实现方式,
    local function varint64_next_byte_h_l(h, l) if h ~= 0 then -- encode lower 28 bits. local b1 = bor(band(l, 0x7F), 0x80) local b2 = bor(band(rshift(l, 7), 0x7F), 0x80) local b3 = bor(band(rshift(l, 14), 0x7F), 0x80) local b4 = bor(band(rshift(l, 21), 0x7F), 0x80) -- merg high 32-bits with the last 4 bits from the low 32-bits l = (h * 16) + band(rshift(l, 28), 0xF) -- Use variable length encoding of higher 36 bits. return b1, b2, b3, b4, varint_next_byte(l) end -- No high bits. Use variable length encoding of low bits. return varint_next_byte(l) end

    相关文章

      网友评论

          本文标题:Protocol Buffer Varint编码简介 与Lua

          本文链接:https://www.haomeiwen.com/subject/nxhvuttx.html