编码(util/coding.h util/coding.cc)

LevelDB将整型编码为二进制字符串的形式,同时又能够和ASCII字符区分。

首先是定长编码:

void EncodeFixed32(char *buf, uint32_t value)
{
    if (port::kLittleEndian)
    {
        memcpy(buf, &value, sizeof(value));
    }
    else
    {
        buf[0] = value & 0xff;
        buf[1] = (value >> 8) & 0xff;
        buf[2] = (value >> 16) & 0xff;
        buf[3] = (value >> 24) & 0xff;
    }
}

void EncodeFixed64(char *buf, uint64_t value)
{
    if (port::kLittleEndian)
    {
        memcpy(buf, &value, sizeof(value));
    }
    else
    {
        buf[0] = value & 0xff;
        buf[1] = (value >> 8) & 0xff;
        buf[2] = (value >> 16) & 0xff;
        buf[3] = (value >> 24) & 0xff;
        buf[4] = (value >> 32) & 0xff;
        buf[5] = (value >> 40) & 0xff;
        buf[6] = (value >> 48) & 0xff;
        buf[7] = (value >> 56) & 0xff;
    }
}

这里根据机器区分大端和小端,LevelDB编码后的字符串为小端存储。在编码时,只是简单的将8位二进制码存储在一个char字符的位置上。因为定长,所以可以和ASCII字符区分。

接下来是定长编码的一些接口函数:

void PutFixed32(std::string *dst, uint32_t value)   // 将一个32位整型值定长编码后存入dst
void PutFixed64(std::string *dst, uint64_t value)   // 将一个64位整型值定长编码后存入dst

然后是变长编码:

char *EncodeVarint32(char *dst, uint32_t v)
{
    // Operate on characters as unsigneds
    unsigned char *ptr = reinterpret_cast<unsigned char *>(dst);
    static const int B = 128;
    if (v < (1 << 7))
    {
        *(ptr++) = v;
    }
    else if (v < (1 << 14))
    {
        *(ptr++) = v | B;
        *(ptr++) = v >> 7;
    }
    else if (v < (1 << 21))
    {
        *(ptr++) = v | B;
        *(ptr++) = (v >> 7) | B;
        *(ptr++) = v >> 14;
    }
    else if (v < (1 << 28))
    {
        *(ptr++) = v | B;
        *(ptr++) = (v >> 7) | B;
        *(ptr++) = (v >> 14) | B;
        *(ptr++) = v >> 21;
    }
    else
    {
        *(ptr++) = v | B;
        *(ptr++) = (v >> 7) | B;
        *(ptr++) = (v >> 14) | B;
        *(ptr++) = (v >> 21) | B;
        *(ptr++) = v >> 28;
    }
    return reinterpret_cast<char *>(ptr);
}

char *EncodeVarint64(char *dst, uint64_t v)
{
    static const int B = 128;
    unsigned char *ptr = reinterpret_cast<unsigned char *>(dst);
    while (v >= B)
    {
        *(ptr++) = (v & (B - 1)) | B;
        v >>= 7;
    }
    *(ptr++) = static_cast<unsigned char>(v);
    return reinterpret_cast<char *>(ptr);
}

LevelDB的变长编码设计的十分巧妙,它以7个二进制bit为一个单位,存入一个char中,同时为了和ASCII码进行区分,将char的最高位设为1(ASCII码为0-127),同样采用小端存储的形式。但是变长编码的最后一个char的最高位是0,以此作为变长编码后的字符串的结束标志。

例如,11001011101111001会被编码为11111001 10101110 00000110。

接下来是一些变长编码的接口函数:

void PutVarint32(std::string *dst, uint32_t v)  // 将一个32位整型值变长编码后存入dst
void PutVarint64(std::string *dst, uint64_t v)  // 将一个64位整型值变长编码后存入dst
int VarintLength(uint64_t v)    // 获取变长编码后的字符串长度(以字节计数)
const char *GetVarint32PtrFallback(const char *p,
                                   const char *limit,
                                   uint32_t *value) // 将以p到limit之间的变长编码字符串解码为32位整型值
