leveldb的缓存机制

leveldb采用LRU机制, 利用键的哈希值前n位作为索引, 将要插入的键值对分派到指定的缓存区, 当缓存区的使用率大于总容量后, 优先淘汰最近最少使用的缓存, 独立的缓存区总量为2^n .

初始化ShardedLRUCache

  • 设置初始缓存容量, 并设置16个子分区的容量.

      static const int kNumShardBits = 4;
    static const int kNumShards = 1 << kNumShardBits;
    explicit ShardedLRUCache(size_t capacity)
    : last_id_(0) {
    const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;
    for (int s = 0; s < kNumShards; s++) {
    shard_[s].SetCapacity(per_shard);
    }
    }

新建缓存

  • 由key的hash值的前kNumShardBits位作为子缓存区索引, 默认为前4位的索引位, 索引到指定的区, 子缓存区LRUCache接管新建缓存的任务.

      class ShardedLRUCache : public Cache {
    ...
    virtual Handle* Insert(const Slice& key, void* value, size_t charge,
    void (*deleter)(const Slice& key, void* value)) {
    const uint32_t hash = HashSlice(key);
    return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);
    }
  • LRUCache结构

      // A single shard of sharded cache.
    class LRUCache {
    public:
    LRUCache();
    ~LRUCache(); // Separate from constructor so caller can easily make an array of LRUCache
    void SetCapacity(size_t capacity) { capacity_ = capacity; } // Like Cache methods, but with an extra "hash" parameter.
    Cache::Handle* Insert(const Slice& key, uint32_t hash,
    void* value, size_t charge,
    void (*deleter)(const Slice& key, void* value));
    Cache::Handle* Lookup(const Slice& key, uint32_t hash);
    void Release(Cache::Handle* handle);
    void Erase(const Slice& key, uint32_t hash); private:
    void LRU_Remove(LRUHandle* e);
    void LRU_Append(LRUHandle* e);
    void Unref(LRUHandle* e); // Initialized before use.
    size_t capacity_; // mutex_ protects the following state.
    port::Mutex mutex_;
    size_t usage_; // Dummy head of LRU list.
    // lru.prev is newest entry, lru.next is oldest entry.
    LRUHandle lru_; HandleTable table_;
    };

    LRUCache才是真正具有缓存功能的结构, capacity_表示它的最大容量, mutex_规范各线程互斥地访问, usage_标志缓存中已用容量, lru_作为哑节点, 它的前节点是最新的缓存对象, 它的后节点是最老的缓存对象, table_是用来统计对象是否被缓存的哈希表.

  • LRUCache缓存生成

    1. 缓存的基础节点是LRUHandle, 储存节点的(键, 值, 哈希值, next, prev节点, 销毁处理函数等)信息. 综合上面的LRUCache结构也看到, 实际上, 缓存节点是双向列表存储, LRUHandle lru_这个哑节点用来分隔最常更新的节点和最不常更新节点.

    2. 当要将缓存节点插入缓存区, 先由哈希表判断缓存是否已存在, 若存在, 将其更新至最常更新节点; 若不存在, 则插入为最常更新节点. 同时更新哈希表HandleTable table_.

    3. 这里的HandleTable实现并没特殊之处, 我看是采用键哈希策略进行哈希, 如果键冲突则以链表进行存储:

    4. 利用二级指针对链表进行插入.

       LRUHandle* Insert(LRUHandle* h) {
      LRUHandle** ptr = FindPointer(h->key(), h->hash);
      LRUHandle* old = *ptr;
      h->next_hash = (old == NULL ? NULL : old->next_hash);
      *ptr = h;
      if (old == NULL) {
      ++elems_;
      if (elems_ > length_) {
      // Since each cache entry is fairly large, we aim for a small
      // average linked list length (<= 1).
      Resize();
      }
      }
      return old;
      }
  • 二级指针

    在HandleTable这个哈希表实现里, 有个FindPointer方法用来查找此对象是否已存在, 并返回LRUHandle**, 代码如下:

      // Return a pointer to slot that points to a cache entry that
    // matches key/hash. If there is no such cache entry, return a
    // pointer to the trailing slot in the corresponding linked list.
    LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
    LRUHandle** ptr = &list_[hash & (length_ - 1)];
    while (*ptr != NULL &&
    ((*ptr)->hash != hash || key != (*ptr)->key())) {
    ptr = &(*ptr)->next_hash;
    }
    return ptr;
    }

    可见, 如果已存在节点, 则返回这个节点的LRUHandle**; 如果不存在, 返回的是可以保存这个LRUHandle*的地址.

  • LRUCache缓存查找

    如果缓存存在, 则将其放置到哑节点lru_的prev位置, 即最近使用节点, 相当于提升它的优先级, 便于下次快速查找; 如果不存在这个缓存, 返回NULL.

小结

看完leveldb的缓存实现, 在实现思路上, 是传统的lru算法, 使用哈希表判重, 根据缓存的请求时间提升缓存的优先级. 里面的细节例如使用哈希值的前n位进行路由, 路由到2^n 个独立的缓存区, 各个缓存区维护自己的mutex进行并发控制; 哈希表在插入节点时判断空间使用率, 并进行自动扩容, 保证查找效率在O(1).

