-
Notifications
You must be signed in to change notification settings - Fork 263
/
quicklist.c
2820 lines (2525 loc) · 118 KB
/
quicklist.c
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* quicklist.c - A doubly linked list of ziplists
* 一个ziplists的双向链表
* Copyright (c) 2014, Matt Stancliff <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must start the above copyright notice,
* this quicklist of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this quicklist of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h> /* for memcpy */
#include "quicklist.h"
#include "zmalloc.h"
#include "ziplist.h"
#include "util.h" /* for ll2string */
#include "lzf.h"
#if defined(REDIS_TEST) || defined(REDIS_TEST_VERBOSE)
#include <stdio.h> /* for printf (debug printing), snprintf (genstr) */
#endif
#ifndef REDIS_STATIC
#define REDIS_STATIC static
#endif
/* Optimization levels for size-based filling */
static const size_t optimization_level[] = {4096, 8192, 16384, 32768, 65536};
/* Maximum size in bytes of any multi-element ziplist.
* Larger values will live in their own isolated ziplists. */
#define SIZE_SAFETY_LIMIT 8192
/* Minimum ziplist size in bytes for attempting compression. */
#define MIN_COMPRESS_BYTES 48
/* Minimum size reduction in bytes to store compressed quicklistNode data.
* This also prevents us from storing compression if the compression
* resulted in a larger size than the original data. */
#define MIN_COMPRESS_IMPROVE 8
/* If not verbose testing, remove all debug printing. */
#ifndef REDIS_TEST_VERBOSE
#define D(...)
#else
#define D(...) \
do { \
printf("%s:%s:%d:\t", __FILE__, __FUNCTION__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (0);
#endif
/* Simple way to give quicklistEntry structs default values with one call. */
//初始化quicklistEntry结构
#define initEntry(e) \
do { \
(e)->zi = (e)->value = NULL; \
(e)->longval = -123456789; \
(e)->quicklist = NULL; \
(e)->node = NULL; \
(e)->offset = 123456789; \
(e)->sz = 0; \
} while (0)
#if __GNUC__ >= 3
#define likely(x) __builtin_expect(!!(x), 1) //x为真的可能性大
#define unlikely(x) __builtin_expect(!!(x), 0) //x为假的可能性大
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
/* __builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。
* __GNUC__ 是gcc编译器编译代码时预定义的一个宏。需要针对gcc编写代码时, 可以使用该宏进行条件编译。
* __GNUC__ 的值表示gcc的版本。需要针对gcc特定版本编写代码时,也可以使用该宏进行条件编译。
* __GNUC__ 的类型是“int”,该宏被扩展后, 得到的是整数字面值。可以通过仅预处理,查看宏扩展后的文本。
*/
/* Create a new quicklist.
* Free with quicklistRelease(). */
quicklist *quicklistCreate(void) { //创建一个新的quicklist,并初始化成员
struct quicklist *quicklist;
quicklist = zmalloc(sizeof(*quicklist)); //分配空间
//初始化各个成员
quicklist->head = quicklist->tail = NULL;
quicklist->len = 0;
quicklist->count = 0;
quicklist->compress = 0; //默认不压缩
quicklist->fill = -2; //设置默认值,每个ziplist的字节数最大为8kb
return quicklist;
}
#define COMPRESS_MAX (1 << 16) //最大压缩程度为2^16,因为compress长度为16位
void quicklistSetCompressDepth(quicklist *quicklist, int compress) { //设置压缩程度
if (compress > COMPRESS_MAX) {
compress = COMPRESS_MAX;
} else if (compress < 0) { //小于0也不压缩
compress = 0;
}
quicklist->compress = compress;
}
#define FILL_MAX (1 << 15) //每个ziplist最多有2^15个entry节点
void quicklistSetFill(quicklist *quicklist, int fill) { //设置ziplist结构的大小
if (fill > FILL_MAX) {
fill = FILL_MAX;
} else if (fill < -5) { //ziplist字节数最大可以为64kb
fill = -5;
}
quicklist->fill = fill;
}
//设置压缩列表表头的fill和compress成员
void quicklistSetOptions(quicklist *quicklist, int fill, int depth) {
quicklistSetFill(quicklist, fill);
quicklistSetCompressDepth(quicklist, depth);
}
/* Create a new quicklist with some default parameters. */
//创建一个quicklist,并且设置默认的参数
quicklist *quicklistNew(int fill, int compress) {
quicklist *quicklist = quicklistCreate();
quicklistSetOptions(quicklist, fill, compress);
return quicklist;
}
//创建一个quicklist节点quicklistNode,并初始化
REDIS_STATIC quicklistNode *quicklistCreateNode(void) {
quicklistNode *node;
node = zmalloc(sizeof(*node));
node->zl = NULL;
node->count = 0;
node->sz = 0;
node->next = node->prev = NULL;
node->encoding = QUICKLIST_NODE_ENCODING_RAW; //默认不压缩
node->container = QUICKLIST_NODE_CONTAINER_ZIPLIST; //默认使用ziplist结构存储数据
node->recompress = 0; //设置没压缩的标志
return node;
}
/* Return cached quicklist count */
//返回ziplist中entry节点的个数
unsigned int quicklistCount(quicklist *ql) { return ql->count; }
/* Free entire quicklist. */
//释放整个quicklist
void quicklistRelease(quicklist *quicklist) {
unsigned long len;
quicklistNode *current, *next;
current = quicklist->head;
len = quicklist->len; //记录quicklistNode节点个数
while (len--) {
next = current->next; //备份后继节点地址
zfree(current->zl); //释放当前节点的ziplist结构
quicklist->count -= current->count; //从quicklist的entry计数器减取当前节点中的entry个数
zfree(current); //释放当前quicklistNode节点
quicklist->len--; //更新quicklistNode节点计数器
current = next; //指向后继节点
}
zfree(quicklist); //释放整个quicklist
}
/* Compress the ziplist in 'node' and update encoding details.
* Returns 1 if ziplist compressed successfully.
* Returns 0 if compression failed or if ziplist too small to compress. */
//压缩node节点,返回0表示压缩失败,1表示成功
REDIS_STATIC int __quicklistCompressNode(quicklistNode *node) {
#ifdef REDIS_TEST
node->attempted_compress = 1; //测试标志
#endif
/* Don't bother compressing small values */
if (node->sz < MIN_COMPRESS_BYTES) //如果ziplist大小小于48字节,压缩失败,返回0
return 0;
quicklistLZF *lzf = zmalloc(sizeof(*lzf) + node->sz); //分配空间
/* Cancel if compression fails or doesn't compress small enough */
//调用laf压缩函数进行压缩并返回压缩后的大小
if (((lzf->sz = lzf_compress(node->zl, node->sz, lzf->compressed,
node->sz)) == 0) ||
lzf->sz + MIN_COMPRESS_IMPROVE >= node->sz) {
/* lzf_compress aborts/rejects compression if value not compressable. */
zfree(lzf); //太小不能压缩或压缩失败则释放空间,返回0
return 0;
}
//压缩成功并分配压缩成功大小的空间
lzf = zrealloc(lzf, sizeof(*lzf) + lzf->sz);
zfree(node->zl); //释放原来的空间
node->zl = (unsigned char *)lzf; //设置zl指向quicklistLZF结构
node->encoding = QUICKLIST_NODE_ENCODING_LZF; //设置encoding编码为lzf类型
node->recompress = 0; //不需要被再次压缩
return 1; //压缩成功返回1
}
/* Compress only uncompressed nodes. */
//只压缩之前没有压缩过的节点
#define quicklistCompressNode(_node) \
do { \
if ((_node) && (_node)->encoding == QUICKLIST_NODE_ENCODING_RAW) { \
__quicklistCompressNode((_node)); \
} \
} while (0)
/* Uncompress the ziplist in 'node' and update encoding details.
* Returns 1 on successful decode, 0 on failure to decode. */
//解压缩node节点的zl,成功返回1 ,失败返回0
REDIS_STATIC int __quicklistDecompressNode(quicklistNode *node) {
#ifdef REDIS_TEST
node->attempted_compress = 0;
#endif
void *decompressed = zmalloc(node->sz); //分配存储空间
quicklistLZF *lzf = (quicklistLZF *)node->zl;
//调用lzf_decompress进行解压缩
if (lzf_decompress(lzf->compressed, lzf->sz, decompressed, node->sz) == 0) {
/* Someone requested decompress, but we can't decompress. Not good. */
zfree(decompressed); //解压缩失败要释放之前分配的空间
return 0; //解压缩失败
}
zfree(lzf); //释放之前的压缩过的空间
node->zl = decompressed; //指向解压缩出来的空间
node->encoding = QUICKLIST_NODE_ENCODING_RAW; //设置为没压缩的标志,成功返回1
return 1;
}
/* Decompress only compressed nodes. */
//解压缩节点_node,_node必须是压缩过的节点
#define quicklistDecompressNode(_node) \
do { \
if ((_node) && (_node)->encoding == QUICKLIST_NODE_ENCODING_LZF) { \
__quicklistDecompressNode((_node)); \
} \
} while (0)
/* Force node to not be immediately re-compresable */
//标记被解压的_node节点已经被解压,等待被再次压缩
#define quicklistDecompressNodeForUse(_node) \
do { \
if ((_node) && (_node)->encoding == QUICKLIST_NODE_ENCODING_LZF) { \
__quicklistDecompressNode((_node)); \
(_node)->recompress = 1; \
} \
} while (0)
/* Extract the raw LZF data from this quicklistNode.
* Pointer to LZF data is assigned to '*data'.
* Return value is the length of compressed LZF data. */
//返回压缩过的ziplist结构的大小,并且将压缩过后的ziplist地址保存到*data中
size_t quicklistGetLzf(const quicklistNode *node, void **data) {
quicklistLZF *lzf = (quicklistLZF *)node->zl;
*data = lzf->compressed;
return lzf->sz;
}
//返回1表示可以压缩,返回0表示不可以压缩
#define quicklistAllowsCompression(_ql) ((_ql)->compress != 0)
/* Force 'quicklist' to meet compression guidelines set by compress depth.
* The only way to guarantee interior nodes get compressed is to iterate
* to our "interior" compress depth then compress the next node we find.
* If compress depth is larger than the entire list, we return immediately. */
//如果node不在压缩程度的范围内,就压缩
REDIS_STATIC void __quicklistCompress(const quicklist *quicklist,
quicklistNode *node) {
/* If length is less than our compress depth (from both sides),
* we can't compress anything. */
//如果quicklist不能压缩或者压缩程度太大直接返回
//quicklist->compress * 2 就是压缩节点的个数,不能比总结的的个数len还要多
if (!quicklistAllowsCompression(quicklist) ||
quicklist->len < (unsigned int)(quicklist->compress * 2))
return;
#if 0
/* Optimized cases for small depth counts */
if (quicklist->compress == 1) {
quicklistNode *h = quicklist->head, *t = quicklist->tail;
quicklistDecompressNode(h);
quicklistDecompressNode(t);
if (h != node && t != node)
quicklistCompressNode(node);
return;
} else if (quicklist->compress == 2) {
quicklistNode *h = quicklist->head, *hn = h->next, *hnn = hn->next;
quicklistNode *t = quicklist->tail, *tp = t->prev, *tpp = tp->prev;
quicklistDecompressNode(h);
quicklistDecompressNode(hn);
quicklistDecompressNode(t);
quicklistDecompressNode(tp);
if (h != node && hn != node && t != node && tp != node) {
quicklistCompressNode(node);
}
if (hnn != t) {
quicklistCompressNode(hnn);
}
if (tpp != h) {
quicklistCompressNode(tpp);
}
return;
}
#endif
/* Iterate until we reach compress depth for both sides of the list.a
* Note: because we do length checks at the *top* of this function,
* we can skip explicit null checks below. Everything exists. */
//压缩:压缩中间的节点,所以从两边开始忘中间找节点
//记录quicklistNode头部节点和尾部节点的地址
quicklistNode *forward = quicklist->head;
quicklistNode *reverse = quicklist->tail;
int depth = 0;
int in_depth = 0;
//从两边往中间找,找compress次
while (depth++ < quicklist->compress) {
//如果压缩过,则将其解压缩
quicklistDecompressNode(forward);
quicklistDecompressNode(reverse);
//如果找到node节点设置标记
if (forward == node || reverse == node)
in_depth = 1;
//如果两个指针相遇,返回
if (forward == reverse)
return;
//更新指针,指向下一个节点
forward = forward->next;
reverse = reverse->prev;
}
//如果node不在两边不需要压缩的范围内,则要压缩这个节点
if (!in_depth)
quicklistCompressNode(node);
if (depth > 2) { //压缩两个指针指向的节点
/* At this point, forward and reverse are one node beyond depth */
quicklistCompressNode(forward);
quicklistCompressNode(reverse);
}
}
//如果_node可以压缩,则要压缩
#define quicklistCompress(_ql, _node) \
do { \
/*如果_node节点需要被再次压缩,则压缩_node节点*/ \
if ((_node)->recompress) \
quicklistCompressNode((_node)); \
else \
__quicklistCompress((_ql), (_node)); \
/*否则,进行范围压缩*/ \
} while (0)
/* If we previously used quicklistDecompressNodeForUse(), just recompress. */
//如果之前调用quicklistDecompressNodeForUse(),只需将_node再次压缩
#define quicklistRecompressOnly(_ql, _node) \
do { \
if ((_node)->recompress) \
quicklistCompressNode((_node)); \
} while (0)
/* Insert 'new_node' after 'old_node' if 'after' is 1.
* Insert 'new_node' before 'old_node' if 'after' is 0.
* Note: 'new_node' is *always* uncompressed, so if we assign it to
* head or tail, we do not need to uncompress it. */
//插入节点,如果after为1,则new_node插在old_node后面,如果为0,则插在前面
//插入的new_node总是未压缩的,所以可以插在头部或尾部。
REDIS_STATIC void __quicklistInsertNode(quicklist *quicklist,
quicklistNode *old_node,
quicklistNode *new_node, int after) {
if (after) { //插入在后面
new_node->prev = old_node; //new_node的前驱指针指向old_node
if (old_node) { //如果old_node非空
new_node->next = old_node->next; //new_node插在old_new的后面
if (old_node->next)
old_node->next->prev = new_node; //old_node的后驱节点的前驱指针变成new_node
old_node->next = new_node; //old_node的后驱节点更新为new_node
}
if (quicklist->tail == old_node) //如果old_node节点是尾节点,需要更新尾节点指针的指向
quicklist->tail = new_node;
} else { //插入在前面
new_node->next = old_node; //将old_node插在new_node后面
if (old_node) {
new_node->prev = old_node->prev; //更新new_node的前驱指针为old_node的前驱指针
if (old_node->prev)
old_node->prev->next = new_node; //更新old_node的前驱节点的后继指针为new_node
old_node->prev = new_node; //将old_node的前驱指针指向new_node
}
if (quicklist->head == old_node) //如果old_node节点是头节点,需要更新头节点指针的指向
quicklist->head = new_node;
}
/* If this insert creates the only element so far, initialize head/tail. */
if (quicklist->len == 0) { //如果quicklist为空列表
quicklist->head = quicklist->tail = new_node;//更新头尾节点指针
}
if (old_node)
quicklistCompress(quicklist, old_node); //如果设置了compress,压缩old_node
quicklist->len++; //更新quicklistNode节点计数器
}
/* Wrappers for node inserting around existing node. */
//将前插法封装封装起来
REDIS_STATIC void _quicklistInsertNodeBefore(quicklist *quicklist,
quicklistNode *old_node,
quicklistNode *new_node) {
__quicklistInsertNode(quicklist, old_node, new_node, 0);
}
//将后插法封装封装起来
REDIS_STATIC void _quicklistInsertNodeAfter(quicklist *quicklist,
quicklistNode *old_node,
quicklistNode *new_node) {
__quicklistInsertNode(quicklist, old_node, new_node, 1);
}
//sz是否满足小于fill所要求的最大值
REDIS_STATIC int
_quicklistNodeSizeMeetsOptimizationRequirement(const size_t sz,
const int fill) {
if (fill >= 0)
return 0;
//fill小于0
size_t offset = (-fill) - 1; //数组的偏移量
//static const size_t optimization_level[] = {4096, 8192, 16384, 32768, 65536};
//(sizeof(optimization_level) / sizeof(*optimization_level) 求出数组的元素个数
//数组偏移量要小于数组元素
if (offset < (sizeof(optimization_level) / sizeof(*optimization_level))) {
if (sz <= optimization_level[offset]) { //sz小于根据fill算出的等级,返回1
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
//sz是否超过ziplist所规定的安全界限8192字节,1表示安全,0表示不安全
#define sizeMeetsSafetyLimit(sz) ((sz) <= SIZE_SAFETY_LIMIT)
//node节点中ziplist能否插入entry节点中,根据fill和sz判断
REDIS_STATIC int _quicklistNodeAllowInsert(const quicklistNode *node,
const int fill, const size_t sz) {
if (unlikely(!node)) //!node为假的可能性大,如果Node为空直接返回
return 0;
int ziplist_overhead;
/* size of previous offset */
//上一个entry节点的信息
if (sz < 254) //如果ziplist的大小小于254
ziplist_overhead = 1; //编码需要1个字节
else
ziplist_overhead = 5; //否则需要5个字节
/* size of forward offset */
//当前entry节点的信息
if (sz < 64) //长度小于2^6-1 用1个字节编码
ziplist_overhead += 1;
else if (likely(sz < 16384)) //长度小于2^14-1 用2个字节编码
ziplist_overhead += 2;
else
ziplist_overhead += 5; //长度小于2^32-1 用5个字节编码
/* new_sz overestimates if 'sz' encodes to an integer type */
unsigned int new_sz = node->sz + sz + ziplist_overhead;
if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(new_sz, fill))) //new_sz符合fill配置,成功
return 1;
else if (!sizeMeetsSafetyLimit(new_sz)) //new_sz不满足安全界限,返回0
return 0;
else if ((int)node->count < fill) //如果entry节点个数小于fill所设置的大小(正数情况),返回1
return 1;
else
return 0;
}
//根据fill判断两个quicklistNode中的ziplist能否合并,返回1可以,否则返回0
REDIS_STATIC int _quicklistNodeAllowMerge(const quicklistNode *a,
const quicklistNode *b,
const int fill) {
if (!a || !b) //a和b任意一个为空则返回0
return 0;
/* approximate merged ziplist size (- 11 to remove one ziplist
* header/trailer) */
//计算合并后的大小,减去以下成员
//albtyes + zltail_offset + zllength + zlend = 11
unsigned int merge_sz = a->sz + b->sz - 11;
if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(merge_sz, fill))) //merge_sz符合fill配置
return 1;
else if (!sizeMeetsSafetyLimit(merge_sz)) //merge_sz超过安全大小的界限
return 0;
else if ((int)(a->count + b->count) <= fill) //合并后的entry个数小于fill所限制的个数
return 1;
else
return 0;
}
//更新Node的ziplist大小sz,将zl的zlbytes成员赋值给sz
#define quicklistNodeUpdateSz(node) \
do { \
(node)->sz = ziplistBlobLen((node)->zl); \
} while (0) //ziplistBlobLen返回整个 ziplist 占用的内存字节数
/* Add new entry to head node of quicklist.
*
* Returns 0 if used existing head.
* Returns 1 if new head created. */
//push一个entry节点到quicklist的头部
//返回0表示不改变头节点指针,返回1表示节点插入在头部,改变了头结点指针
int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {
quicklistNode *orig_head = quicklist->head; //备份头结点地址
//如果ziplist可以插入entry节点
if (likely(
_quicklistNodeAllowInsert(quicklist->head, quicklist->fill, sz))) {
quicklist->head->zl =
ziplistPush(quicklist->head->zl, value, sz, ZIPLIST_HEAD); //将节点push到头部
quicklistNodeUpdateSz(quicklist->head); //更新quicklistNode记录ziplist大小的sz
} else { //如果不能插入entry节点到ziplist
quicklistNode *node = quicklistCreateNode(); //新创建一个quicklistNode节点
//将entry节点push到新创建的quicklistNode节点中
node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_HEAD);
quicklistNodeUpdateSz(node); //更新ziplist的大小sz
_quicklistInsertNodeBefore(quicklist, quicklist->head, node); //将新创建的节点插入到头节点前
}
quicklist->count++; //更新quicklistNode计数器
quicklist->head->count++; //更新entry计数器
return (orig_head != quicklist->head); //如果改变头节点指针则返回1,否则返回0
}
/* Add new entry to tail node of quicklist.
*
* Returns 0 if used existing tail.
* Returns 1 if new tail created. */
//push一个entry节点到quicklist的尾节点中,如果不能push则新创建一个quicklistNode节点
//返回0表示不改变尾节点指针,返回1表示节点插入在尾部,改变了尾结点指针
int quicklistPushTail(quicklist *quicklist, void *value, size_t sz) {
quicklistNode *orig_tail = quicklist->tail;
//如果ziplist可以插入entry节点
if (likely(
_quicklistNodeAllowInsert(quicklist->tail, quicklist->fill, sz))) {
quicklist->tail->zl =
ziplistPush(quicklist->tail->zl, value, sz, ZIPLIST_TAIL); //将节点push到尾部
quicklistNodeUpdateSz(quicklist->tail); //更新quicklistNode记录ziplist大小的sz
} else {
quicklistNode *node = quicklistCreateNode(); //新创建一个quicklistNode节点
//将entry节点push到新创建的quicklistNode节点中
node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_TAIL);
quicklistNodeUpdateSz(node); //更新ziplist的大小sz
_quicklistInsertNodeAfter(quicklist, quicklist->tail, node);//将新创建的节点插入到尾节点后
}
quicklist->count++; //更新quicklistNode计数器
quicklist->tail->count++; //更新entry计数器
return (orig_tail != quicklist->tail); //如果改变尾节点指针则返回1,否则返回0
}
/* Create new node consisting of a pre-formed ziplist.
* Used for loading RDBs where entire ziplists have been stored
* to be retrieved later. */
//追加quicklist一个quicklist节点
void quicklistAppendZiplist(quicklist *quicklist, unsigned char *zl) {
quicklistNode *node = quicklistCreateNode(); //创建一个新的quicklistNode节点
node->zl = zl; //设置zl指向ziplist
node->count = ziplistLen(node->zl); //设置entry节点计数器
node->sz = ziplistBlobLen(zl); //设置ziplist的大小
_quicklistInsertNodeAfter(quicklist, quicklist->tail, node); //将node节点追加到quicklist的尾部
quicklist->count += node->count; //更新quicklist的entry节点计数器
}
/* Append all values of ziplist 'zl' individually into 'quicklist'.
*
* This allows us to restore old RDB ziplists into new quicklists
* with smaller ziplist sizes than the saved RDB ziplist.
*
* Returns 'quicklist' argument. Frees passed-in ziplist 'zl' */
//在quicklist末尾追加一个entry
quicklist *quicklistAppendValuesFromZiplist(quicklist *quicklist,
unsigned char *zl) {
unsigned char *value;
unsigned int sz;
long long longval;
char longstr[32] = {0};
unsigned char *p = ziplistIndex(zl, 0); //获得ziplist第一个节点的地址
while (ziplistGet(p, &value, &sz, &longval)) { //将p指向的entry节点信息,保存到value或sz或longval中
if (!value) { //如果字符串为空
/* Write the longval as a string so we can re-add it */
sz = ll2string(longstr, sizeof(longstr), longval); //将longlong类型的整数转换为字符串
value = (unsigned char *)longstr; //保存到value中
}
quicklistPushTail(quicklist, value, sz); //追加到quicklist的尾部
p = ziplistNext(zl, p); //更新p指向下一个entry节点
}
zfree(zl); //释放空间
return quicklist;
}
/* Create new (potentially multi-node) quicklist from a single existing ziplist.
*
* Returns new quicklist. Frees passed-in ziplist 'zl'. */
//创建一个quicklist,并将zl追加到其中
quicklist *quicklistCreateFromZiplist(int fill, int compress,
unsigned char *zl) {
return quicklistAppendValuesFromZiplist(quicklistNew(fill, compress), zl);
}
//删除空quicklistNode节点
#define quicklistDeleteIfEmpty(ql, n) \
do { \
if ((n)->count == 0) { \
__quicklistDelNode((ql), (n)); \
(n) = NULL; \
} \
} while (0)
//删除quicklistNode节点node
REDIS_STATIC void __quicklistDelNode(quicklist *quicklist,
quicklistNode *node) {
if (node->next) //如果后继节点指针不为空,则将后继节点的前驱指针跳过当前节点
node->next->prev = node->prev;
if (node->prev) //如果前驱节点指针不为空,则将前驱节点的后继指针跳过当前节点
node->prev->next = node->next;
if (node == quicklist->tail) { //如果被删除的节点是尾节点,则要更新尾节点指针
quicklist->tail = node->prev;
}
if (node == quicklist->head) { //如果被删除的节点是头节点,则要更新头节点指针
quicklist->head = node->next;
}
/* If we deleted a node within our compress depth, we
* now have compressed nodes needing to be decompressed. */
__quicklistCompress(quicklist, NULL); //如果删除的节点在压缩的范围内,必须更新quicklist的压缩情况
quicklist->count -= node->count; //更新entry计数器
zfree(node->zl); //释放空间
zfree(node);
quicklist->len--; //更新quicklistNode计数器
}
/* Delete one entry from list given the node for the entry and a pointer
* to the entry in the node.
*
* Note: quicklistDelIndex() *requires* uncompressed nodes because you
* already had to get *p from an uncompressed node somewhere.
*
* Returns 1 if the entire node was deleted, 0 if node still exists.
* Also updates in/out param 'p' with the next offset in the ziplist. */
//删除ziplist中的entry,如果entry是最后一个,则删除当前quicklistNode节点,返回1,没有删除当前节点则返回0
REDIS_STATIC int quicklistDelIndex(quicklist *quicklist, quicklistNode *node,
unsigned char **p) {
int gone = 0;
node->zl = ziplistDelete(node->zl, p); //删除p指向的entry
node->count--; //更新计数器
if (node->count == 0) { //如果entry为0
gone = 1;
__quicklistDelNode(quicklist, node);//删除当前的quicklistNode节点
} else {
quicklistNodeUpdateSz(node); //否则更新node中ziplist大小sz
}
quicklist->count--; //更新quicklist表头中的quicklistNode节点计数器
/* If we deleted the node, the original node is no longer valid */
return gone ? 1 : 0;
}
/* Delete one element represented by 'entry'
*
* 'entry' stores enough metadata to delete the proper position in
* the correct ziplist in the correct quicklist node. */
//删除一个entry通过quicklistEntry结构的形式
void quicklistDelEntry(quicklistIter *iter, quicklistEntry *entry) {
//获得entry所属节点的前驱节点和后继节点的地址
quicklistNode *prev = entry->node->prev;
quicklistNode *next = entry->node->next;
//删除entry所属的节点
int deleted_node = quicklistDelIndex((quicklist *)entry->quicklist,
entry->node, &entry->zi);
/* after delete, the zi is now invalid for any future usage. */
iter->zi = NULL; //更新迭代器的zi
/* If current node is deleted, we must update iterator node and offset. */
//如果当前的quicklistNode节点被删除,需要更新迭代器的正在指向的节点的地址
if (deleted_node) {
if (iter->direction == AL_START_HEAD) { //如果是正向迭代则指向next,offset为0
iter->current = next;
iter->offset = 0;
} else if (iter->direction == AL_START_TAIL) { //如果是反向迭代则指向prev,offset为-1
iter->current = prev;
iter->offset = -1;
}
}
/* else if (!deleted_node), no changes needed.
* we already reset iter->zi above, and the existing iter->offset
* doesn't move again because:
* - [1, 2, 3] => delete offset 1 => [1, 3]: next element still offset 1
* - [1, 2, 3] => delete offset 0 => [2, 3]: next element still offset 0
* if we deleted the last element at offet N and now
* length of this ziplist is N-1, the next call into
* quicklistNext() will jump to the next node. */
}
/* Replace quicklist entry at offset 'index' by 'data' with length 'sz'.
*
* Returns 1 if replace happened.
* Returns 0 if replace failed and no changes happened. */
//下标为index的entry被data替换
int quicklistReplaceAtIndex(quicklist *quicklist, long index, void *data,
int sz) {
quicklistEntry entry;
if (likely(quicklistIndex(quicklist, index, &entry))) { //找到下标为index的entry
/* quicklistIndex provides an uncompressed node */
entry.node->zl = ziplistDelete(entry.node->zl, &entry.zi); //删除被替换的entry
entry.node->zl = ziplistInsert(entry.node->zl, entry.zi, data, sz); //在删除的地方插入一个entry
quicklistNodeUpdateSz(entry.node); //更新quicklistNode节点的信息
quicklistCompress(quicklist, entry.node); //按需压缩
return 1;
} else {
return 0;
}
}
/* Given two nodes, try to merge their ziplists.
*
* This helps us not have a quicklist with 3 element ziplists if
* our fill factor can handle much higher levels.
*
* Note: 'a' must be to the LEFT of 'b'.
*
* After calling this function, both 'a' and 'b' should be considered
* unusable. The return value from this function must be used
* instead of re-using any of the quicklistNode input arguments.
*
* Returns the input node picked to merge against or NULL if
* merging was not possible. */
//合并a和b的ziplist,返回空说明合并失败或没有发生改变
REDIS_STATIC quicklistNode *_quicklistZiplistMerge(quicklist *quicklist,
quicklistNode *a,
quicklistNode *b) {
D("Requested merge (a,b) (%u, %u)", a->count, b->count);
//将a和b先解压
quicklistDecompressNode(a);
quicklistDecompressNode(b);
//合并a和b的ziplist
if ((ziplistMerge(&a->zl, &b->zl))) {
/* We merged ziplists! Now remove the unused quicklistNode. */
quicklistNode *keep = NULL, *nokeep = NULL;
if (!a->zl) { //a的zl为空,说明a发生改变
nokeep = a;
keep = b;
} else if (!b->zl) { //b的zl为空,说明a发生改变
nokeep = b;
keep = a;
}
keep->count = ziplistLen(keep->zl); //合并之后的entry元素个数
quicklistNodeUpdateSz(keep); //更新keep的ziplist大小sz
nokeep->count = 0; //a被合并到b中,因此a中的节点数为0
__quicklistDelNode(quicklist, nokeep); //删除被合并的节点
quicklistCompress(quicklist, keep); //按需压缩
return keep;
} else {
/* else, the merge returned NULL and nothing changed. */
return NULL;
}
}
/* Attempt to merge ziplists within two nodes on either side of 'center'.
*
* We attempt to merge:
* - (center->prev->prev, center->prev)
* - (center->next, center->next->next)
* - (center->prev, center)
* - (center, center->next)
*/
//合并以center为中心的左右两个节点,最多将5个节点合并为1个
REDIS_STATIC void _quicklistMergeNodes(quicklist *quicklist,
quicklistNode *center) {
int fill = quicklist->fill; //备份配置的ziplist的大小
quicklistNode *prev, *prev_prev, *next, *next_next, *target;
prev = prev_prev = next = next_next = target = NULL;
//备份center节点的prev节点和prev的prev节点
if (center->prev) {
prev = center->prev;
if (center->prev->prev)
prev_prev = center->prev->prev;
}
//备份center节点的next节点和next的next节点
if (center->next) {
next = center->next;
if (center->next->next)
next_next = center->next->next;
}
/* Try to merge prev_prev and prev */
//如果允许合并,合并prev_prev and prev节点
if (_quicklistNodeAllowMerge(prev, prev_prev, fill)) {
_quicklistZiplistMerge(quicklist, prev_prev, prev);
prev_prev = prev = NULL; /* they could have moved, invalidate them. */
}
/* Try to merge next and next_next */
//如果允许合并,合并next and next_next节点
if (_quicklistNodeAllowMerge(next, next_next, fill)) {
_quicklistZiplistMerge(quicklist, next, next_next);
next = next_next = NULL; /* they could have moved, invalidate them. */
}
/* Try to merge center node and previous node */
//如果允许合并,合并center和prev节点
if (_quicklistNodeAllowMerge(center, center->prev, fill)) {
target = _quicklistZiplistMerge(quicklist, center->prev, center);
center = NULL; /* center could have been deleted, invalidate it. */
} else {
/* else, we didn't merge here, but target needs to be valid below. */
target = center; //防止野指针
}
/* Use result of center merge (or original) to merge with next node. */
//如果允许合并,合并target和next节点
if (_quicklistNodeAllowMerge(target, target->next, fill)) {
_quicklistZiplistMerge(quicklist, target, target->next);
}
}
/* Split 'node' into two parts, parameterized by 'offset' and 'after'.
*
* The 'after' argument controls which quicklistNode gets returned.
* If 'after'==1, returned node has elements after 'offset'.
* input node keeps elements up to 'offset', including 'offset'.
* If 'after'==0, returned node has elements up to 'offset', including 'offset'.
* input node keeps elements after 'offset'.
*
* If 'after'==1, returned node will have elements _after_ 'offset'.
* The returned node will have elements [OFFSET+1, END].
* The input node keeps elements [0, OFFSET].
*
* If 'after'==0, returned node will keep elements up to and including 'offset'.
* The returned node will have elements [0, OFFSET].
* The input node keeps elements [OFFSET+1, END].
*
* The input node keeps all elements not taken by the returned node.
*
* Returns newly created node or NULL if split not possible. */
//通过offset和after将node分割成两个部分,返回分离出的节点地址
REDIS_STATIC quicklistNode *_quicklistSplitNode(quicklistNode *node, int offset,
int after) {
size_t zl_sz = node->sz;
quicklistNode *new_node = quicklistCreateNode(); //创建一个新quicklistNode节点
new_node->zl = zmalloc(zl_sz); //为ziplist分配空间
/* Copy original ziplist so we can split it */
memcpy(new_node->zl, node->zl, zl_sz); //将ziplist拷贝1份到new_node中
/* -1 here means "continue deleting until the list ends" */
//-1 表示ziplist列表的最后一个entry节点的下标
//如果after为1,则表示:将node分割成new+orig的前后顺序
//如果after为0,则表示:将node分割成orig+new的前后顺序
//计算删除的范围
int orig_start = after ? offset + 1 : 0;
int orig_extent = after ? -1 : offset;
int new_start = after ? 0 : offset;
int new_extent = after ? offset + 1 : -1;
D("After %d (%d); ranges: [%d, %d], [%d, %d]", after, offset, orig_start,
orig_extent, new_start, new_extent);
node->zl = ziplistDeleteRange(node->zl, orig_start, orig_extent); //删除原来节点的orig部分
node->count = ziplistLen(node->zl); //更新entry节点计数器
quicklistNodeUpdateSz(node); //更新ziplist的大小sz
new_node->zl = ziplistDeleteRange(new_node->zl, new_start, new_extent); //删除新节点的new部分
new_node->count = ziplistLen(new_node->zl); //更新entry节点计数器
quicklistNodeUpdateSz(new_node); //更新ziplist的大小sz
D("After split lengths: orig (%d), new (%d)", node->count, new_node->count);
return new_node;
}
/* Insert a new entry before or after existing entry 'entry'.
*
* If after==1, the new value is inserted after 'entry', otherwise
* the new value is inserted before 'entry'. */
//如果after为1,在已存在的entry后插入一个entry,否则在前面插入
REDIS_STATIC void _quicklistInsert(quicklist *quicklist, quicklistEntry *entry,
void *value, const size_t sz, int after) {
int full = 0, at_tail = 0, at_head = 0, full_next = 0, full_prev = 0;
int fill = quicklist->fill;
quicklistNode *node = entry->node;
quicklistNode *new_node = NULL;
if (!node) { //如果entry为没有所属的quicklistNode节点,需要新创建
/* we have no reference node, so let's create only node in the list */
D("No node given!");
new_node = quicklistCreateNode(); //创建一个节点
//将entry值push到new_node新节点的ziplist中
new_node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_HEAD);
//将新的quicklistNode节点插入到quicklist中
__quicklistInsertNode(quicklist, NULL, new_node, after);
//更新entry计数器
new_node->count++;
quicklist->count++;
return;
}
/* Populate accounting flags for easier boolean checks later */
//如果node不能插入entry
if (!_quicklistNodeAllowInsert(node, fill, sz)) {
D("Current node is full with count %d with requested fill %lu",
node->count, fill);
full = 1; //设置full的标志
}
//如果是后插入且当前entry为尾部的entry
if (after && (entry->offset == node->count)) {
D("At Tail of current ziplist");
at_tail = 1; //设置在尾部at_tail标示
//如果node的后继节点不能插入
if (!_quicklistNodeAllowInsert(node->next, fill, sz)) {
D("Next node is full too.");
full_next = 1; //设置标示
}
}
//如果是前插入且当前entry为头部的entry
if (!after && (entry->offset == 0)) {
D("At Head");
at_head = 1; //设置at_head表示
if (!_quicklistNodeAllowInsert(node->prev, fill, sz)) { //如果node的前驱节点不能插入
D("Prev node is full too.");
full_prev = 1; //设置标示
}
}
/* Now determine where and how to insert the new element */
//如果node不满,且是后插入
if (!full && after) {
D("Not full, inserting after current position.");
quicklistDecompressNodeForUse(node); //将node临时解压
unsigned char *next = ziplistNext(node->zl, entry->zi); //返回下一个entry的地址
if (next == NULL) { //如果next为空,则直接在尾部push一个entry
node->zl = ziplistPush(node->zl, value, sz, ZIPLIST_TAIL);
} else { //否则,后插入一个entry
node->zl = ziplistInsert(node->zl, next, value, sz);
}
node->count++; //更新entry计数器
quicklistNodeUpdateSz(node); //更新ziplist的大小sz
quicklistRecompressOnly(quicklist, node); //将临时解压的重压缩
//如果node不满且是前插
} else if (!full && !after) {
D("Not full, inserting before current position.");
quicklistDecompressNodeForUse(node); //将node临时解压