LevelDB简介

2023-11-02

综述

level是使用lsm tree作为单机数据结构的存储引擎

内存中的 MemTable 写满后,会转换为 Immutable MemTable,然后被后台线程 compact 成按 key 有序存储的 SSTable(顺序写)。 SSTable 按照数据从新到旧被组织成多个层次(上层新下层旧),点查询(Get)的时候从上往下一层层查找,所以 LevelDB 的读操作可能会有多次磁盘 IO(LevelDB 通过 table cache、block cache 和 bloom filter 等优化措施来减少读操作的 I/O 次数)。 后台线程的定期 compaction 负责回收过期数据和维护每一层数据的有序性。在数据局部有序的基础上,LevelDB 实现了数据的(全局)有序遍历。

leveldb整体架构

LevelDB整体架构

  1. MemTable:内存数据结构,具体实现是 SkipList。 接受用户的读写请求,新的数据会先在这里写入。
  2. Immutable MemTable:当 MemTable 的大小达到设定的阈值后,会被转换成 Immutable MemTable,只接受读操作,不再接受写操作,然后由后台线程 flush 到磁盘上 —— 这个过程称为 minor compaction。
  3. Log:数据写入 MemTable 之前会先写日志,用于防止宕机导致 MemTable 的数据丢失。一个日志文件对应到一个 MemTable
  4. SSTable:Sorted String Table。分为 level-0 到 level-n 多层,每一层包含多个 SSTable,文件内数据有序。除了 level-0 之外,每一层内部的 SSTable 的 key 范围都不相交。
  5. Manifest:Manifest 文件中记录 SSTable 在不同 level 的信息,包括每一层由哪些 SSTable,每个 SSTable 的文件大小、最大 key、最小 key 等信息。
  6. Current:重启时,LevelDB 会重新生成 Manifest,所以 Manifest 文件可能同时存在多个,Current 记录的是当前使用的 Manifest 文件名。
  7. TableCache:TableCache 用于缓存 SSTable 的文件描述符、索引和 filter。
  8. BlockCache:SSTable 的数据是被组织成一个个 block。BlockCache 用于缓存这些 block(解压后)的数据。

提供接口

include
└── leveldb
    ├── c.h              => c binding
    ├── cache.h          => cache接口
    ├── comparator.h     => 比较器接口
    ├── db.h             => DB接口
    ├── env.h            => 为跨平台准备的env接口
    ├── filter_policy.h  => fliter策略,用于缓存,请看到文档及相应实现
    ├── iterator.h       => 迭代器,用于遍历数据库中存储的数据
    ├── options.h        => 包含控制数据库的Options,控制读的WriteOptions,ReadOptions
    ├── slice.h          => Slice的接口
    ├── status.h         => leveldb中大多接口返回的Status接口
    ├── table.h           => immutable接口
    ├── table_builder.h  => 用于创建table的构建器接口
    └── write_batch.h    => 使多个写操作成为原子写的接口

db.h

db.h是使用leveldb时最经常include的头文件.在这个头文件中提供了DB的接口的定义,也是我们需要的部分.在db.h中,定义了Snapshot,Range,DB三个接口.Range为一个Slice对,定义了[start,end).符合C++的习惯.Snapshot为DB的某个特定状态.由于其只读,因此多线程访问并不需要锁.DB则提供了经常使用的几个方法:

class LEVELDB_EXPORT DB {
 public:
  // Open the database with the specified "name".
  // Stores a pointer to a heap-allocated database in *dbptr and returns
  // OK on success.
  // Stores nullptr in *dbptr and returns a non-OK status on error.
  // Caller should delete *dbptr when it is no longer needed.
  static Status Open(const Options& options, const std::string& name,
                     DB** dbptr);

  DB() = default;

  DB(const DB&) = delete;
  DB& operator=(const DB&) = delete;

  virtual ~DB();

  // Set the database entry for "key" to "value".  Returns OK on success,
  // and a non-OK status on error.
  // Note: consider setting options.sync = true.
  virtual Status Put(const WriteOptions& options, const Slice& key,
                     const Slice& value) = 0;

  // Remove the database entry (if any) for "key".  Returns OK on
  // success, and a non-OK status on error.  It is not an error if "key"
  // did not exist in the database.
  // Note: consider setting options.sync = true.
  virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;

