每個壓縮列表節點可以保存一個字節數組或者一個整數值, 其中, 字節數組可以是以下三種長度的其中一種:
1. 長度小于等于?`63`?()字節的字節數組;
2. 長度小于等于?`16383`?() 字節的字節數組;
3. 長度小于等于?`4294967295`?()字節的字節數組;
而整數值則可以是以下六種長度的其中一種:
1. `4`?位長,介于?`0`?至?`12`?之間的無符號整數;
2. `1`?字節長的有符號整數;
3. `3`?字節長的有符號整數;
4. `int16_t`?類型整數;
5. `int32_t`?類型整數;
6. `int64_t`?類型整數。
每個壓縮列表節點都由?`previous_entry_length`?、?`encoding`?、?`content`?三個部分組成, 如圖 7-4 所示。

接下來的內容將分別介紹這三個組成部分。
## previous_entry_length
節點的?`previous_entry_length`?屬性以字節為單位, 記錄了壓縮列表中前一個節點的長度。
`previous_entry_length`?屬性的長度可以是?`1`?字節或者?`5`?字節:
* 如果前一節點的長度小于?`254`?字節, 那么?`previous_entry_length`?屬性的長度為?`1`?字節: 前一節點的長度就保存在這一個字節里面。
* 如果前一節點的長度大于等于?`254`?字節, 那么?`previous_entry_length`?屬性的長度為?`5`?字節: 其中屬性的第一字節會被設置為?`0xFE`(十進制值?`254`), 而之后的四個字節則用于保存前一節點的長度。
圖 7-5 展示了一個包含一字節長?`previous_entry_length`?屬性的壓縮列表節點, 屬性的值為?`0x05`?, 表示前一節點的長度為?`5`?字節。

圖 7-6 展示了一個包含五字節長?`previous_entry_length`?屬性的壓縮節點, 屬性的值為?`0xFE00002766`?, 其中值的最高位字節?`0xFE`?表示這是一個五字節長的?`previous_entry_length`?屬性, 而之后的四字節?`0x00002766`?(十進制值?`10086`?)才是前一節點的實際長度。

因為節點的?`previous_entry_length`?屬性記錄了前一個節點的長度, 所以程序可以通過指針運算, 根據當前節點的起始地址來計算出前一個節點的起始地址。
舉個例子, 如果我們有一個指向當前節點起始地址的指針?`c`?, 那么我們只要用指針?`c`?減去當前節點?`previous_entry_length`?屬性的值, 就可以得出一個指向前一個節點起始地址的指針?`p`?, 如圖 7-7 所示。

壓縮列表的從表尾向表頭遍歷操作就是使用這一原理實現的: 只要我們擁有了一個指向某個節點起始地址的指針, 那么通過這個指針以及這個節點的?`previous_entry_length`?屬性, 程序就可以一直向前一個節點回溯, 最終到達壓縮列表的表頭節點。
圖 7-8 展示了一個從表尾節點向表頭節點進行遍歷的完整過程:
* 首先,我們擁有指向壓縮列表表尾節點?`entry4`?起始地址的指針?`p1`?(指向表尾節點的指針可以通過指向壓縮列表起始地址的指針加上`zltail`?屬性的值得出);
* 通過用?`p1`?減去?`entry4`?節點?`previous_entry_length`?屬性的值, 我們得到一個指向?`entry4`?前一節點?`entry3`?起始地址的指針?`p2`?;
* 通過用?`p2`?減去?`entry3`?節點?`previous_entry_length`?屬性的值, 我們得到一個指向?`entry3`?前一節點?`entry2`?起始地址的指針?`p3`?;
* 通過用?`p3`?減去?`entry2`?節點?`previous_entry_length`?屬性的值, 我們得到一個指向?`entry2`?前一節點?`entry1`?起始地址的指針?`p4`?,?`entry1`為壓縮列表的表頭節點;
* 最終, 我們從表尾節點向表頭節點遍歷了整個列表。




