• 数据库 redis底层实现


    redis是一个存储键值对的内存数据库,并且持久化到磁盘。

    1、简单动态字符串(Simple Dynamic String,简称SDS)

    1)利用len记录字符串长度,使得strlen时间复杂度从O(N)变为O(1)。

    // sds.h
    struct __attribute__ ((__packed__)) sdshdr64 {
        uint64_t len; // 字符串已用的长度
        uint64_t alloc; // 分配的总长度
        char buf[]; // 字符串内容
    };
    

    2)利用类似vector的分配策略,append时预分配一倍空间,减少内存分配次数。 

    // sds.c/sdsMakeRoomFor
    if (avail >= addlen) return s;
    newlen = (len+addlen);
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;
    sdssetalloc(s, newlen);
    

    2、双向链表(Doubly Linked List)

    1)利用len,使得计算链表长度的时间复杂度从O(N)变为O(1)。

    2)表头和表尾插入元素的时间复杂度都是O(1)。注:这是所有双向链表的特性。 

    // adlist.h
    typedef struct listNode {
        struct listNode *prev;
        struct listNode *next;
        void *value;
    } listNode;
    
    typedef struct list {
        listNode *head;
        listNode *tail;
        unsigned long len; // 链表长度
    } list;

    3、字典(Dictionary)

    1)每个字典对应两个哈希表,ht[1]用于重哈希。

    // 字典
    typedef struct dict {
        dictht ht[2]; // 两个哈希表
        long rehashidx; // 重哈希的进度,到哪个桶了
    } dict;

    2)解决冲突:哈希值一样的多个键值对,放在同一个链表,即对应同一个桶。 

    // 字典元素:键值对
    typedef struct dictEntry {
        void *key;
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
            double d;
        } v;
        struct dictEntry *next;
    } dictEntry;
    
    // 哈希表
    typedef struct dictht {
        dictEntry **table;
        unsigned long size; // 桶个数
        unsigned long sizemask; // 等于size - 1
        unsigned long used; // 键值对个数
    } dictht;
    

    3)重哈希(rehash)

    3.1)数据不是一次倒完,而是多次渐进。

    3.2)新键值对会添加到ht[1]。

  • 相关阅读:
    ideaj项目切换不同版本的jdk
    物理机(window)安装linux系统
    linux jar自启动
    swap扩容
    tomcat加载外部项目
    springboot2.3.2控制台输出@RequestMapping路径
    linux磁盘扩容
    springboot-easycode配置文件修改
    List
    Map HashMap跟HashTable
  • 原文地址:https://www.cnblogs.com/yangwenhuan/p/12177027.html
Copyright © 2020-2023  润新知