  // Apply the specified updates to the database.
  // Returns OK on success, non-OK on failure.
  // Note: consider setting options.sync = true.
  virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;

  // If the database contains an entry for "key" store the
  // corresponding value in *value and return OK.
  //
  // If there is no entry for "key" leave *value unchanged and return
  // a status for which Status::IsNotFound() returns true.
  //
  // May return some other Status on an error.
  virtual Status Get(const ReadOptions& options, const Slice& key,
                     std::string* value) = 0;

  // Return a heap-allocated iterator over the contents of the database.
  // The result of NewIterator() is initially invalid (caller must
  // call one of the Seek methods on the iterator before using it).
  //
  // Caller should delete the iterator when it is no longer needed.
  // The returned iterator should be deleted before this db is deleted.
  virtual Iterator* NewIterator(const ReadOptions& options) = 0;

  // Return a handle to the current DB state.  Iterators created with
  // this handle will all observe a stable snapshot of the current DB
  // state.  The caller must call ReleaseSnapshot(result) when the
  // snapshot is no longer needed.
  virtual const Snapshot* GetSnapshot() = 0;

  // Release a previously acquired snapshot.  The caller must not
  // use "snapshot" after this call.
  virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;

  // DB implementations can export properties about their state
  // via this method.  If "property" is a valid property understood by this
  // DB implementation, fills "*value" with its current value and returns
  // true.  Otherwise returns false.
  //
  //
  // Valid property names include:
  //
  //  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
  //     where <N> is an ASCII representation of a level number (e.g. "0").
  //  "leveldb.stats" - returns a multi-line string that describes statistics
  //     about the internal operation of the DB.
  //  "leveldb.sstables" - returns a multi-line string that describes all
  //     of the sstables that make up the db contents.
  //  "leveldb.approximate-memory-usage" - returns the approximate number of
  //     bytes of memory in use by the DB.
  virtual bool GetProperty(const Slice& property, std::string* value) = 0;

  // For each i in [0,n-1], store in "sizes[i]", the approximate
  // file system space used by keys in "[range[i].start .. range[i].limit)".
  //
  // Note that the returned sizes measure file system space usage, so
  // if the user data compresses by a factor of ten, the returned
  // sizes will be one-tenth the size of the corresponding user data size.
  //
  // The results may not include the sizes of recently written data.
  virtual void GetApproximateSizes(const Range* range, int n,
                                   uint64_t* sizes) = 0;

  // Compact the underlying storage for the key range [*begin,*end].
  // In particular, deleted and overwritten versions are discarded,
  // and the data is rearranged to reduce the cost of operations
  // needed to access the data.  This operation should typically only
  // be invoked by users who understand the underlying implementation.
  //
  // begin==nullptr is treated as a key before all keys in the database.
  // end==nullptr is treated as a key after all keys in the database.
  // Therefore the following call will compact the entire database:
  //    db->CompactRange(nullptr, nullptr);
  virtual void CompactRange(const Slice* begin, const Slice* end) = 0;
};

技术

memtable

MemTable,顾名思议,就是内存表。每个 LevelDB 实例最多会维护两个 MemTable: mem_imm_mem_ 可以读写,imm_ 只读。LevelDB 的 MemTable 的主要功能是将内部编码、内存分配(Arena)和 SkipList 封装在一起。

在 LevelDB 中,最新写入的数据都会保存到 mem_ 中。当 mem_ 的大小超过 write_buffer_size 时,LevelDB 就会将其切换成 imm_,并生成新的 mem_。 LevelDB 的后台线程会将 imm_ compact 成 SSTable 保存在磁盘上。 如果前台的写入速度很快,有可能出现 mem_ 的大小已经超过 write_buffer_size,但是前一个 imm_ 还没有被 compact 到磁盘上,无法切换 MemTable,此时就会出现 stall write(阻塞写请求)。

WAL

为了防止宕机导致数据丢失,在将数据写入 MemTable 之前,会先将数据持久化到 log 文件中。

LevelDB采用这种定长块的方式保存日志呢。其明显的好处是:当日志文件发生数据损坏的时候,这种定长块的模式可以很简单地跳过有问题的块,而不会导致局部的错误影响到整个文件。

目前 LevelDB 没有对日志进行压缩。

sstable

