List详解

[toc]

在Redis3.2之后,它采用QuickList来实现List。

Redis7之前,QuickList底层是ZipList,7之后底层是listpack。

image-20240922140827310

PUSH操作底层都是由pushGenericCommand()函数来完成,只是参数不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// t_list.c
/* 实现了LPUSH/RPUSH/LPUSHX/RPUSHX. */
void pushGenericCommand(client *c, int where, int xx) { // 如果xx为true,那么仅在key存在时才Push
int j;

robj *lobj = lookupKeyWrite(c->db, c->argv[1]); // 查找列表对象
if (checkType(c,lobj,OBJ_LIST)) return; // 检查类型是否为List
if (!lobj) { // 处理不存在的列表
if (xx) { // 列表不存在且xx为true,返回
addReply(c, shared.czero);
return;
}

lobj = createListListpackObject(); // 列表不存在且xx为false,可以插入,创建一个list,初始只有一个listpack
dbAdd(c->db,c->argv[1],lobj); // 添加元素
}

listTypeTryConversionAppend(lobj,c->argv,2,c->argc-1,NULL,NULL); // 尝试转换为更高效的格式(如果需要的话)
for (j = 2; j < c->argc; j++) {
listTypePush(lobj,c->argv[j],where);
server.dirty++; // 脏数据计数器,用于跟踪数据修改
}

addReplyLongLong(c, listTypeLength(lobj)); // 更新状态和回复

char *event = (where == LIST_HEAD) ? "lpush" : "rpush"; // 发送通知
signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id);
}