arena是levelDB中的内存池实现
接口 # 没有太多好说的,都非常直观。补了些注释
1 2class Arena { 3 public: 4 Arena(); 5 6 Arena(const Arena&) = delete; 7 Arena& operator=(const Arena&) = delete; 8 9 ~Arena(); 10 11 // Return a pointer to a newly allocated memory block of "bytes" bytes. 12 char* Allocate(size_t bytes); 13 14 // Allocate memory with the normal alignment guarantees provided by malloc. 15 char* AllocateAligned(size_t bytes); 16 17 // Returns an estimate of the total memory usage of data allocated 18 // by the arena. 19 size_t MemoryUsage() const { 20 return memory_usage_.load(std::memory_order_relaxed); 21 } 22 23 private: 24 char* AllocateFallback(size_t bytes); 25 char* AllocateNewBlock(size_t block_bytes); 26 27 // Allocation state 28 // alloc_ptr_ 表示下一个可用的位置 29 char* alloc_ptr_; 30 size_t alloc_bytes_remaining_; 31 32 // Array of new[] allocated memory blocks 33 // 需要注意,vector中每一个元素都是一段内存块(memory, block) 34 std::vector<char*> blocks_; 35 36 // Total memory usage of the arena. 37 // 38 // TODO(costan): This member is accessed via atomics, but the others are 39 // accessed without any locking. Is this OK? 40 std::atomic<size_t> memory_usage_; 41}; 分配策略 # 代码可说的不多,主要想讲讲分配策略
FilterPolicy接口 # 1 2class LEVELDB_EXPORT FilterPolicy { 3 public: 4 virtual ~FilterPolicy(); 5 6 // Return the name of this policy. Note that if the filter encoding 7 // changes in an incompatible way, the name returned by this method 8 // must be changed. Otherwise, old incompatible filters may be 9 // passed to methods of this type. 10 virtual const char* Name() const = 0; 11 12 // keys[0,n-1] contains a list of keys (potentially with duplicates) 13 // that are ordered according to the user supplied comparator. 14 // Append a filter that summarizes keys[0,n-1] to *dst. 15 // 16 // Warning: do not change the initial contents of *dst. Instead, 17 // append the newly constructed filter to *dst. 18 virtual void CreateFilter(const Slice* keys, int n, 19 std::string* dst) const = 0; 20 21 // "filter" contains the data appended by a preceding call to 22 // CreateFilter() on this class. This method must return true if 23 // the key was in the list of keys passed to CreateFilter(). 24 // This method may return true or false if the key was not on the 25 // list, but it should aim to return false with a high probability. 26 virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; 27}; 其中CreateFilter的含义是从n个key生成一个 std::string. 生成的std::string可以包含n个key的信息(类似于生成了一个全集) 从而后续判断某个key是否在其中。
从 Cache 接口进入 LevelDB 的 LRUCache、Handle 生命周期与分片并发设计。
梳理 shared_ptr 的控制块、引用计数、线程安全边界和常见使用陷阱。
背景 # 一种很常见的背景是,需要表示未知类型的数据。比如可能是用户提供的数据,也可能是一个 Cache 的实现,其 value 想支持任意类型的数据
levelDB是一个有序的KV存储,因此key的顺序是十分关键的 levelDB提供用户自己定义key顺序的能力
先看下comparator的接口
接口 include/leveldb/comparator.h # 1 2// A Comparator object provides a total order across slices that are 3// used as keys in an sstable or a database. A Comparator implementation 4// must be thread-safe since leveldb may invoke its methods concurrently 5// from multiple threads. 6class LEVELDB_EXPORT Comparator { 7 public: 8 virtual ~Comparator(); 9 10 // Three-way comparison. Returns value: 11 // < 0 iff "a" < "b", 12 // == 0 iff "a" == "b", 13 // > 0 iff "a" > "b" 14 virtual int Compare(const Slice& a, const Slice& b) const = 0; 15 16 // The name of the comparator. Used to check for comparator 17 // mismatches (i.e., a DB created with one comparator is 18 // accessed using a different comparator. 19 // 20 // The client of this package should switch to a new name whenever 21 // the comparator implementation changes in a way that will cause 22 // the relative ordering of any two keys to change. 23 // 24 // Names starting with "leveldb." are reserved and should not be used 25 // by any clients of this package. 26 virtual const char* Name() const = 0; 27 28 // Advanced functions: these are used to reduce the space requirements 29 // for internal data structures like index blocks. 30 31 // If *start < limit, changes *start to a short string in [start,limit). 32 // Simple comparator implementations may return with *start unchanged, 33 // i.e., an implementation of this method that does nothing is correct. 34 virtual void FindShortestSeparator(std::string* start, 35 const Slice& limit) const = 0; 36 37 // Changes *key to a short string >= *key. 38 // Simple comparator implementations may return with *key unchanged, 39 // i.e., an implementation of this method that does nothing is correct. 40 virtual void FindShortSuccessor(std::string* key) const = 0; 41}; 比较让人迷惑的应该是 FindShortestSeparator 和 FindShortSuccessor 函数。 其实可以简单理解成为了节省存储,而对key做了一定修改。 这个实现是不确定的,甚至完全什么都不做也是合法的。
背景 # 最近在做一个智能算力相关的项目,类似美团外卖广告智能算力的探索与实践 其中实现控制系统需要与数据库交互。虽然最后技术选型并没有使用到levelDB,但是想趁机把代码读了吧。
竟然一下子就2022年了,时间过得真快。 还是简单列一下TODO list吧。
源码 # levelDB workflow 书籍 # APUE # Advanced Programming in the UNIX Environment, 3rd Edition
博客要长草了。。趁着过年时间多,打理一下。。
添加google analytics # hugo本身已经集成了这个功能 要点是集成的是旧版本的universal analytics (对应的是UA-ID) 而目前google主推得其实是新版本google analytics 4(对应的是GA4-ID)
围绕 Robin Hood Hashing、探测距离和存储布局,拆解 ska::flat_hash_map 的实现思路。
从最小复现、指令集与 ABI 差异入手,定位旧版 GCC 环境中的 AVX2 崩溃问题。
背景 # 动手实现一个简单的 Lab,主要依赖于课本第八章的内容。 感觉主要是 05 比较难:一开始发现执行的顺序不太对,原因是 SIGCHLD 里 waitpid 的参数没写对,后面就相对简单了。 累计大概花了 10 个小时的样子。
从数值微分与符号微分出发,解释反向模式自动微分及其计算图实现。
背景 # 动手实现一个 memory allocator,体会 core 到爆炸的乐趣(不是
trace file 结构分析 # trace file 是对 allocator 输入的描述,可以从 mdriver.c 中的
迫于生计,从今天开始学习推荐系统相关的内容,先来读一篇推荐系统领域的综述 Toward the next generation of recommender systems: a survey of the state-of-the-art and possible extensions
由于目前的工作其实偏向推荐系统的 serving、训练的开发,因此这些 paper 可能都是粗读,也不会把 paper 中的内容逐句翻译,而是找出我认为最为重要的一些概念加以记录。
目前我的博客是部署在 GitHub Pages 上,源码是一个 repo,渲染出来的静态页面是一个 repo。更新的时候是把后者作为前者的 submodule。 感觉这种方式有些落后了,简直和某司内部的平台有的一比。因此尝试用 GitHub Actions 来自动化这个部署流程。
本来不知道写什么所以不打算写了,不过后来觉得可以把今年做的一些重大的决定写出来,把当时的分析和想法记录下来。这样若干年后再回看,就能找到:是哪些明智或愚蠢的决定对人生产生了巨大的影响。
背景 # CSAPP:3e 的配套实验 地址 分成了两个部分,第一部分是模拟一下 cache 的 miss、hit、evict 的规则,第二部分是优化一个矩阵的转置,使得 miss 尽可能少。
前言 # 偶然发现了 torch2trt 的模型转换方案,思路是直接将pytorch op映射到TensorRT的python api. 在pytorch进行每个op forward的时候,tensorrt也相应往network上添加op. 这里会先涉及torch2trt的使用,后面会补充这个转换工具的代码学习
写在前面 # 主要是需要在 jetson nano 上做模型转换,来记录下踩的坑。 目前有两条路径,一条是我们现有的转换路径,也就是 pytorch->onnx(->caffe)->trt 的路径。 在这条路径上踩了比较多的坑,最终暂时放弃,最直接的原因是 cudnn8.0 升级接口发生改动,编译 caffe 遇到较多问题。 这里其实仍然采用了两条平行的路径,一条是直接在 nano 上构建环境,另外一种是基于 docker(包括构建交叉编译环境用于加快编译速度)。