首页 > Rocksdb Slice使用中的一个小坑

Rocksdb Slice使用中的一个小坑

本文记录一下使用Rocksdb Slice过程中的一个小小坑,差点没一口老血吐出来。

rocksdb的Slice 数据结构是一个小型得不可变类string数据结构,设计出来的目的是为了保证rocksdb内部处理用户输入的key在从内存到持久化磁盘的整个处理链路是不会被修改的,比较方便得从user_key 解码出internal_key

如果把这个数据结构当作普通字符串来使用,会有意想不到的 收获

Slice数据结构代码如下:

class Slice { public:// Create an empty slice.Slice() : data_(""), size_(0) { }// Create a slice that refers to d[0,n-1].Slice(const char* d, size_t n) : data_(d), size_(n) { }// Create a slice that refers to the contents of "s"/* implicit */Slice(const std::string& s) : data_(s.data()), size_(s.size()) { }#ifdef __cpp_lib_string_view// Create a slice that refers to the same contents as "sv"/* implicit */Slice(std::string_view sv) : data_(sv.data()), size_(sv.size()) { }
#endif// Create a slice that refers to s[0,strlen(s)-1]/* implicit */Slice(const char* s) : data_(s) { cout << "called Slice(const char* s)" << endl;size_ = (s == nullptr) ? 0 : strlen(s); }// Create a single slice from SliceParts using buf as storage.// buf must exist as long as the returned Slice exists.Slice(const struct SliceParts& parts, std::string* buf);// Return a pointer to the beginning of the referenced dataconst char* data() const {  return data_; }// Return the length (in bytes) of the referenced datasize_t size() const {  return size_; }// Return true iff the length of the referenced data is zerobool empty() const {  return size_ == 0; }// Return the ith byte in the referenced data.// REQUIRES: n < size()char operator[](size_t n) const { assert(n < size());return data_[n];}...// Return a string that contains the copy of the referenced data.// when hex is true, returns a string of twice the length hex encoded (0-9A-F)// Return a string that contains the copy of the referenced data.std::string ToString(bool hex = false) const { std::string result;  // RVO/NRVO/moveif (hex) { result.reserve(2 * size_);for (size_t i = 0; i < size_; ++i) { unsigned char c = data_[i];result.push_back(toHex(c >> 4));result.push_back(toHex(c & 0xf));}return result;} else { result.assign(data_, size_);return result;}}	......// Compare two slices and returns the first byte where they differsize_t difference_offset(const Slice& b) const;// private: make these public for rocksdbjni accessconst char* data_;size_t size_;// Intentionally copyable
};

主要是其维护了一个const char* data_成员变量,当我们用户通过db->Put(opts, "key","value",)时会调用Slice(const std::string& s)构造函数,并不会维护一个新的存储空间,而是使用本来的默认构造函数为data_分配的地址空间。

坑就来了,也就是想要通过如下方式创建一个新的Slice变量:

map<Slice,int, MetaCmp> mp;
void AddSlice(const Slice& buf, const int& value) { if(mp.find(buf) != mp.end()) { mp[buf] = value;} else { mp.insert(pair<Slice, int>(buf, value));}
}int main() { for(int i = 0;i < 10; i++) { Slice str("meta" + to_string(i));AddSlice(str, i);}return 0;
}

会发现每次创建的Slice都会放在一个地址中,你以为你创建了9个Slice,并且存放到了一个map中,但实际上Slice的数据地址其实只有一个内容。

called default constructor 0x10e756290
called Slice(const std::string& s) meta0 0x7ffee14b5738
called Slice(const std::string& s) meta1 0x7ffee14b5738
called Slice(const std::string& s) meta2 0x7ffee14b5738
called Slice(const std::string& s) meta3 0x7ffee14b5738
called Slice(const std::string& s) meta4 0x7ffee14b5738
called Slice(const std::string& s) meta5 0x7ffee14b5738
called Slice(const std::string& s) meta6 0x7ffee14b5738
called Slice(const std::string& s) meta7 0x7ffee14b5738
called Slice(const std::string& s) meta8 0x7ffee14b5738
called Slice(const std::string& s) meta9 0x7ffee14b5738
key: meta9 value: 9

