首页 > 编程语言 >StarRocks Segment源码阅读笔记--Page的组成

StarRocks Segment源码阅读笔记--Page的组成

时间:2023-07-19 20:23:07浏览次数:73  
标签:body StarRocks footer -- 源码 compressed codec page size

Page由4部分组成

PageBody,PageFooter,FooterSize(4),CheckSum(4)

PageBody是由page类型决定的,可能是压缩的。

PageFooter是经过序列化的PageFooterPB。它包含page_type、未压缩的body大小和其他通用的元数据。如果PageBody的大小和未压缩的body大小一致,则表示这个page是未压缩的。

FooterSize表示PageFooter的长度。

CheckSum是前面3部分的crc32值。

对应的类为PageIO,包含的成员函数如下:

class PageIO {
public:
    // Compress `body' using `codec' into `compressed_body'.
    // The size of returned `compressed_body' is 0 when the body is not compressed, this
    // could happen when `codec' is null or space saving is less than `min_space_saving'.
/*BlockCompressionCodec是对压缩算法的封装,通过上面的注释可以看出该函数的作用是使用codec将body压缩成compressed_body*/
    static Status compress_page_body(const BlockCompressionCodec* codec, double min_space_saving,
                                     const std::vector<Slice>& body, faststring* compressed_body);

    // Encode page from `body' and `footer' and write to `file'.
    // `body' could be either uncompressed or compressed.
    // On success, the file pointer to the written page is stored in `result'.
/*通过上面的注释可以看出该函数的作用是将body和footer写到文件中,并返回文件指针*/
    static Status write_page(WritableFile* wfile, const std::vector<Slice>& body, const PageFooterPB& footer,
                             PagePointer* result);

    // Convenient function to compress page body and write page in one go.
    static Status compress_and_write_page(const BlockCompressionCodec* codec, double min_space_saving,
                                          WritableFile* wfile, const std::vector<Slice>& body,
                                          const PageFooterPB& footer, PagePointer* result) {
        DCHECK_EQ(footer.uncompressed_size(), Slice::compute_total_size(body));
        faststring compressed_body;
        RETURN_IF_ERROR(compress_page_body(codec, min_space_saving, body, &compressed_body));
        if (compressed_body.size() == 0) { // uncompressed
            return write_page(wfile, body, footer, result);
        }
        return write_page(wfile, {Slice(compressed_body)}, footer, result);
    }

    // Read and parse a page according to `opts'.
    // On success
    //     `handle' holds the memory of page data,
    //     `body' points to page body,
    //     `footer' stores the page footer.
/*通过上面的注释可以看出,该函数的作用是根据opts中指定的参数来解析page,返回page的body和footer*/
    static Status read_and_decompress_page(const PageReadOptions& opts, PageHandle* handle, Slice* body,
                                           PageFooterPB* footer);
};

 将数据写入page时,先调用compress_page_body对数据进行压缩,对应的代码如下:

Status PageIO::compress_page_body(const BlockCompressionCodec* codec, double min_space_saving,
                                  const std::vector<Slice>& body, faststring* compressed_body) {
/*从这里可以看出body是由很多个Slice组成的,Slice其实就是包含data和length的结构,先计算出所有Slice的总长度,
下面会校验是否超过压缩算法支持的最大长度,通过代码中可以了解到LZ4格式LZ4_MAX_INPUT_SIZE的限制,
SNAPPY/LZ4FRAME/ZLIB/ZSTD没有限制,对于LZ4格式,如果超过了最大的长度,则不再对数据进行压缩。*/ size_t uncompressed_size = Slice::compute_total_size(body); auto cleanup = MakeScopedCleanup([&]() { compressed_body->clear(); }); if (codec != nullptr && codec->exceed_max_input_size(uncompressed_size)) { compressed_body->clear(); return Status::OK(); } if (codec != nullptr && uncompressed_size > 0) { /*对于LZ4_FRAME、ZSTD和LZ4,可以使用compression pool,作用是先将压缩的结果放到compression_buffer中,
然后再将compression_buffer中的数据拷贝到compressed_body中,这样做的好处是避免一开始就申请很大块的内存,然后再缩小。*/ if (use_compression_pool(codec->type())) { Slice compressed_slice; RETURN_IF_ERROR( codec->compress(body, &compressed_slice, true, uncompressed_size, compressed_body, nullptr)); } else { compressed_body->resize(codec->max_compressed_len(uncompressed_size)); Slice compressed_slice(*compressed_body); RETURN_IF_ERROR(codec->compress(body, &compressed_slice)); compressed_body->resize(compressed_slice.get_size()); } double space_saving = 1.0 - static_cast<double>(compressed_body->size()) / uncompressed_size; // return compressed body only when it saves more than min_space_saving if (space_saving > 0 && space_saving >= min_space_saving) { //空间节省率超过10%的时候执行shrink_to_fit,对空间进行重新整理。 compressed_body->shrink_to_fit(); cleanup.cancel(); return Status::OK(); } } return Status::OK(); }

压缩完毕之后,将数据写到文件中,如下面代码所示:

    std::string footer_buf; // serialized footer + footer size
    footer.SerializeToString(&footer_buf);
    put_fixed32_le(&footer_buf, static_cast<uint32_t>(footer_buf.size()));

    //首先将body放到page中
    std::vector<Slice> page = body;
    //然后将序列化后的footer放到page中
    page.emplace_back(footer_buf);

    // checksum
    uint8_t checksum_buf[sizeof(uint32_t)];
    uint32_t checksum = crc32c::Value(page);
    encode_fixed32_le(checksum_buf, checksum);
    //最后再将checksum值放到page中
    page.emplace_back(checksum_buf, sizeof(uint32_t));

    uint64_t offset = wfile->size();
    //将这个page写到file中
    RETURN_IF_ERROR(wfile->appendv(&page[0], page.size()));

    result->offset = offset;
    result->size = wfile->size() - offset;

至此,page的写入过程完成。

读取page的过程,在函数read_and_decompress_page中实现

auto cache = StoragePageCache::instance();
    PageCacheHandle cache_handle;
    //CacheKey有两个信息组成:文件名称和文件偏移
    StoragePageCache::CacheKey cache_key(opts.read_file->filename(), opts.page_pointer.offset);
    //在StoragePageCache中查找指定的CacheKey是否存在,如果存在,则使用Cache中缓存的page.
    if (opts.use_page_cache && cache->lookup(cache_key, &cache_handle)) {
        // we find page in cache, use it
        *handle = PageHandle(std::move(cache_handle));
        opts.stats->cached_pages_num++;
        // parse body and footer
        Slice page_slice = handle->data();
        uint32_t footer_size = decode_fixed32_le((uint8_t*)page_slice.data + page_slice.size - 4);
        //解析得到footer
        std::string footer_buf(page_slice.data + page_slice.size - 4 - footer_size, footer_size);
        if (!footer->ParseFromString(footer_buf)) {
            return Status::Corruption("Bad page: invalid footer");
        }
        //解析得到body
        *body = Slice(page_slice.data, page_slice.size - 4 - footer_size);
        return Status::OK();
    }

如果cache中不存在,则先拿到page的body,再拿到page的footer,如果body是压缩的,则解压,得到解压后的body,并将解压后的数据放到cache中,cache使用的是LRU Cache。

标签:body,StarRocks,footer,--,源码,compressed,codec,page,size
From: https://www.cnblogs.com/snake-fly/p/17566624.html

相关文章

  • mysql创建流程1.如何远程访问数据库 1.面板-->MySQL®数据库 1.创建数据库 2.创建用户 3.给数据库添加新用户[权限] 4.确定添加后在面板中选远程MySQ 1.添加自己的ip进去 2.那服务器ip默认端口号刚才添加的用户名密码就可以远程访问刚才分配权限的数......
  • 【dp,建模】AGC032D Rotation Sort
    ProblemLink有一个长为\(n\)的排列\(p\),给定\(A,B\),你每次可以做以下两种操作之一:选取\(l,r\),将\(p[l:r]\)循环右移,代价为\(A\);选取\(l,r\),将\(p[l:r]\)循环左移,代价为\(B\)。求将\(p\)排序所需的最小代价。\(n\le5000\)。技巧:循环移位→插入→实数坐......
  • Day-4 返回值
    常见问题中文显示ascci码  可以看到返回值变成了编码  ......
  • vue基本操作[2] 续更----让世界感知你的存在
    Vue文件解析什么是<template/>标签template是html5新元素,主要用于保存客户端中的内容,表现为浏览器解析该内容但不渲染出来,可以将一个模板视为正在被存储以供随后在文档中使用的一个内容片段。关于单文件组件vue的单文件相当于一个页面中的组件,包含了关于该组件的html-css-js文......
  • 【linux】gcc编译选项:-fomit-frame-pointer,-fno-tree-vectorize,-fno-strict-aliasing
    Date:2018.9.81、参考https://www.cnblogs.com/islandscape/p/3444122.htmlhttps://blog.csdn.net/chdhust/article/details/8462414https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc.pdfhttps://blog.csdn.net/u012927281/article/details/50999138https://blog.csdn.net/sof......
  • 10亿级用户,如何做 熔断降级架构?微信和hystrix的架构对比
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • Windows下将“使用VSCode打开”添加至右键菜单“
    Windows下将“使用VSCode打开”添加至右键菜单"本文转载自 Windows下将“使用VSCode打开”添加至右键菜单",特此记录收藏一下。问题:Windows上面安装VisualStudioCode编辑器后,常常会因为安装的时候忘记勾选等原因,没有将OpenwithCode(右键快捷方式)"添加到鼠标右键菜单里,所......
  • Python基础day48
    伪类选择器<style>/*未访问时候显示的*/a:link{color:#FF0000;}/*鼠标移动到链接上*/a:hover{color:#FF00FF}/*选定的链接鼠标点击时出现*/a:active{c......
  • 在C语言中嵌入python,未定义的符号。PyExc_ImportError
    本文是小编为大家收集整理的关于在C语言中嵌入python,未定义的符号。PyExc_ImportError的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。中文English问题描述点击免费获取 CRMEB开源商城系统源码 ......
  • 2023.7.19 周三:冒泡排序
    1importjava.sql.SQLOutput;2importjava.util.Arrays;3importjava.util.Scanner;4//冒泡排序5publicclasstest{6publicstaticvoidmain(String[]args){7int[]a={5,4,6,8,9,1,7,2,3};8intarray[]=sort(a);9S......