Redis初学者学习:字典(图)及其基本编码结构
redis
是用C编写的,但是C
语言没有字典数据结构,所以C
语言本身使用字典结构来定义结构typedef Redis数据库结构体
/* Redis database representation. There are multiple databases identified * by integers from 0 (the default database) up to the max configured * database. The database number is the 'id' field in the structure. */ typedef struct redisDb { dict *dict; /* The keyspace for this DB */ 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 */ unsigned long expires_cursor; /* Cursor of the active expire cycle. */ list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */ } redisDb;
redisDb 在结构体 redisDb
src\server.h 中存储了 redis 数据库的底层数据结构: 过期时间 等待数据的客户端密钥 (BLPOP) 接收 PUSH 的密钥被阻止❙‶监控 Pu❙tin ULTI/EXEC CAS 类似事务 使用数据库 ID , 0-15 统计平均ttl expires_cursor过期ter 内存按键列表 src\dict.h 字典数据结构字典数据结构存储 私有数据 哈希表、旧表和新表。新表仅在哈希表扩展时使用,即 3 个参数 具体数据 key1 key1 该键的具体值 key2 该键的具体值 功能它点此 keyCompare 指示器用于比较两个键的大小。容量 哈希表 等于大小 -1 可哈希元素数量 可哈希元素数量 可哈希元素数量 typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
dictDi res
typedef struct dict
ht[1]
typedef struct dictType
typedef struct dictType {
uint64_t (*hashFunction)(const void *key);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
int (*expandAllowed)(size_t moreMem, double usedRatio);
} dictType;
dictType定义了多个函数指针,方便后续方法实现和调用。 比如函数指针
keyCompare
,它是一个指向函数的指针。该函数有 3 个参数和 1 个返回值: 127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44
127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44
127.0.0.1:6379> set test 99999999991111111111222222222233333333334444 OK 127.0.0.1:6379> OBJECT encoding test "embstr" 127.0.0.1:6379> STRLEN test (integer) 44
可散列元素的数量
127.0.0.1:6379> set test 99999999991111111111222222222233333333334444 OK 127.0.0.1:6379> OBJECT encoding test "embstr" 127.0.0.1:6379> STRLEN test (integer) 44
可哈希的元素数量 Enstruct try是一个真实的键值对数据结构
- key
键值实际上是类型为的 value dikt试试 例如我们在上一篇文章中介绍过的 上面串联v,第一个里面的元素是 类型,占用4位,用来限制客户端API,例如string 类型、embstr、hash、zset 等 编码类型,占用 4 位,使用的数字为 0 - 10,代表不同的数据类型。 lru 占用 24 位,3 个字节,内存消除算法 引用计数,int 类型,占用 4 个字节 ‶‶ 64 位系统运行时当前数据指针,ptr 占用8 字节 设置位图键,表示在线用户号。 11 Via ❙ Via ❙‶‶‷‶‶‶ 可见第 1 号有 3 人在线。 12 AND 登录:9:11 和登录:9:12 计算总和。 11两天在线人数12人。好的验证 我们看一下11号和12号任意一天的在线人数。 根据上面的结果可以看到,11号和12号任意一天的在线人数都是3人。我们来验证一下ok 看看上面使用的key,看看redis里到底是什么数据类型。 可以看到上面都是“raw”类型,是类型为 的redis sds 我们看一个小再举个例子。设置redis中的字符串key 我们看到类型name是“embstr”,那么“embstr”底层是如何实现的呢? “embstr”可以携带多少字节的数据? 我们上面提到了redis中存储键值对的地方是在结构体dictEntry中。结构体dictEntry中的val指针指向redisObject结构体是这样的 Buffer line 有 64 个字节 和 redisObject 结构占用 ♷ 6 那么有48 字节 可以使用它所拥有的redis中可以使用sds数据结构吗?保存数据? 使用hisdshdr8类型。 hisdshdr8类型的前3个sds元素占用3个字节,那么剩余的buf数据可存储45个字节 6 -16个字节 如果你这么认为,那么你就是有点粗心,因为redis为了兼容C语言标准,在字符串末尾添加了一个‘\0’,这个以字节为单位占用的字节数是 44字节 回顾上一篇文章,我们看到 当数据占用0 - - 2^5-1之间的空间时,使用hisdshdr5数据类型♝2^^8 - 1 占用时改为使用hisdshdr8数据类型 我们在redis中设置测试值为 44字节内容 对于这个key,是embstr 然后设置test2 到,大于44字节,然后检查其内容是否为上面的♝❙ raw',然后检查其内容是否为上面的♝❙ raw'。结构 参考:sds
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
v vv
指针,它指向其他数据,主要是为了解决哈希冲突hash
,为如下图所示,key为1,在(k3,v3)上,其他点在(k2,v2)上,一般默认其他点在NULLvoid 其实这个元素指向一个Actual值,这个元素是一个指针,实际的数据结构是这样的
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
位图 小写字母
127.0.0.1:6379> SETBIT login:9:11 25 1
(integer) 0
127.0.0.1:6379> SETBIT login:9:11 26 1
(integer) 0
127.0.0.1:6379> SETBIT login:9:11 27 1
(integer) 0
127.0.0.1:6379> BITCOUNT login:9:11
(integer) 3
127.0.0.1:6379> strlen login:9:11
(integer) 4
127.0.0.1:6379> BITOP or login:or login:9:11 login:9:12
(integer) 4
127.0.0.1:6379> BITCOUNT login:or
(integer) 3
127.0.0.1:6379> type login:or
string
127.0.0.1:6379> OBJECT encoding login:or
"raw"
127.0.0.1:6379> OBJECT encoding login:9:12
"raw"
127.0.0.1:6379> OBJECT encoding login:and
"raw"
cache line
127.0.0.1:6379> set name xiaoming
OK
127.0.0.1:6379> OBJECT encoding name
"embstr"
“embstr”
实际可以占用的字节数店铺: 一点练习
127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。