也就是当我们调用Slice str("meta" + to_string(i));构造一个str对象时,实际存放数据的内存空间内容就已经被修改了,后续的AddSlice函数已经其内部添加到一个map中的操作其实都是在针对已存在的key进行的操作。

归根结底就是其维护了一个const char* data_;成员变量,它约束了当我们启动一个进程时data_指针指向的内容只能是常量区域的一个固定的地址,并不会为各位新开辟一个存储空间。

以上代码切换成我们的string 时,则每一次构造都会重新分配一个新的地址来存放我们的内容。

坑~~~

更多相关:

  • 在H.264之前的标准中,比如H.263,其比特流中的数据是按照一个宏块接一个宏块的方式排列的,一旦发生丢包,很多相邻宏块信息都会丢失,很难进行错误隐藏处理。在H.264中加入了一项新特性:把宏块在比特流中的数据按照一定的映射规则进行排列,而不一定按照原本的光栅扫描顺序排列,这种方称为灵活的宏块重拍FMO(Flexible Macr...

  • mutable的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。   在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。   我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成cons...

  • 前言:很多人都把const int * 、int * const、int const* 的区别和联系搞混,我自己在学习C++的过程中,也经常性          弄不 清楚,今天特意总结一下,作为学习笔记记录下来。 一,const修饰符用于指针         将const用于指针有些很微妙的地方,有两种不同的方式将const关键...

  •   注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客   在/api/demo/文件夹下面创建exportAndDownl...

  • 项目结构 main.js(入口文件,开启9999端口监听,实现RESTful风格接口访问) const express = require("express"); const app = express(); const port = 9999;//设置端口号,如果端口号被占用需要自己修改,否则无法跑起来(建议不要用80和80...

  • ES6 你可能不知道的事 – 基础篇 转载 作者:淘宝前端团队(FED)- 化辰 链接:taobaofed.org/blog/2016/07/22/es6-basics/   序   ES6,或许应该叫 ES2015(2015 年 6 月正式发布),对于大多数前端同学都不陌生。   首先这篇文章不是工具书,不会去过多谈概念,而是...

  • importjava.security.SecureRandom;importjavax.crypto.Cipher;importjavax.crypto.SecretKey;importjavax.crypto.SecretKeyFactory;importjavax.crypto.spec.DESKeySpec;//结果与DES算...

  • 题目:替换空格 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 输入:s = "We are happy." 输出:"We%20are%20happy." 限制: 0 <= s 的长度 <= 10000 解题: 时间复杂度:O(n) 空间复杂度:O(n) class Solution { public:s...

  • 在C++11标准库中,string.h已经添加了to_string方法,方便从其他类型(如整形)快速转换成字面值。 例如: for (size_t i = 0; i < texArrSize; i++)RTX_Shader.SetInt(string("TexArr[") + to_string(i) + "]", 7 + i);...

  • Ubuntu 14.04安装并升级之后,变成楷体字体非常难看,我昨天搞了一晚上,终于理了个头绪,这里整理一下。 经过网上调研,大家的一致看法是,使用开源字体库文泉驿的微黑字体效果比较理想,甚至效果不输windows平台的雅黑字体。下面我打算微黑来美化Ubuntu 14.04. 1.安装文泉驿微黑字体库 sudo aptitude...

  • 使用string时发现了一些坑。 我们知道stl 容器并不是线程安全的,所以在使用它们的过程中往往需要一些同步机制来保证并发场景下的同步更新。 应该踩的坑还是一个不拉的踩了进去,所以还是记录一下吧。 string作为一个容器,随着我们的append 或者 针对string的+ 操作都会让string内部的数据域动态增加,而动态增加的...