### 3.1.3 數據庫鍵空間(key space)
`server.h/redisDb`結構中的dict稱為數據庫鍵空間,保存了數據庫的所有鍵值對,鍵為字符串對象,值為任意對象
```c
typedef struct redisDb {
dict *dict; // 數據庫鍵空間,保存所有鍵值對,鍵為字符串對象,值為任意對象
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
```
鍵空間的增刪改查都同dict操作,此外還有:
- 清空鍵空間:`FlushDb`
- 從鍵空間隨機返回一個鍵:`RandomKey`
- 返回數據庫鍵數量:`DbSize`
- 還有`Exists`、`Rename`、`Keys`等
----
讀寫鍵空間時的維護操作如下:
- 讀取一個鍵后(讀寫操作都會對鍵進行讀取),服務器會根據鍵是否存在,更新`hit`(命中)和`miss`(未命中),這兩個值可以通過`info status`命令查看
- 在讀取一個鍵后,服務器會更新鍵的`lru`(最后一次更新時間)屬性,可以通過`object idleime <key>`命令查看某個鍵的閑置時間
- 讀取一個鍵時,如果發現其已過期,會先刪除再進行其他操作
- 每次修改一個鍵后,會對`dirty`(臟計數器)加1,這個計數器會觸發服務器的持久化以及復制操作
- 如果開啟了服務器通知功能,在對鍵進行修改之后,服務器將按照配置發送相應的數據庫通知
----
設置鍵的生存時間和過期時間:
- 通過`Expire`和`PExpire`,客戶端能以秒或毫秒的精度為數據庫中的某個鍵設置`ttl`(Time To Live,生存時間),服務器會自動刪除生存時間為0的鍵
- 與此類似,可以通過`ExpireAt`和`PExpireAt`設置過期時間,過期時間是一個UNIX時間戳,當過期時間來臨時,服務器會自動刪除該鍵。
- `ttl`和`pttl`接收一個帶有生存時間或過期時間的鍵,返回這個鍵的剩余生存時間。
- `setex` 命令可以再設置一個字符串鍵的同時為鍵設置過期時間,這是一個類型限定的命令,其原理與`Expire`完全一樣。
其中,`EXPIRE`命令將轉成`PEXPIRE`命令,`PEXPIRE`和`EXPIREAT`都將轉成`PEXPIREAT`命令。
----
redisDb結構的expires字典保存了數據庫中所有鍵的過期時間,稱為`過期字典`
- 過期字典的鍵是一個指針,指向鍵空間的某個對象
- 過期字典的值是一個`long long`類型的整數,保存了過期時間(毫秒精度的UNIX時間戳)
----
`PPERSIST`命令可以移除一個鍵的過期時間,如`PERSIST <key>`,底層是將字典中的key移除。
----
過期時間的判定:
- 檢查給定鍵是否存在于過期字典,如果存在則取得其過期時間
- 檢查當前UNIX時間戳是否大于鍵的過期時間:如果是的話,那么鍵已過期,否則的話,鍵未過期。
----
過期鍵的刪除策略:
- 定時刪除:在設置鍵的過期時間的同時,創建一個定時器(Timer),讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作。
- 對內存最友好,對CPU最不友好
- 惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除鍵。
- 對CPU最友好,對內存最不友好
- 由`db.c/expireIfNeed`函數實現
- 定期刪除:每隔一段時間,程序就對數據庫進行一次檢查,刪除里面的過期鍵,具體由算法決定。
- 難點是確定刪除操作執行的時長和頻率
- 由`server.c/activeExpireCycle`函數實現
- 空白目錄
- 精簡版Spring的實現
- 0 前言
- 1 注冊和獲取bean
- 2 抽象工廠實例化bean
- 3 注入bean屬性
- 4 通過XML配置beanFactory
- 5 將bean注入到bean
- 6 加入應用程序上下文
- 7 JDK動態代理實現的方法攔截器
- 8 加入切入點和aspectj
- 9 自動創建AOP代理
- Redis原理
- 1 Redis簡介與構建
- 1.1 什么是Redis
- 1.2 構建Redis
- 1.3 源碼結構
- 2 Redis數據結構與對象
- 2.1 簡單動態字符串
- 2.1.1 sds的結構
- 2.1.2 sds與C字符串的區別
- 2.1.3 sds主要操作的API
- 2.2 雙向鏈表
- 2.2.1 adlist的結構
- 2.2.2 adlist和listNode的API
- 2.3 字典
- 2.3.1 字典的結構
- 2.3.2 哈希算法
- 2.3.3 解決鍵沖突
- 2.3.4 rehash
- 2.3.5 字典的API
- 2.4 跳躍表
- 2.4.1 跳躍表的結構
- 2.4.2 跳躍表的API
- 2.5 整數集合
- 2.5.1 整數集合的結構
- 2.5.2 整數集合的API
- 2.6 壓縮列表
- 2.6.1 壓縮列表的結構
- 2.6.2 壓縮列表結點的結構
- 2.6.3 連鎖更新
- 2.6.4 壓縮列表API
- 2.7 對象
- 2.7.1 類型
- 2.7.2 編碼和底層實現
- 2.7.3 字符串對象
- 2.7.4 列表對象
- 2.7.5 哈希對象
- 2.7.6 集合對象
- 2.7.7 有序集合對象
- 2.7.8 類型檢查與命令多態
- 2.7.9 內存回收
- 2.7.10 對象共享
- 2.7.11 對象空轉時長
- 3 單機數據庫的實現
- 3.1 數據庫
- 3.1.1 服務端中的數據庫
- 3.1.2 切換數據庫
- 3.1.3 數據庫鍵空間
- 3.1.4 過期鍵的處理
- 3.1.5 數據庫通知
- 3.2 RDB持久化
- 操作系統
- 2021-01-08 Linux I/O 操作
- 2021-03-01 Linux 進程控制
- 2021-03-01 Linux 進程通信
- 2021-06-11 Linux 性能優化
- 2021-06-18 性能指標
- 2022-05-05 Android 系統源碼閱讀筆記
- Java基礎
- 2020-07-18 Java 前端編譯與優化
- 2020-07-28 Java 虛擬機類加載機制
- 2020-09-11 Java 語法規則
- 2020-09-28 Java 虛擬機字節碼執行引擎
- 2020-11-09 class 文件結構
- 2020-12-08 Java 內存模型
- 2021-09-06 Java 并發包
- 代碼性能
- 2020-12-03 Java 字符串代碼性能
- 2021-01-02 ASM 運行時增強技術
- 理解Unsafe
- Java 8
- 1 行為參數化
- 1.1 行為參數化的實現原理
- 1.2 Java 8中的行為參數化
- 1.3 行為參數化 - 排序
- 1.4 行為參數化 - 線程
- 1.5 泛型實現的行為參數化
- 1.6 小結
- 2 Lambda表達式
- 2.1 Lambda表達式的組成
- 2.2 函數式接口
- 2.2.1 Predicate
- 2.2.2 Consumer
- 2.2.3 Function
- 2.2.4 函數式接口列表
- 2.3 方法引用
- 2.3.1 方法引用的類別
- 2.3.2 構造函數引用
- 2.4 復合方法
- 2.4.1 Comparator復合
- 2.4.2 Predicate復合
- 2.4.3 Function復合
- 3 流處理
- 3.1 流簡介
- 3.1.1 流的定義
- 3.1.2 流的特點
- 3.2 流操作
- 3.2.1 中間操作
- 3.2.2 終端操作
- 3.3.3 構建流
- 3.3 流API
- 3.3.1 flatMap的用法
- 3.3.2 reduce的用法
- 3.4 collect操作
- 3.4.1 collect示例
- 3.4.2 Collector接口