bool GetVarint32(Slice *input, uint32_t *value) // 将以p到limit之间的变长编码字符串解码为32位整型值并封装入Slice中
const char *GetVarint64Ptr(const char *p, const char *limit, uint64_t *value)   // 将以p到limit之间的变长编码字符串解码为64位整型值
bool GetVarint64(Slice *input, uint64_t *value) // 将以p到limit之间的变长编码字符串解码为64位整型值并封装入Slice中

227 Love u

LevelDB源码分析-编码的更多相关文章

  1. leveldb源码分析--WriteBatch

    从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批 ...

  2. leveldb源码分析--Key结构

    [注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...

  3. leveldb源码分析--SSTable之block

    在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...

  4. Leveldb源码分析--1

    coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...

  5. v74.01 鸿蒙内核源码分析(编码方式篇) | 机器指令是如何编码的 | 百篇博客分析OpenHarmony源码

    本篇关键词:指令格式.条件域.类型域.操作域.数据指令.访存指令.跳转指令.SVC(软件中断) 内核汇编相关篇为: v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的 v75.03 ...

  6. leveldb源码分析--日志

    我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析 ...

  7. leveldb源码分析之Slice

    转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...

  8. LevelDB源码分析--Cache及Get查找流程

    本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...

  9. leveldb源码分析--SSTable之TableBuilder

    上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...

随机推荐

  1. 24. dfs数的路径查找

    输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径. 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. (注意: 在返回值的list中,数组长度大的数组 ...

  2. macbook下mysql安装

    1 原材料 1.1 mysql-5.7.22-macos10.13-x86_64.dmg 2 msql在macbook下的安装: 双击dmg进行解压, 再双击解压出来的pkg文件进行安装 3. Con ...

  3. java.net.BindException: Address already in use: JVM_Bind:80 异常的解决办法

    今天遇见了这个端口被占用问题 然后各种百度 先是说 用命令 netstat -a -n -o 最后一个选项表示连接所在进程id. 找到8080端口的PID然后打开任务管理器, 切换到进程选项卡, 在菜 ...

  4. 百度地图 JavaScript API

    最近有点懒  项目结尾了  完了好长时间 没有去总结项目中的问题 想了下还是写写吧 这是一个关于百度地图的 网页展示 <!DOCTYPE html><html><head ...

  5. 笔记本使用control线连接交换机

    要求: 1.一台笔记本 2.一条usb转rj45串口线 (一端是usb口一端是网口) 连接步骤: usb口插入笔记本,网口插入交换机控制口(交换机上面一般会有标注) 直连步骤: 首先查看是哪个com口 ...

  6. 谈谈 ServerFul 架构

    我写了一篇文章 <自己实现一个线程池>  https://www.cnblogs.com/KSongKing/p/9803935.html , 其实 不仅仅 是 线程池, 中间件 层 的 ...

  7. JAVA 集合操作总结

    1.Collection 1.基本操作 对集合的基础操作 1.boolean add(Object o) //添加对象到集合 2.boolean remove(Object o) //删除指定的对象 ...

  8. Mysql 数据库操作之DDL、DML、DQL语句操作

    Mysql 数据库操作之DDL.DML.DQL语句操作 设置数据库用户名密码 l  Show databases 查看数据库列表信息 l  查看数据库中的数据表信息 ,格式: use 数据库名: sh ...

  9. ubuntu彻底卸载opencv

    说正事之前,先啰嗦两句背景,算是拿个小本本记下了. 我本打算下载opencv2.4.在github上找到源码,在Branch处选择切换到2.4,然后复制URL,在terminal里面使用git clo ...

  10. JavaScript中的匿名函数遇上!会怎么样

    通常,我们声明一个函数test){},可以通过test()来调用这个函数.但是,如果我们在这个函数声明的末尾加上(),解析器是无法理解的. function test(){ console.log(' ...