Rocksdb 写入数据后 GetApproximateSizes 获取的大小竟然为0?
项目开发中需要从引擎 获取一定范围的数据大小,用作打点上报,测试过程中竟然发现写入了一部分数据之后通过GetApproximateSizes 获取写入的key的范围时取出来的数据大小竟然为0。。。难道发现了一个bug?(欣喜)
因为写入的数据是小于一个sst的data-block(默认是4K),会不会因为GetApproximateSizes 对小于一个data-block的数据大小都默认是0?对于一个严谨的引擎,这么明显的问题显然不可忍。
问题代码:
#include <iostream>
#include <string>#include <rocksdb/db.h>
#include <rocksdb/slice.h>#define VALUE_SIZE 100using namespace std;
using namespace rocksdb;void check_status(Status s, std::string op) {if (!s.ok()) {cout << " Excute " << op << " failed "<< s.ToString() << endl;exit(1);}
}static std::string Key(int i) {char buf[100];snprintf(buf, sizeof(buf), "key%06d", i);return std::string(buf);
}int main() {rocksdb::DB* db;rocksdb::Options options;rocksdb::Status s;options.create_if_missing = true;options.compression = kNoCompression;// 打开dbcheck_status(rocksdb::DB::Open(options, "./db", &db), "Open DB");// 写入10条key-value,value大小是100Bfor (int i = 0;i < 10; i++) {check_status(db->Put(WriteOptions(), Key(i), Slice(string(VALUE_SIZE, 'a' + (i % 26)))), "Put DB");}// 取其中的key范围为[1,3],获取处于这个范围的key-value大小uint64_t size;string start = Key(1);string end = Key(3);Range r(start, end);db->GetApproximateSizes(&r, 1, &size);cout << "Approximate size is " << size << endl; delete db;return 0;
}
最终的执行结果是:
Approximate size is 0
本来开开心心,很明显的问题,想要分析一下原因,向社区提一个PR,结果翻看了一下源代码就没心情了,还是自己太天真。
这个获取指定范围的key大小的接口是有一个额外参数的include_flags
:
virtual void GetApproximateSizes(const Range* ranges, int n, uint64_t* sizes,uint8_t include_flags = INCLUDE_FILES) {GetApproximateSizes(DefaultColumnFamily(), ranges, n, sizes, include_flags);}
这个额外参数是用来指定从rocksdb的哪一个组件获取指定范围的key的大小,比如从memtable,或则 sst?
自己使用默认参数 写入了一小部分数据,显然没有达到触发flush的条件,都会存储在memtable,所以这里从默认的sst文件获取这个范围的key大小时显然获取不到。
可以继续看更底层的实现:
Status DBImpl::GetApproximateSizes(const SizeApproximationOptions& options,ColumnFamilyHandle* column_family,const Range* range, int n, uint64_t* sizes) {......Version* v;auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);auto cfd = cfh->cfd();// 增加针对当前cf的引用SuperVersion* sv = GetAndRefSuperVersion(cfd);v = sv->current;// 允许同时传入多个range,这里对传入的range进行遍历for (int i = 0; i < n; i++) {Slice start = range[i].start;Slice limit = range[i].limit;// Add timestamp if neededstd::string start_with_ts, limit_with_ts;if (ts_sz > 0) {// Maximum timestamp means including all key with any timestampAppendKeyWithMaxTimestamp(&start_with_ts, start, ts_sz);// Append a maximum timestamp as the range limit is exclusive:// [start, limit)AppendKeyWithMaxTimestamp(&limit_with_ts, limit, ts_sz);start = start_with_ts;limit = limit_with_ts;}// Convert user_key into a corresponding internal key.InternalKey k1(start, kMaxSequenceNumber, kValueTypeForSeek);InternalKey k2(limit, kMaxSequenceNumber, kValueTypeForSeek);sizes[i] = 0;// 从sst文件中取指定key范围的大小if (options.include_files) {sizes[i] += versions_->ApproximateSize(options, v, k1.Encode(), k2.Encode(), /*start_level=*/0,/*end_level=*/-1, TableReaderCaller::kUserApproximateSize);}// 从memtable中取出指定key范围的大小,包括mem和immif (options.include_memtabtles) {sizes[i] += sv->mem->ApproximateStats(k1.Encode(), k2.Encode()).size;sizes[i] += sv->imm->ApproximateStats(k1.Encode(), k2.Encode()).size;}}// 释放对superversion的引用ReturnAndCleanupSuperVersion(cfd, sv);return Status::OK();
}
再对应到从sst文件的blockbased table中取数据,需要创建blockbased的index的iter来取start-end key所属的datablock的偏移地址。
如果要从memtable 中取数据,也就是需要遍历skiplist,顺序逐层遍历跳表,找到属于start-end范围内的所有key的个数,统一计算大小。
经过上面一轮的分析,我们就知道了想要通过GetApproximateSizes 获取准确的一个区间内的key-value大小,需要同时计算memtable+sst的大小,这才足够精确。
ps: 同样的数据放在memtable和放在sst中是不一样的,因为sst中除了data-block中key-value数据,还有indexblock,还有metaindex,还有footer。所以统计同样的数据在memtable和sst中会有一些差异。
最终正确使用GetApproximateSizes()
接口的方式如下:
#include <iostream>
#include <string>#include <rocksdb/db.h>
#include <rocksdb/slice.h>#define VALUE_SIZE 100using namespace std;
using namespace rocksdb;void check_status(Status s, std::string op) {if (!s.ok()) {cout << " Excute " << op << " failed "<< s.ToString() << endl;exit(1);}
}static std::string Key(int i) {char buf[100];snprintf(buf, sizeof(buf), "key%06d", i);return std::string(buf);
}int main() {rocksdb::DB* db;rocksdb::Options options;rocksdb::Status s;options.create_if_missing = true;options.compression = kNoCompression;check_status(rocksdb::DestroyDB("./db", options),"DestroyDB");check_status(rocksdb::DB::Open(options, "./db", &db), "Open DB");for (int i = 0;i < 3; i++) {check_status(db->Put(WriteOptions(), Key(i), Slice(string(VALUE_SIZE, 'a' + (i % 26)))), "Put DB");}uint64_t size;string start = Key(1);string end = Key(3);Range r(start, end);db->GetApproximateSizes(&r, 1, &size);cout << "Approximate size is " << size << endl; uint8_t include_both = DB::SizeApproximationFlags::INCLUDE_FILES |DB::SizeApproximationFlags::INCLUDE_MEMTABLES;db->GetApproximateSizes(&r, 1, &size, include_both);cout << "After set memtable flag, Approximate size is " << size << endl; db->Flush(FlushOptions());db->GetApproximateSizes(&r, 1, &size);cout << "After flush, Approximate size is " << size << endl; delete db;return 0;
}
输出如下:
Approximate size is 0
After set memtable flag, Approximate size is 238
After flush, Approximate size is 1151
好吧,不用提bug了。。。。。。
相关文章:

Java项目:在线婚纱摄影预定系统(java+javaweb+SSM+springboot+mysql)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 前后用户的登录注册,婚纱照片分类,查看,摄影师预 订,后台订单管理,图片管理等等。 二、项目运行 环境配置&am…

Linux Terminal 控制终端的使用
1. Open new Terminal:Ctrl Alt T 或者 Ctrl Shift N 2. Open Tab:Ctrl Shift T 3. Close Tab:Ctrl Shift W 4. Close Window:Ctrl Shift Q 5. Copy : Ctrl Shift C 6. Paste: Ctrl Shift V 7. Full Screen: F11 8.…

如何防止代码腐烂
http://blog.jobbole.com/5643/ 很多团队都有这个问题,一个项目的代码本来开始设计得好好的,一段时间以后,代码就会变得难以理解,难以维护,难以修改。为什么?我一直在思考这个问题。 让我们先看一个人的情况…

CORS在Spring中的实现
CORS: 通常情况下浏览器禁止AJAX从外部获取资源,因此就衍生了CORS这一标准体系,来实现跨域请求。 CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源(协议 域名…

从BloomFilter到Counter BloomFilter
文章目录前言1. Traditional BloomFilter2. Counter BloomFilter本文traditional bloomfilter 和 counter bloomfilter的C实现 均已上传至: https://github.com/BaronStack/BloomFilter 前言 Bloomfilter 是一个老生常谈的数据结构,应用在存储领域的各…

进程、线程、多线程相关总结
进程、线程、多线程相关总结 一、说说概念 1、进程(process) 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个程序关于某个数据集合的一次运行。它是操作系统动态执行的基本单元,在传统的操作系统中&#…

Java项目:在线蛋糕商城系统(java+jsp+jdbc+mysql)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 主页显示热销商品;所有蛋糕商品展示,可进行商品搜 索;点击商品进入商品详情页,具有立即购买和加入购物 车功能,可…

业界对生成图片缩略图的做法归纳
网站如果有很多用户上传图片(相册,商品图片),一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的,而shopex之类也大…

thinkPHP5.0 URL路由优化
在tp中访问页面的时候URL地址是 域名/模块/控制器/方法,在点击首页的时候URL是 域名/index/index/index 而不是只显示域名,这样不利于SEO,而且强迫症的我看着很不爽,这个时候我们需要优化路由 Route::rule(路由表达式,路由地址,请…

Rocksdb 获取当前db内部的有效key个数 (估值)
文章目录1. 基本接口2. Memtable key个数统计3. Immutable Memtable key个数统计4. Sstables key个数统计5. 疑问Rocksdb因为是AppendOnly 方式写入,所以没有办法提供db内部唯一key个数的接口(可能存在多版本的key,对用户来说只有一个userkey…

Java项目:网上花店商城系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 一套完整的网上花店商场系统,系统支持前台会员的注册 登陆系统留言,花朵的品种选择,详情浏览,加入购物 车,购买花…

使用Uboot启动内核并挂载NFS根文件系统
配置编译好内核之后,将生成的内核文件uImage拷贝到/tftpboot/下,通过tftp服务器将内核下载到开发板,使用命令:tftp 31000000 uImage.下载完成之后配置bootargs环境变量:setenv bootargs noinitrd consolettySAC0,11520…

Centos系统上安装php遇到的错误解决方法集锦
Centos系统上安装php遇到的错误解决方法集锦1.configure: error: xml2-config not found. Please check your libxml2 installationyum install libxml2 libxml2-devel2.configure: error: Cannot find OpenSSL’s yum install openssl openssl-devel3.configure: error: Pleas…

2.27 MapReduce Shuffle过程如何在Job中进行设置
一、shuffle过程 总的来说: *分区 partitioner*排序 sort*copy (用户无法干涉) 拷贝*分组 group可设置 *压缩 compress*combiner map task端的Reduce二、示例 package com.ibeifeng.hadoop.senior.mapreduce;import java.io.IOException; import java.util.StringTo…

Rocksdb Slice使用中的一个小坑
本文记录一下使用Rocksdb Slice过程中的一个小小坑,差点没一口老血吐出来。 rocksdb的Slice 数据结构是一个小型得不可变类string数据结构,设计出来的目的是为了保证rocksdb内部处理用户输入的key在从内存到持久化磁盘的整个处理链路是不会被修改的&…

Java项目:仿天猫网上商城项目(java+jsp+servlet+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 前台: * 用户模块 * 分类模块 * 商品模块 * 购物车模块 * 订单模块 后台: * 管理员模块 * 分类管理模块 * 商品管理模块 * 订单模块…

转--Android如何在java代码中设置margin
3 在Java代码里设置button的margin(外边距)? 1、获取按钮的LayoutParams LinearLayout.LayoutParams layoutParams (LinearLayout.LayoutParams)button.getLayoutParams(); 2、在LayoutParams中设置margin layoutParams.setMargins(100,20,10,5);//4个参数按顺序分…

poj12月其他题解(未完)
最近编程的时间比较少啊…… poj3253 就是个合并果子,各种优先队列即可(显然单调队列最优) poj3263 线段树统计每个点被覆盖了多少次即可,注意要去重 poj3625 最小生成树 poj3626 bfs poj3624 01背包 poj3615 floyd即可 poj3278 简…

0409-0416的笔记
1 获取前几天,近几个月的时间 function getDay(day) {var today new Date();var targetday_milliseconds today.getTime() 1000 * 60 * 60 * 24 * day;today.setTime(targetday_milliseconds); //注意,这行是关键代码var tYear today.getFullYear();…

Linux NUMA 架构 :基础软件工程师需要知道一些知识
文章目录前言从物理CPU、core到HT(hyper-threading)UMA(Uniform memory access)NUMA架构NUMA下的内存分配策略1. MPOL_DEFAULT2. MPOL_BIND3. MPOL_INTERLEAVE4. MPOL_PREFERRED5. 一些NUMA架构下的内核配置总结参考前言 NUMA(Non-Uniform m…

Java项目:网上书城+后台管理系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述(附带IW文档) 功能: 前台: * 用户模块 * 分类模块 * 图书模块 * 购物车模块 * 订单模块 后台: * 管理员模块 * 分类管理模块 * 图书管理模块 * 订单模块 …

java.util.concurrent包API学习笔记
newFixedThreadPool 创建一个固定大小的线程池。 shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭。 awaitTermination():用于等待子线程结束,再继续执行下面的代码。该例中我设置一直等着子线程结束。Java…

oracle读书记录
很久没有关注自己怕博客了,差不多有两年了。虽然这两年来一直关注51CTO,每天上班打开电脑或者周末在家开启电脑的时候都会浏览一下,这已经是习惯了,但是把自己的blog给忘了。今天,周末,2013年12月21日,同往…

输入、方法的运用
/ /猜数游戏,编写一个功能,完成猜数游戏,产生一个1~10之间的随机数 //与输入的数对对比,返回结果 猜中和没猜中 import java.util.Scanner; //引入(输入)的util包Scanner public class HelloWorld { public static void main(String[] args) {System…

Rocksdb 利用recycle_log_file_num 重用wal-log文件
recycle_log_file_num 复用wal文件信息, 优化wal文件的空间分配,减少pagecache中文件元信息的更新开销。 为同事提供了一组rocksdb写优化参数之后有一个疑惑的现象被问到,发现之前的一些代码细节有遗忘情况,同时也发现了这个参数…

Java项目:网上商城系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述(需求文档PPT) 功能: 主页显示热销商品;所有商品展示,可进行商品搜索;点 击商品进入商品详情页,显示库存&…

clock函数返回负值~ (转)
使用clock() 函数来进行计时,时不时的返回一个很大的负数,怎么检查也检查不出错误,现在找出错误原因,给大家分享一下。 来源网页:http://kebe-jea.blogbus.com/logs/33603387.html 跑实验的时候,结果时不时…

c实现面向对象编程(3)
http://blog.csdn.net/kennyrose/article/details/7564105转载于:https://www.cnblogs.com/pengkunfan/p/3486612.html

echarts - 条形图grid设置距离绘图区域的距离
在一些数据量过大的情况下,在一个固定的区域绘图往往需要对图表绘制区域的大小进行动态改变。这时候设置条形图距离绘图区域上下左右的距离可使用如下方式:表示条形图的柱子距离绘图区左边30%,距离右边40%,而距离顶部和底部分别为…

TitanDB 中使用Compaction Filter ,产生了预期之外几十倍的读I/O
Compaction过程中 产生大量读I/O 的背景 项目中因大value 需求,引入了PingCap 参考Wisckey 思想实现的key-value分离存储 titan, 使用过程中因为有用到Rocksdb本身的 CompactionFilter功能,所以就直接用TitanDB的option 传入了compaction fi…