LevelDb日知录之七:读取记录

本文详细介绍了LevelDb的读取流程,包括从内存到磁盘的查询路径选择原理,以及如何确保返回最新数据。此外还探讨了SSTable文件的高效查找策略,并对比了读写操作的性能。

        LevelDb是针对大规模Key/Value数据的单机存储库从应用的角度来看LevelDb就是一个存储工具而作为称职的存储工具常见的调用接口无非是新增KV删除KV读取KV更新Key对应的Value值这么几种操作LevelDb的接口没有直接支持更新操作的接口如果需要更新某个KeyValue,你可以选择直接生猛地插入新的KV保持Key相同这样系统内的key对应的value就会被更新或者你可以先删除旧的KV 之后再插入新的KV这样比较委婉地完成KV的更新操作

        假设应用提交一个Key下面我们看看LevelDb是如何从存储的数据中读出其对应的Value值的1LevelDb读取过程的整体示意图


        LevelDb首先会去查看内存中的Memtable如果Memtable中包含key及其对应的value则返回value值即可如果在Memtable没有读到key则接下来到同样处于内存中的Immutable Memtable中去读取类似地如果读到就返回若是没有读到,那么只能万般无奈下从磁盘中的大量SSTable文件中查找因为SSTable数量较多而且分成多个Level所以在SSTable中读数据是相当蜿蜒曲折的一段旅程总的读取原则是这样的首先从属于level 0的文件中查找如果找到则返回对应的value如果没有找到那么到level1中的文件中去找如此循环往复直到在某层SSTable文件中找到这个key对应的value为止或者查到最高level查找失败说明整个系统中不存在这个Key)

        那么为什么是从MemtableImmutableMemtable再从ImmutableMemtable到文件而文件中为何是从低level到高level这么一个查询路径呢道理何在之所以选择这么个查询路径是因为从信息的更新时间来说很明显Memtable存储的是最新鲜的KVImmutable Memtable中存储的KV数据对的新鲜程度次之而所有SSTable文件中的KV数据新鲜程度一定不如内存中的MemtableImmutableMemtable对于SSTable文件来说如果同时在level LLevelL+1找到同一个keylevelL的信息一定比level L+1的要新也就是说上面列出的查找路径就是按照数据新鲜程度排列出来的越新鲜的越先查找

        为啥要优先查找新鲜的数据呢这个道理不言而喻举个例子比如我们先往levelDb里面插入一条数据{key="www.samecity.com" value="我们"},过了几天samecity网站改名为69同城此时我们插入数据{key="www.samecity.com" value="69同城"}同样的key,不同的value逻辑上理解好像levelDb中只有一个存储记录即第二个记录但是在levelDb中很可能存在两条记录即上面的两个记录都在levelDb中存储了此时如果用户查询key="www.samecity.com",我们当然希望找到最新的更新记录也就是第二个记录返回这就是为何要优先查找新鲜数据的原因

        前文有讲对于SSTable文件来说如果同时在level LLevelL+1找到同一个keylevelL的信息一定比level L+1的要新这是一个结论理论上需要一个证明过程否则会招致如下的问题为神马呢从道理上讲呢很明白因为Level L+1的数据不是从石头缝里蹦出来的也不是做梦梦到的那它是从哪里来的Level L+1的数据是从LevelL 经过Compaction后得到的如果您不知道什么是Compaction那么........也许以后会知道的),也就是说您看到的现在的Level L+1层的SSTable数据是从原来的LevelL中来的现在的LevelL比原来的Level L数据要新鲜所以可证现在的Level L比现在的LevelL+1的数据要新鲜

        SSTable文件很多如何快速地找到key对应的valueLevelDblevel 0一直都爱搞特殊化level 0和其它level中查找某个key的过程是不一样的因为level 0下的不同文件可能key的范围有重叠某个要查询的key有可能多个文件都包含这样的话LevelDb的策略是先找出level0中哪些文件包含这个keymanifest文件中记载了level和对应的文件及文件里key的范围信息LevelDb在内存中保留这种映射表), 之后按照文件的新鲜程度排序新的文件排在前面之后依次查找读出key对应的value而如果是非level 0的话因为这个level的文件之间key是不重叠的所以只从一个文件就可以找到key对应的value

        最后一个问题,如果给定一个要查询的key和某个keyrange包含这个keySSTable文件那么levelDb是如何进行具体查找过程的呢levelDb一般会先在内存中的Cache中查找是否包含这个文件的缓存记录如果包含则从缓存中读取如果不包含则打开SSTable文件同时将这个文件的索引部分加载到内存中并放入Cache 这样Cache里面就有了这个SSTable的缓存项但是只有索引部分在内存中之后levelDb根据索引可以定位到哪个内容Block会包含这条key从文件中读出这个Block的内容在根据记录一一比较如果找到则返回结果如果没有找到那么说明这个levelSSTable文件并不包含这个key所以到下一级别的SSTable中去查找

        从之前介绍的LevelDb的写操作和这里介绍的读操作可以看出相对写操作读操作处理起来要复杂很多所以写的速度必然要远远高于读数据的速度也就是说LevelDb比较适合写操作多于读操作的应用场合而如果应用是很多读操作类型的那么顺序读取效率会比较高因为这样大部分内容都会在缓存中找到尽可能避免大量的随机读取操作