SSTable 全称 Sorted String Table,顾名思义,里面的 key-value 都是有序保存的。除了两个 MemTable,LevelDB 中的大部分数据是以 SSTable 的形式保存在外存上。sstable是只读的,只有compaction才会更改其内容

在一个 SSTable 中,文件末尾的 Footer 是定长的,其他数据都被划分成一个个变长的 block:index block、metaindex block、meta blocks、data blocks。

  • meta blocks:目前 LevelDB 中只有一个 meta block,保存的是这个 SSTable 中的 key 组成的 bloom filter。布隆过滤器
  • Data Block:存储的是实际的 key-value 数据。

levelDB SStable中的block使用了前缀压缩。前缀压缩利用了 key 的有序性(前缀相同的有序 key 会聚集在一起)对 key 进行压缩,每个 key 与前一个 key 相同的前缀部分可以不用保存。读取的时候再根据规则进行解码即可。

Manifest

Manifest 文件保存了整个 LevelDB 实例的元数据,比如:每一层有哪些 SSTable。LevelDB 用 VersionEdit 来表示一次元数据的变更。Manifest 文件保存 VersionEdit 序列化后的数据。

cache

根据功能的不同,LevelDB 中有两种 cache:

  1. Block cache:缓存解压后的 data block,可以加快热数据的查询。
  2. Table cache:缓存打开的 SSTable 文件描述符和对应的 index block、meta block 等信息。

在 LevelDB 中,block cache 和 table cache 都是基于 ShardedLRUCache 实现的。

LRU cache

LevelDB 的 LRUCache 的实现由一个哈希表两个链表组成:

  • 链表 lru_:维护 cache 中的缓存对象的使用热度。数据每次被访问的时候,都会被插入到这个链表最新的地方。 lru_->next 指向最旧的数据, lru_->prev 指向最新的数据。当 cache 占用的内存超过限制时,则从 lru_->next 开始清理数据。
  • 链表 in_use_:维护 cache 中有哪些缓存对象被返回给调用端使用。这些数据不能被淘汰。
  • 哈希表 table_:保存所有 key -> 缓存对象,用于快速查找数据。

LRUCacheInsertLookup 的时间复杂度都是 O(1)。

LRU的优缺点

LRU 是一种常用的缓存淘汰策略,因为大部分情况下,数据的访问都是具有局部性的——最近访问过的数据,短时间内还被访问的概率比较大;而比较久没被访问的数据,短时间内会被访问的概率比较小。

但是当热点数据比较集中时,LRU 的缓存命中率比较高。但是在某些场景下,LRU 的缓存命中率会急剧下降,比如批量遍历

  1. LevelDB 在读参数 ReadOptions 提供了一个参数 fill_cache ,让上层控制是否要将 data block 放入到 block cache。
  2. MySQL 的 InnoDB 的 LRU 缓存实现为了避免扫描操作污染 cache,采用了两级的 LRU cache。数据会先进入第一级 cache,一段时间之后还有访问再放到第二级 cache。

filter

LevelDB 可以设置通过 bloom filter 来减少不必要的读 I/O 次数。

levelDB初始化

一个 LevelDB 实例初始化的主要任务包括:

  1. 从 Manifest 文件恢复各个 level 的 SSTable 的元数据。
  2. 根据 log 文件恢复 MemTable。
  3. 恢复 last_sequence_、next_file_numbe_等元信息。

compaction

compaction的触发

除了从外部调用 CompactRange,LevelDB 有几种情况会自动触发 compaction:

  1. 当 MemTable 的大小达到阈值时,进行 MemTable 切换,然后需要将 Immutable MemTable 刷到外存上 —— 一般称之为 Minor Compaction
  2. 当 level-n 的 SSTable 超过限制,level-n 和 level-n+1 的 SSTable 会进行 compaction —— 一般称之为 Major Compaction
    1. level-0 是通过 SSTable 的数量来判断是否需要 compaction。
    2. level-n(n > 0) 是通过 SSTable 的大小来判断是否需要 compaction。

LevelDB compaction