## encoding
節點的?`encoding`?屬性記錄了節點的?`content`?屬性所保存數據的類型以及長度:
* 一字節、兩字節或者五字節長, 值的最高位為?`00`?、?`01`?或者?`10`?的是字節數組編碼: 這種編碼表示節點的?`content`?屬性保存著字節數組, 數組的長度由編碼除去最高兩位之后的其他位記錄;
* 一字節長, 值的最高位以?`11`?開頭的是整數編碼: 這種編碼表示節點的?`content`?屬性保存著整數值, 整數值的類型和長度由編碼除去最高兩位之后的其他位記錄;
表 7-2 記錄了所有可用的字節數組編碼, 而表 7-3 則記錄了所有可用的整數編碼。 表格中的下劃線?`_`?表示留空, 而?`b`?、?`x`?等變量則代表實際的二進制數據, 為了方便閱讀, 多個字節之間用空格隔開。
* * *
表 7-2 字節數組編碼
| 編碼 | 編碼長度 | `content`?屬性保存的值 |
| --- | --- | --- |
| `00bbbbbb` | `1`?字節 | 長度小于等于?`63`?字節的字節數組。 |
| `01bbbbbb?xxxxxxxx` | `2`?字節 | 長度小于等于?`16383`?字節的字節數組。 |
| `10______?aaaaaaaa?bbbbbbbb?cccccccc?dddddddd` | `5`?字節 | 長度小于等于?`4294967295`?的字節數組。 |
表 7-3 整數編碼
| 編碼 | 編碼長度 | `content`?屬性保存的值 |
| --- | --- | --- |
| `11000000` | `1`?字節 | `int16_t`?類型的整數。 |
| `11010000` | `1`?字節 | `int32_t`?類型的整數。 |
| `11100000` | `1`?字節 | `int64_t`?類型的整數。 |
| `11110000` | `1`?字節 | `24`?位有符號整數。 |
| `11111110` | `1`?字節 | `8`?位有符號整數。 |
| `1111xxxx` | `1`?字節 | 使用這一編碼的節點沒有相應的?`content`?屬性, 因為編碼本身的?`xxxx`?四個位已經保存了一個介于?`0`?和`12`?之間的值, 所以它無須?`content`?屬性。 |
* * *
## content
節點的?`content`?屬性負責保存節點的值, 節點值可以是一個字節數組或者整數, 值的類型和長度由節點的?`encoding`?屬性決定。
圖 7-9 展示了一個保存字節數組的節點示例:
* 編碼的最高兩位?`00`?表示節點保存的是一個字節數組;
* 編碼的后六位?`001011`?記錄了字節數組的長度?`11`?;
* `content`?屬性保存著節點的值?`"hello?world"`?。

圖 7-10 展示了一個保存整數值的節點示例:
* 編碼?`11000000`?表示節點保存的是一個?`int16_t`?類型的整數值;
* `content`?屬性保存著節點的值?`10086`?。

- 介紹
- 前言
- 致謝
- 簡介
- 第一部分:數據結構與對象
- 簡單動態字符串
- SDS 的定義
- SDS 與 C 字符串的區別
- SDS API
- 重點回顧
- 參考資料
- 鏈表
- 鏈表和鏈表節點的實現
- 鏈表和鏈表節點的 API
- 重點回顧
- 字典
- 字典的實現
- 哈希算法
- 解決鍵沖突
- rehash
- 漸進式 rehash
- 字典 API
- 重點回顧
- 跳躍表
- 跳躍表的實現
- 跳躍表 API
- 重點回顧
- 整數集合
- 整數集合的實現
- 升級
- 升級的好處
- 降級
- 整數集合 API
- 重點回顧
- 壓縮列表
- 壓縮列表的構成
- 壓縮列表節點的構成
- 連鎖更新
- 壓縮列表 API
- 重點回顧
- 對象
- 對象的類型與編碼
- 字符串對象
- 列表對象
- 哈希對象
- 集合對象
- 有序集合對象
- 類型檢查與命令多態
- 內存回收
- 對象共享
- 對象的空轉時長
- 重點回顧
- 第二部分:單機數據庫的實現
- 數據庫
- 數據庫鍵空間
- 重點回顧
- RDB 持久化
- RDB 文件結構
- 重點回顧
- AOF 持久化
- AOF 持久化的實現
- 重點回顧
- 事件
- 文件事件
- 重點回顧
- 參考資料
- 客戶端
- 客戶端屬性
- 重點回顧
- 服務器
- 命令請求的執行過程
- 重點回顧
- 第三部分:多機數據庫的實現
- 復制
- 舊版復制功能的實現
- 重點回顧
- Sentinel
- 啟動并初始化 Sentinel
- 重點回顧
- 參考資料
- 集群
- 節點
- 重點回顧
- 第四部分:獨立功能的實現
- 發布與訂閱
- 頻道的訂閱與退訂
- 重點回顧
- 參考資料
- 事務
- 事務的實現
- 重點回顧
- Lua 腳本
- 創建并修改 Lua 環境
- 重點回顧
- 排序
- SORT <key> 命令的實現
- 重點回顧
- 二進制位數組
- GETBIT 命令的實現
- 重點回顧
- 慢查詢日志
- 慢查詢記錄的保存
- 慢查詢日志的閱覽和刪除
- 添加新日志
- 重點回顧
- 監視器
- 成為監視器
- 向監視器發送命令信息
- 重點回顧
- 源碼、相關資源和勘誤