备注:本文转载自朗格科技:http://www.samecity.com/blog/Article.asp?ItemID=122

 

多源动态最优潮流的分布鲁棒优化方法(IEEE118节点)(Matlab代码实现)内容概要:本文介绍了基于Matlab代码实现的多源动态最优潮流的分布鲁棒优化方法,适用于IEEE118节点电力系统。该方法结合两阶段鲁棒模型与确定性模型,旨在应对电力系统中多源输入(如可再生能源)的不确定性,提升系统运行的安全性与经济性。文中详细阐述了分布鲁棒优化的建模思路,包括不确定性集合的构建、目标函数的设计以及约束条件的处理,并通过Matlab编程实现算法求解,提供了完整的仿真流程与结果分析。此外,文档还列举了大量相关电力系统优化研究案例,涵盖微电网调度、电动汽车集群并网、需求响应、储能配置等多个方向,展示了其在实际工程中的广泛应用价值。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事能源系统优化工作的工程师。; 使用场景及目标:①用于研究高比例可再生能源接入背景下电力系统的动态最优潮流问题;②支撑科研工作中对分布鲁棒优化模型的复现与改进;③为电力系统调度、规划及运行决策提供理论支持与仿真工具。; 阅读建议:建议读者结合提供的Matlab代码与IEEE118节点系统参数进行实操演练,深入理解分布鲁棒优化的建模逻辑与求解过程,同时可参考文中提及的其他优化案例拓展研究思路。
### 问题分析 在 `FuseDaemon` 中,日志提示的错误信息为: ``` LOG(ERROR) << "Leveldb setup is missing for: " << instance_name; ``` 该错误表示在 `fuse->level_db_connection_map` 中未找到与实例名 `'fbc9-1703'` 相关的 LevelDB 连接记录。这通常意味着在程序运行过程中,该实例的 LevelDB 未被正确初始化或加载。 ### 原因分析 1. **实例未初始化**:可能在程序启动时,未为 `'fbc9-1703'` 实例调用 LevelDB 的初始化逻辑。 2. **路径配置错误**:LevelDB 的存储路径可能未正确配置,导致连接失败。 3. **连接未建立**:即使数据库存在,若未在 `level_db_connection_map` 中注册连接对象,也会导致该错误。 4. **资源释放后未重新加载**:如果之前建立了连接但被释放(如程序重启或连接中断),未重新加载数据库也会出现此问题。 ### 解决方案 #### 1. 确保 LevelDB 初始化逻辑执行 在程序启动时,应确保为 `'fbc9-1703'` 实例正确调用 LevelDB 初始化函数,例如: ```cpp leveldb::DB* db; leveldb::Options options; options.create_if_missing = true; leveldb::Status status = leveldb::DB::Open(options, "/path/to/db/fbc9-1703", &db); if (status.ok()) { fuse->level_db_connection_map["fbc9-1703"] = db; } else { LOG(ERROR) << "Failed to open LevelDB for instance: fbc9-1703"; } ``` #### 2. 检查数据库路径配置 确保配置文件或运行参数中指定的数据库路径正确,且文件系统中存在该路径。若路径错误,`leveldb::DB::Open` 将失败,除非设置 `create_if_missing = true`。 #### 3. 验证连接是否注册 在初始化完成后,应确保将 `db` 指针注册到 `level_db_connection_map` 中。若未注册,即使数据库存在,也无法通过 `CheckLevelDbConnection` 的检查。 #### 4. 异常处理与重试机制 在连接失败时,可以添加重试逻辑,例如: ```cpp int retry = 3; while (retry-- > 0) { leveldb::Status status = leveldb::DB::Open(options, "/path/to/db/fbc9-1703", &db); if (status.ok()) { fuse->level_db_connection_map["fbc9-1703"] = db; break; } else { std::this_thread::sleep_for(std::chrono::seconds(1)); } } ``` #### 5. 日志记录与诊断 在连接失败时,应输出详细的错误信息,便于诊断问题,例如: ```cpp if (!status.ok()) { LOG(ERROR) << "Failed to open LevelDB: " << status.ToString(); } ``` ### 相关知识补充 LevelDB 在删除数据时,并非真正删除,而是插入一个标记为 `kTypeDeletion` 的记录,最终通过 `compaction` 操作清理过期数据[^1]。因此,即使执行了删除操作,数据库文件仍可能增长,直到 `compaction` 完成。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值