levelDB缓存实现的更多相关文章

  1. MyCat源码分析系列之——BufferPool与缓存机制

    更多MyCat源码分析,请戳MyCat源码分析系列 BufferPool MyCat的缓冲区采用的是java.nio.ByteBuffer,由BufferPool类统一管理,相关的设置在SystemC ...

  2. leveldb 性能、使用场景评估

    最近有个业务写远远大于读,读也集中在最近写入,这不很适合采用leveldb存储么,leveldb业界貌似ssdb用得挺广,花了两天时间就ssdb简单做下测试,以下总结. ssdb 是leveldb的r ...

  3. 大型web系统数据缓存设计

    1. 前言 在高访问量的web系统中,缓存几乎是离不开的:但是一个适当.高效的缓存方案设计却并不容易:所以接下来将讨论一下应用系统缓存的设计方面应该注意哪些东西,包括缓存的选型.常见缓存系统的特点和数 ...

  4. LevelDB库简介

    LevelDB库简介 一.LevelDB入门 LevelDB是Google开源的持久化KV单机数据库,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般,也就是说,LevelDB很适合应用在查询 ...

  5. HBase、Redis、MongoDB、Couchbase、LevelDB主流 NoSQL 数据库的对比

    最近小组准备启动一个 node 开源项目,从前端亲和力.大数据下的IO性能.可扩展性几点入手挑选了 NoSql 数据库,但具体使用哪一款产品还需要做一次选型. 我们最终把选项范围缩窄在 HBase.R ...

  6. 161104、NoSQL数据库:key/value型之levelDB介绍及java实现

    简介:Leveldb是一个google实现的非常高效的kv数据库,能够支持billion级别的数据量了. 在这个数量级别下还有着非常高的性能,主要归功于它的良好的设计.特别是LSM算法.LevelDB ...

  7. [转载] leveldb日知录

    原文: http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html 对leveldb非常好的一篇学习总结文章 郑重声明:本篇博客是自己学 ...

  8. 关于时间序列数据库的思考——(1)运用hash文件(例如:RRD,Whisper) (2)运用LSM树来备份(例如:LevelDB,RocksDB,Cassandra) (3)运用B-树排序和k/v存储(例如:BoltDB,LMDB)

    转自:http://0351slc.com/portal.php?mod=view&aid=12 近期网络上呈现了有关catena.benchmarking boltdb等时刻序列存储办法的介 ...

  9. Leveldb 实现原理

    原文地址:http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html LevelDb日知录之一:LevelDb 101 说起LevelD ...

随机推荐

  1. The c programming language第一章节所有程序的实现

    //打印第一个程序hello, word #include<stdio.h> int main() { printf("hello, world\n"); ; } // ...

  2. Windows phone 8.1 MessageBox 变了哦!

    using Windows.UI.Popups; public async void MessageBoxShow(string content, string caption) { MessageD ...

  3. IIS7内建账号,应用程序池

    在IIS7以前的IIS版本中有一个本地帐号,是在安装时创建的,叫做 IUSR_MachineName.一旦启用匿名身份认证,这个IUSR_MachineName帐号就是IIS默认使用的身份(ident ...

  4. 实现将VirtualBox 虚拟机转换为KVM虚拟机的步骤

    原来在桌面上一直使用virtualbox虚拟机管理程序(VMM)构建虚拟机安装不同的操作系统,现在 研究linux下的KVM,能否将已经建立的virtualBox虚拟客户机(guest)转换为KVM虚 ...

  5. 一步一步学习SignalR进行实时通信_3_通过CORS解决跨域

    原文:一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 一步一步学习SignalR进行实时通信\_3_通过CORS解决跨域 SignalR 一步一步学习SignalR进行实时通信_3_ ...

  6. HDU1506 ( Largest Rectangle in a Histogram ) [dp]

    近期情绪太不稳定了.可能是由于在找实习这个过程碰壁了吧.第一次面试就跪了,可能是我面的是一个新公司,制度不完好,我感觉整个面试过程全然不沾编程,我面试的还是软件开发-后来我同学面试的时候.说是有一道数 ...

  7. android http同步请求

    1.界面 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:too ...

  8. not enough actual parameters for macro 'min'(QT与vs2010)

    解决方案见以下: qdatetime.h:“min”宏的实参不足 | 浏览:73 | 更新:2015-01-06 12:36 百度经验:jingyan.baidu.com 最近用VS2012 中Qt5 ...

  9. BestCoder Round #38

    1001 Four Inages Strategy 题意:给定空间的四个点,判断这四个点是否能形成正方形 思路:判断空间上4个点是否形成一个正方形方法有很多,这里给出一种方法,在p2,p3,p4中枚举 ...

  10. 从PHP程序员到RAW开发~

    RAW是一款PHP网站开发系统,即使不懂PHP,也可以使用RAW进行PHP程序开发,当然如果已经掌握了PHP,那么使用RAW开发将会是如虎添翼! 怎么理解“如虎添翼”:我们平时要做一个项目的话,我们要 ...