参考链接

  1. LevelDB 完全解析(0):基本原理和整体架构本文内容很多参考了这个专栏,两张图片也摘自此专栏。系列文章,讲的很详细
  2. LevelDB 完全解析(8):读操作之 Get
  3. leveldb接口
  4. leveldb接口概览
  5. LevelDB library documentation基本使用方法
  6. leveldb iterator 的 Prev 究竟比 Next 差在哪?MemTable是skiplist,next是O(1),prev是O(log(N)),sstable是index_block+data_block,每次反向遍历都需要重新定位index
  7. LevelDB 之 Compaction
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LevelDB简介 的相关文章

  • sql临时表、创建虚拟表、select临时表、多行数据、自定义数据、插入数据

    SELECT FROM VALUES John 25 Jane 30 Mike 35 AS table name name age 方法2 select 1 2 union all select 3 4
  • 【计算机开题报告】 医药信息管理系统

    一 选题依据 简述国内外研究现状 生产需求状况 说明选题目的 意义 列出主要参考文献 1 研究背景 随着医药事业的不断壮大 相关单位对于医药信息的管理变得越来越重要 传统的手工管理效率低 易出错 费时费力 不能及时精确的收集 传递 存储 加
  • Nexus5596交换机支持3层需要的子卡

    3层子卡 nexus5596如果没有这块子卡 无法支持3层特性 TEST Cisco N5596 1 show modu Mod Ports Module Type Model Status 1 48 O2 32X10GBase T 16X
  • InfluxDB学习笔记

    本博客是我在学习InfluxDB的时候 记录的笔记 大家可以看看参考学些 简介 简述 InfluxDB是一个由InfluxData开发的开源时序型数据 它由Go写成 着力于高性能查询与存储时序型数据 InfluxDB被广泛应用于存储系统的监
  • 天猫数据分析工具推荐(天猫第三方数据平台)

    在电商迅速发展的大背景下 做好天猫数据分析能够在多方面帮助品牌商家更好地运营店铺 塑造品牌 如通过数据分析了解消费者的需求 购买偏好 这有利于品牌商家及时调整商品结构 产品推广 商品宣传等等 灵活制定品牌的销售策略 那么 天猫平台行业 品牌
  • 搜索二叉树(BSTree)

    一 搜索二叉树的概念 二叉搜索树又称为做二叉排序树 二叉查找树 其要么是一棵空树 要么是一个满足以下性质的二叉树 若它的左子树不空 则左子树上所有结点的关键字均小于根结点关键字 若它的右子树不空 则右子树上所有结点的关键字均大于根结点关键字
  • 成为一个黑客,就按照这个路线来!

    前几天一个同学在聊天中提到毕业后想要从事网络安全方向的工作 虽然他本身也是学计算机的 但是又怕心有余而力不足 因为 从事网络安全方面的工作向来起点都比较高 大学里少有开设这类课程的 在学校能够学到的知识比较有限 网上的关于这方面课程的质量又
  • AntDB内存管理之内存上下文之内存上下文机制是怎么实现的

    4 内存上下文机制是怎么实现的 下文将针对内存上下文机制进行代码说明 本次以AntDB的代码为例 来解析内存上下文的实现方式 4 1 最基础的数据结构 MemoryContextData和MemoryContextMethods是内存上下文
  • 【计算机毕业设计】网上拍卖系统

    现代经济快节奏发展以及不断完善升级的信息化技术 让传统数据信息的管理升级为软件存储 归纳 集中处理数据信息的管理方式 本网上拍卖系统就是在这样的大环境下诞生 其可以帮助使用者在短时间内处理完毕庞大的数据信息 使用这种软件工具可以帮助管理人员
  • APP端网络测试与弱网模拟

    当前APP网络环境比较复杂 网络制式有2G 3G 4G网络 还有越来越多的公共Wi Fi 不同的网络环境和网络制式的差异 都会对用户使用app造成一定影响 另外 当前app使用场景多变 如进地铁 上公交 进电梯等 使得弱网测试显得尤为重要
  • 206.翻转链表

    翻转链表 力扣 LeetCode 官网 全球极客挚爱的技术成长平台 备战技术面试 力扣提供海量技术面试资源 帮助你高效提升编程技能 轻松拿下世界 IT 名企 Dream Offer https leetcode cn problems re
  • 矩阵基本操作3

    题目描述 问题描述 定义一个N M N M lt 100 的矩阵 将一个该矩阵的行和列的元素互换 存到另一个二维数组中 输入格式 一行两个整数 N M 中间用空格隔开 表示矩阵有N行 M列 接下来共N行M列表示矩阵 输出格式 输出转置以后的
  • 【计算机毕业设计】电影播放平台

    电影播放平台采用B S架构 数据库是MySQL 网站的搭建与开发采用了先进的java进行编写 使用了springboot框架 该系统从两个对象 由管理员和用户来对系统进行设计构建 主要功能包括 个人信息修改 对用户 电影分类 电影信息等功能
  • 【计算机毕业设计】白优校园社团网站的设计与实现

    近些年 随着中国经济发展 人民的生活质量逐渐提高 对网络的依赖性越来越高 通过网络处理的事务越来越多 随着白优校园社团网站的常态化 如果依然采用传统的管理方式 将会为工作人员带来庞大的工作量 这将是一个巨大考验 需要投入大量人力开展对社团
  • 【计算机毕业设计】springbootstone音乐播放器的设计与实现

    随着我国经济的高速发展与人们生活水平的日益提高 人们对生活质量的追求也多种多样 尤其在人们生活节奏不断加快的当下 人们更趋向于足不出户解决生活上的问题 stone音乐播放器展现了其蓬勃生命力和广阔的前景 与此同时 为解决用户需求 stone
  • 单向不带头链表的使用

    单向不带头链表的使用 链表的创建 typedef struct LNode SLDataType data struct LNode next LNode LinkList 按位查找 LNode GetElem LinkList L int
  • 30天精通Nodejs--第二十天:express-操作mysql

    目录 前言 安装依赖并配置MySQL连接 安装mysql2库 配置连接信息 在Express应用中使用MySQL 结合Express路由实现CRUD操作 整合到主应用 结语 前言 在Node js中使用Expre
  • 「优选算法刷题」:快乐数

    一 题目 编写一个算法来判断一个数 n 是不是快乐数 快乐数 定义为 对于一个正整数 每一次将该数替换为它每个位置上的数字的平方和 然后重复这个过程直到这个数变为 1 也可能是 无限循环 但始终变不到 1 如果这个过程 结果为 1 那么这个
  • 温室气体排放更敏感的模型(即更高的平衡气候敏感性(ECS))在数年到数十年时间尺度上也具有更高的温度变化(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Python代码 数据
  • SAP ERP系统是什么?SAP好用吗?

    A公司是一家传统制造企业 公司曾先后使用过数个管理软件系统 但各部门使用的软件都是单独功能 导致企业日常管理中数据流与信息流相对独立 形成了 信息孤岛 随着公司近年业务规模的快速发展以及客户数量的迅速增加 企业原有的信息系统在销售预测及生产

随机推荐

  • 心音信号特征提取Matlab系统

    心音信号特征提取Matlab系统 心脏疾病是一种常见的疾病 如果能够通过自己开发的程序来对心音信号进行分析 检测就更加方便快捷了 本文章将介绍如何使用 Matlab 提取心音信号的频域特征值 包括频谱 能量谱 功率谱和倒频谱等 同时 将通过
  • 10个免费的web压力测试工具

    转自 http apps hi baidu com share detail 53794908 当一套程序写完或者一台服务器配置完成后 相必很多朋友会像我一样 非常想知道它到底能够承受多大的负载压力 那在本文中 就给大家介绍十个免费的可以用
  • Ubuntu安装*.deb程序,用gdebi

    Ubuntu 安装 deb程序的时候 用安装源 gdebi 命令 sudo gdebi deb 如果 Ubuntu 没有安装gdebi的 shell term 运行命令 sudo apt get install gdebi
  • PHP代码审计12—反序列化漏洞

    文章目录 一 PHP反序列化漏洞基础 1 序列化与反序列化 2 反序列化漏洞类型 3 常见的一些魔法函数 4 漏洞利用与防御 二 MRCTF2020 Ezpop 分析与利用 三 Phar反序列化例题分析 四 PHPmyadmin 2 x 反
  • 软件测试面试必问的几个问题,拿好标准答案,有备无患~

    在今年这个特殊的情况下 竞争压力增大 各大企业对于求职者的要求也随之增高 很多小伙伴都面临着这样的情况 千辛万苦拿到了面试机会 却因种种原因翻车 在面试的时候不能将自己的真实实力表现出来 在回答面试官问题时 抓不到重点 紧张 说话结巴 不知
  • leetcode312 戳气球

    题目 https leetcode cn com problems burst balloons 思路 动态规划 状态 dp i j 表示戳破 i j 范围内这些气球所能获得的最大数量的硬币 转移方程 dp i j max dp i j d
  • 给自己的软件添加数字签名&数字签名格式转换

    工具链接 解压密码为 解压密码 ziyuanxiaozhan outlook com 废话不说 先上图 添加数字签名前 添加正规数字签名后 数字签名相关文件的后缀 pfx一定包含或可以转换为所有文件 pem可以包含或可以转换为所有文件但不一
  • orcad caputre里面Off-Page connect和port的区别

    1 下图即为orcad caputre里面Off Page connect和port的符号 1 在同一张page里面想要实现信号的连接可以之间将两个端口连接起来 如下图 也可以将两个端口的网络符号改为一致 软件也认为是连在一起的 2 在不同
  • 单片机(ISIS 7 Professional):简易数码管显示0~99计数代码项目

    上一篇文章主要介绍用C语言制作一个按钮的简易0 9控制计数器 单片机 ISIS 7 Professional 简易数码管显示0 9计数代码项目https blog csdn net MOKI36 article details 122810
  • 2023年计算机毕业设计选题大全 计算机毕业设计选题推荐Java、Python、Android、小程序等

    2023年计算机毕业设计选题大全 计算机毕业设计选题推荐Java Python Android 小程序等 在已经迎来2023年的毕业季 很多同学咨询关于计算机毕业设计选题方面的问题 例如计算机毕设选题什么好 计算机毕设选题选什么新颖一些 计
  • AAudio进行音频采集的实现

    使用AAudio进行音频采集 介绍 AAudio 是在Android 8 0版本中引入的一种基于C语言的本地音频API Android 8 1版本具有增强功能 可在支持MMAP的HAL和驱动程序结合使用时缩短延迟时间 AAUdio提供 Op
  • redis连接数合理配置_redis如何进行合理配置,这10种配置参数你必须知道

    redis参数如何配置 redis数据库的使用 关键一步是对redis进行合理的参数配置 redis的配置文件都在安装目录下的redis conf文件中进行相关参数配置 redis参数的配置可以通过config get命令来获取redis参
  • Java实现最长公共子序列

    动态规划做最长公共子序列 最重要的是求出状态转移方程 理论的就不多说了 用语言太难描述了 直接去看视频吧 我们直接上代码 对这里来说 他的状态转移方程如下 if a i 1 b j 1 c i j c i 1 j 1 1 d i j 1 e
  • 服务器里的文件启动失败404,云表服务器启动失败问题汇总

    这是在安装本地版时经常发生的问题 10个人 就有7个人都会出现这样的问题 出现这样的问题 怎么解决呢 首先 想要连接服务器 必须要开启数据库的服务 其次 服务器其实是 锁 住的 那么你要连接服务器 肯定得有钥匙 这里的钥匙可以看成是授权文件
  • Qt之布局管理——停靠窗口

    QDockWidget类继承与QWidget类 用于停靠窗口的管理 在主窗口中 先设置中心控件 然后实例化QDockWidget对象 通过setFeatures 设置停靠窗口的窗体特性 通过 setAllowedAreas 设置窗体可停靠的
  • 1200*C. Stripe

    题意翻译 给定一整数n 下面有n个数a i 求将该数列分割成两个非空数列且两个数列内数字的和相等的方案数 1 lt n lt 10 5 a i 的绝对值不大于10000 解析 前缀和 include
  • QT 实现16进制与字符串互转

    QT 实现16进制与字符串互转 文章目录 QT 实现16进制与字符串互转 前言 一 字符串QString转换16进制 二 16进制转换为字符串QString 三 正则表达式限制输入16进制 四 文本自动补全空格功能的实现 前言 QT在界面时
  • matlab图像处理——直方图及直方图均衡化

    imhist 对rice png和增强亮度后的 增强对比度后的图进行直方图展示 imhist 对于brightness 和 contrast的不同 clear all brightness I imread rice png J imadd
  • 洛谷Java入门代码之分苹果

    题目描述 八尾勇喜欢吃苹果 她现在有 m m 100 m m le 100 m m 100 个苹果 吃完一个苹果需要花费 t t 100 t t le100 t t 100 分钟 吃完一个后立刻开始吃下一个 现在时间过去了 s s 1000
  • LevelDB简介

    LevelDB简介 综述 leveldb整体架构 提供接口 db h 技术 memtable WAL sstable Manifest cache LRU cache LRU的优缺点 filter levelDB初始化 compaction