forked from huangzworks/redis-3.0-annotated
/
ziplist.c
2284 lines (2027 loc) · 77.2 KB
/
ziplist.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
/* The ziplist is a specially encoded dually linked list that is designed
* to be very memory efficient.
*
* Ziplist 是为了尽可能地节约内存而设计的特殊编码双端链表。
*
* It stores both strings and integer values,
* where integers are encoded as actual integers instead of a series of
* characters.
*
* Ziplist 可以储存字符串值和整数值,
* 其中,整数值被保存为实际的整数,而不是字符数组。
*
* It allows push and pop operations on either side of the list
* in O(1) time. However, because every operation requires a reallocation of
* the memory used by the ziplist, the actual complexity is related to the
* amount of memory used by the ziplist.
*
* Ziplist 允许在列表的两端进行 O(1) 复杂度的 push 和 pop 操作。
* 但是,因为这些操作都需要对整个 ziplist 进行内存重分配,
* 所以实际的复杂度和 ziplist 占用的内存大小有关。
*
* ----------------------------------------------------------------------------
*
* ZIPLIST OVERALL LAYOUT:
* Ziplist 的整体布局:
*
* The general layout of the ziplist is as follows:
* 以下是 ziplist 的一般布局:
*
* <zlbytes><zltail><zllen><entry><entry><zlend>
*
* <zlbytes> is an unsigned integer to hold the number of bytes that the
* ziplist occupies. This value needs to be stored to be able to resize the
* entire structure without the need to traverse it first.
*
* <zlbytes> 是一个无符号整数,保存着 ziplist 使用的内存数量。
*
* 通过这个值,程序可以直接对 ziplist 的内存大小进行调整,
* 而无须为了计算 ziplist 的内存大小而遍历整个列表。
*
* <zltail> is the offset to the last entry in the list. This allows a pop
* operation on the far side of the list without the need for full traversal.
*
* <zltail> 保存着到达列表中最后一个节点的偏移量。
*
* 这个偏移量使得对表尾的 pop 操作可以在无须遍历整个列表的情况下进行。
*
* <zllen> is the number of entries.When this value is larger than 2**16-2,
* we need to traverse the entire list to know how many items it holds.
*
* <zllen> 保存着列表中的节点数量。
*
* 当 zllen 保存的值大于 2**16-2 时,
* 程序需要遍历整个列表才能知道列表实际包含了多少个节点。
*
* <zlend> is a single byte special value, equal to 255, which indicates the
* end of the list.
*
* <zlend> 的长度为 1 字节,值为 255 ,标识列表的末尾。
*
* ZIPLIST ENTRIES:
* ZIPLIST 节点:
*
* Every entry in the ziplist is prefixed by a header that contains two pieces
* of information. First, the length of the previous entry is stored to be
* able to traverse the list from back to front. Second, the encoding with an
* optional string length of the entry itself is stored.
*
* 每个 ziplist 节点的前面都带有一个 header ,这个 header 包含两部分信息:
*
* 1)前置节点的长度,在程序从后向前遍历时使用。
*
* 2)当前节点所保存的值的类型和长度。
*
* The length of the previous entry is encoded in the following way:
* If this length is smaller than 254 bytes, it will only consume a single
* byte that takes the length as value. When the length is greater than or
* equal to 254, it will consume 5 bytes. The first byte is set to 254 to
* indicate a larger value is following. The remaining 4 bytes take the
* length of the previous entry as value.
*
* 编码前置节点的长度的方法如下:
*
* 1) 如果前置节点的长度小于 254 字节,那么程序将使用 1 个字节来保存这个长度值。
*
* 2) 如果前置节点的长度大于等于 254 字节,那么程序将使用 5 个字节来保存这个长度值:
* a) 第 1 个字节的值将被设为 254 ,用于标识这是一个 5 字节长的长度值。
* b) 之后的 4 个字节则用于保存前置节点的实际长度。
*
* The other header field of the entry itself depends on the contents of the
* entry. When the entry is a string, the first 2 bits of this header will hold
* the type of encoding used to store the length of the string, followed by the
* actual length of the string. When the entry is an integer the first 2 bits
* are both set to 1. The following 2 bits are used to specify what kind of
* integer will be stored after this header. An overview of the different
* types and encodings is as follows:
*
* header 另一部分的内容和节点所保存的值有关。
*
* 1) 如果节点保存的是字符串值,
* 那么这部分 header 的头 2 个位将保存编码字符串长度所使用的类型,
* 而之后跟着的内容则是字符串的实际长度。
*
* |00pppppp| - 1 byte
* String value with length less than or equal to 63 bytes (6 bits).
* 字符串的长度小于或等于 63 字节。
* |01pppppp|qqqqqqqq| - 2 bytes
* String value with length less than or equal to 16383 bytes (14 bits).
* 字符串的长度小于或等于 16383 字节。
* |10______|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes
* String value with length greater than or equal to 16384 bytes.
* 字符串的长度大于或等于 16384 字节。
*
* 2) 如果节点保存的是整数值,
* 那么这部分 header 的头 2 位都将被设置为 1 ,
* 而之后跟着的 2 位则用于标识节点所保存的整数的类型。
*
* |11000000| - 1 byte
* Integer encoded as int16_t (2 bytes).
* 节点的值为 int16_t 类型的整数,长度为 2 字节。
* |11010000| - 1 byte
* Integer encoded as int32_t (4 bytes).
* 节点的值为 int32_t 类型的整数,长度为 4 字节。
* |11100000| - 1 byte
* Integer encoded as int64_t (8 bytes).
* 节点的值为 int64_t 类型的整数,长度为 8 字节。
* |11110000| - 1 byte
* Integer encoded as 24 bit signed (3 bytes).
* 节点的值为 24 位(3 字节)长的整数。
* |11111110| - 1 byte
* Integer encoded as 8 bit signed (1 byte).
* 节点的值为 8 位(1 字节)长的整数。
* |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer.
* Unsigned integer from 0 to 12. The encoded value is actually from
* 1 to 13 because 0000 and 1111 can not be used, so 1 should be
* subtracted from the encoded 4 bit value to obtain the right value.
* 节点的值为介于 0 至 12 之间的无符号整数。
* 因为 0000 和 1111 都不能使用,所以位的实际值将是 1 至 13 。
* 程序在取得这 4 个位的值之后,还需要减去 1 ,才能计算出正确的值。
* 比如说,如果位的值为 0001 = 1 ,那么程序返回的值将是 1 - 1 = 0 。
* |11111111| - End of ziplist.
* ziplist 的结尾标识
*
* All the integers are represented in little endian byte order.
*
* 所有整数都表示为小端字节序。
*
* ----------------------------------------------------------------------------
*
* Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* 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 retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include "zmalloc.h"
#include "util.h"
#include "ziplist.h"
#include "endianconv.h"
#include "redisassert.h"
/*
* ziplist 末端标识符,以及 5 字节长长度标识符
*/
#define ZIP_END 255
#define ZIP_BIGLEN 254
/* Different encoding/length possibilities */
/*
* 字符串编码和整数编码的掩码
*/
#define ZIP_STR_MASK 0xc0
#define ZIP_INT_MASK 0x30
/*
* 字符串编码类型
*/
#define ZIP_STR_06B (0 << 6)
#define ZIP_STR_14B (1 << 6)
#define ZIP_STR_32B (2 << 6)
/*
* 整数编码类型
*/
#define ZIP_INT_16B (0xc0 | 0<<4)
#define ZIP_INT_32B (0xc0 | 1<<4)
#define ZIP_INT_64B (0xc0 | 2<<4)
#define ZIP_INT_24B (0xc0 | 3<<4)
#define ZIP_INT_8B 0xfe
/* 4 bit integer immediate encoding
*
* 4 位整数编码的掩码和类型
*/
#define ZIP_INT_IMM_MASK 0x0f
#define ZIP_INT_IMM_MIN 0xf1 /* 11110001 */
#define ZIP_INT_IMM_MAX 0xfd /* 11111101 */
#define ZIP_INT_IMM_VAL(v) (v & ZIP_INT_IMM_MASK)
/*
* 24 位整数的最大值和最小值
*/
#define INT24_MAX 0x7fffff
#define INT24_MIN (-INT24_MAX - 1)
/* Macro to determine type
*
* 查看给定编码 enc 是否字符串编码
*/
#define ZIP_IS_STR(enc) (((enc) & ZIP_STR_MASK) < ZIP_STR_MASK)
/* Utility macros */
/*
* ziplist 属性宏
*/
// 定位到 ziplist 的 bytes 属性,该属性记录了整个 ziplist 所占用的内存字节数
// 用于取出 bytes 属性的现有值,或者为 bytes 属性赋予新值
#define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl)))
// 定位到 ziplist 的 offset 属性,该属性记录了到达表尾节点的偏移量
// 用于取出 offset 属性的现有值,或者为 offset 属性赋予新值
#define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint32_t))))
// 定位到 ziplist 的 length 属性,该属性记录了 ziplist 包含的节点数量
// 用于取出 length 属性的现有值,或者为 length 属性赋予新值
#define ZIPLIST_LENGTH(zl) (*((uint16_t*)((zl)+sizeof(uint32_t)*2)))
// 返回 ziplist 表头的大小
#define ZIPLIST_HEADER_SIZE (sizeof(uint32_t)*2+sizeof(uint16_t))
// 返回指向 ziplist 第一个节点(的起始位置)的指针
#define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE)
// 返回指向 ziplist 最后一个节点(的起始位置)的指针
#define ZIPLIST_ENTRY_TAIL(zl) ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))
// 返回指向 ziplist 末端 ZIP_END (的起始位置)的指针
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
/*
空白 ziplist 示例图
area |<---- ziplist header ---->|<-- end -->|
size 4 bytes 4 bytes 2 bytes 1 byte
+---------+--------+-------+-----------+
component | zlbytes | zltail | zllen | zlend |
| | | | |
value | 1011 | 1010 | 0 | 1111 1111 |
+---------+--------+-------+-----------+
^
|
ZIPLIST_ENTRY_HEAD
&
address ZIPLIST_ENTRY_TAIL
&
ZIPLIST_ENTRY_END
非空 ziplist 示例图
area |<---- ziplist header ---->|<----------- entries ------------->|<-end->|
size 4 bytes 4 bytes 2 bytes ? ? ? ? 1 byte
+---------+--------+-------+--------+--------+--------+--------+-------+
component | zlbytes | zltail | zllen | entry1 | entry2 | ... | entryN | zlend |
+---------+--------+-------+--------+--------+--------+--------+-------+
^ ^ ^
address | | |
ZIPLIST_ENTRY_HEAD | ZIPLIST_ENTRY_END
|
ZIPLIST_ENTRY_TAIL
*/
/* We know a positive increment can only be 1 because entries can only be
* pushed one at a time. */
/*
* 增加 ziplist 的节点数
*
* T = O(1)
*/
#define ZIPLIST_INCR_LENGTH(zl,incr) { \
if (ZIPLIST_LENGTH(zl) < UINT16_MAX) \
ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \
}
/*
* 保存 ziplist 节点信息的结构
*/
typedef struct zlentry {
// prevrawlen :前置节点的长度
// prevrawlensize :编码 prevrawlen 所需的字节大小
unsigned int prevrawlensize, prevrawlen;
// len :当前节点值的长度
// lensize :编码 len 所需的字节大小
unsigned int lensize, len;
// 当前节点 header 的大小
// 等于 prevrawlensize + lensize
unsigned int headersize;
// 当前节点值所使用的编码类型
unsigned char encoding;
// 指向当前节点的指针
unsigned char *p;
} zlentry;
/* Extract the encoding from the byte pointed by 'ptr' and set it into
* 'encoding'.
*
* 从 ptr 中取出节点值的编码类型,并将它保存到 encoding 变量中。
*
* T = O(1)
*/
#define ZIP_ENTRY_ENCODING(ptr, encoding) do { \
(encoding) = (ptr[0]); \
if ((encoding) < ZIP_STR_MASK) (encoding) &= ZIP_STR_MASK; \
} while(0)
/* Return bytes needed to store integer encoded by 'encoding'
*
* 返回保存 encoding 编码的值所需的字节数量
*
* T = O(1)
*/
static unsigned int zipIntSize(unsigned char encoding) {
switch(encoding) {
case ZIP_INT_8B: return 1;
case ZIP_INT_16B: return 2;
case ZIP_INT_24B: return 3;
case ZIP_INT_32B: return 4;
case ZIP_INT_64B: return 8;
default: return 0; /* 4 bit immediate */
}
assert(NULL);
return 0;
}
/* Encode the length 'l' writing it in 'p'. If p is NULL it just returns
* the amount of bytes required to encode such a length.
*
* 编码节点长度值 l ,并将它写入到 p 中,然后返回编码 l 所需的字节数量。
*
* 如果 p 为 NULL ,那么仅返回编码 l 所需的字节数量,不进行写入。
*
* T = O(1)
*/
static unsigned int zipEncodeLength(unsigned char *p, unsigned char encoding, unsigned int rawlen) {
unsigned char len = 1, buf[5];
// 编码字符串
if (ZIP_IS_STR(encoding)) {
/* Although encoding is given it may not be set for strings,
* so we determine it here using the raw length. */
if (rawlen <= 0x3f) {
if (!p) return len;
buf[0] = ZIP_STR_06B | rawlen;
} else if (rawlen <= 0x3fff) {
len += 1;
if (!p) return len;
buf[0] = ZIP_STR_14B | ((rawlen >> 8) & 0x3f);
buf[1] = rawlen & 0xff;
} else {
len += 4;
if (!p) return len;
buf[0] = ZIP_STR_32B;
buf[1] = (rawlen >> 24) & 0xff;
buf[2] = (rawlen >> 16) & 0xff;
buf[3] = (rawlen >> 8) & 0xff;
buf[4] = rawlen & 0xff;
}
// 编码整数
} else {
/* Implies integer encoding, so length is always 1. */
if (!p) return len;
buf[0] = encoding;
}
/* Store this length at p */
// 将编码后的长度写入 p
memcpy(p,buf,len);
// 返回编码所需的字节数
return len;
}
/* Decode the length encoded in 'ptr'. The 'encoding' variable will hold the
* entries encoding, the 'lensize' variable will hold the number of bytes
* required to encode the entries length, and the 'len' variable will hold the
* entries length.
*
* 解码 ptr 指针,取出列表节点的相关信息,并将它们保存在以下变量中:
*
* - encoding 保存节点值的编码类型。
*
* - lensize 保存编码节点长度所需的字节数。
*
* - len 保存节点的长度。
*
* T = O(1)
*/
#define ZIP_DECODE_LENGTH(ptr, encoding, lensize, len) do { \
\
/* 取出值的编码类型 */ \
ZIP_ENTRY_ENCODING((ptr), (encoding)); \
\
/* 字符串编码 */ \
if ((encoding) < ZIP_STR_MASK) { \
if ((encoding) == ZIP_STR_06B) { \
(lensize) = 1; \
(len) = (ptr)[0] & 0x3f; \
} else if ((encoding) == ZIP_STR_14B) { \
(lensize) = 2; \
(len) = (((ptr)[0] & 0x3f) << 8) | (ptr)[1]; \
} else if (encoding == ZIP_STR_32B) { \
(lensize) = 5; \
(len) = ((ptr)[1] << 24) | \
((ptr)[2] << 16) | \
((ptr)[3] << 8) | \
((ptr)[4]); \
} else { \
assert(NULL); \
} \
\
/* 整数编码 */ \
} else { \
(lensize) = 1; \
(len) = zipIntSize(encoding); \
} \
} while(0);
/* Encode the length of the previous entry and write it to "p". Return the
* number of bytes needed to encode this length if "p" is NULL.
*
* 对前置节点的长度 len 进行编码,并将它写入到 p 中,
* 然后返回编码 len 所需的字节数量。
*
* 如果 p 为 NULL ,那么不进行写入,仅返回编码 len 所需的字节数量。
*
* T = O(1)
*/
static unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) {
// 仅返回编码 len 所需的字节数量
if (p == NULL) {
return (len < ZIP_BIGLEN) ? 1 : sizeof(len)+1;
// 写入并返回编码 len 所需的字节数量
} else {
// 1 字节
if (len < ZIP_BIGLEN) {
p[0] = len;
return 1;
// 5 字节
} else {
// 添加 5 字节长度标识
p[0] = ZIP_BIGLEN;
// 写入编码
memcpy(p+1,&len,sizeof(len));
// 如果有必要的话,进行大小端转换
memrev32ifbe(p+1);
// 返回编码长度
return 1+sizeof(len);
}
}
}
/* Encode the length of the previous entry and write it to "p". This only
* uses the larger encoding (required in __ziplistCascadeUpdate).
*
* 将原本只需要 1 个字节来保存的前置节点长度 len 编码至一个 5 字节长的 header 中。
*
* T = O(1)
*/
static void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) {
if (p == NULL) return;
// 设置 5 字节长度标识
p[0] = ZIP_BIGLEN;
// 写入 len
memcpy(p+1,&len,sizeof(len));
memrev32ifbe(p+1);
}
/* Decode the number of bytes required to store the length of the previous
* element, from the perspective of the entry pointed to by 'ptr'.
*
* 解码 ptr 指针,
* 取出编码前置节点长度所需的字节数,并将它保存到 prevlensize 变量中。
*
* T = O(1)
*/
#define ZIP_DECODE_PREVLENSIZE(ptr, prevlensize) do { \
if ((ptr)[0] < ZIP_BIGLEN) { \
(prevlensize) = 1; \
} else { \
(prevlensize) = 5; \
} \
} while(0);
/* Decode the length of the previous element, from the perspective of the entry
* pointed to by 'ptr'.
*
* 解码 ptr 指针,
* 取出编码前置节点长度所需的字节数,
* 并将这个字节数保存到 prevlensize 中。
*
* 然后根据 prevlensize ,从 ptr 中取出前置节点的长度值,
* 并将这个长度值保存到 prevlen 变量中。
*
* T = O(1)
*/
#define ZIP_DECODE_PREVLEN(ptr, prevlensize, prevlen) do { \
\
/* 先计算被编码长度值的字节数 */ \
ZIP_DECODE_PREVLENSIZE(ptr, prevlensize); \
\
/* 再根据编码字节数来取出长度值 */ \
if ((prevlensize) == 1) { \
(prevlen) = (ptr)[0]; \
} else if ((prevlensize) == 5) { \
assert(sizeof((prevlensize)) == 4); \
memcpy(&(prevlen), ((char*)(ptr)) + 1, 4); \
memrev32ifbe(&prevlen); \
} \
} while(0);
/* Return the difference in number of bytes needed to store the length of the
* previous element 'len', in the entry pointed to by 'p'.
*
* 计算编码新的前置节点长度 len 所需的字节数,
* 减去编码 p 原来的前置节点长度所需的字节数之差。
*
* T = O(1)
*/
static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
unsigned int prevlensize;
// 取出编码原来的前置节点长度所需的字节数
// T = O(1)
ZIP_DECODE_PREVLENSIZE(p, prevlensize);
// 计算编码 len 所需的字节数,然后进行减法运算
// T = O(1)
return zipPrevEncodeLength(NULL, len) - prevlensize;
}
/* Return the total number of bytes used by the entry pointed to by 'p'.
*
* 返回指针 p 所指向的节点占用的字节数总和。
*
* T = O(1)
*/
static unsigned int zipRawEntryLength(unsigned char *p) {
unsigned int prevlensize, encoding, lensize, len;
// 取出编码前置节点的长度所需的字节数
// T = O(1)
ZIP_DECODE_PREVLENSIZE(p, prevlensize);
// 取出当前节点值的编码类型,编码节点值长度所需的字节数,以及节点值的长度
// T = O(1)
ZIP_DECODE_LENGTH(p + prevlensize, encoding, lensize, len);
// 计算节点占用的字节数总和
return prevlensize + lensize + len;
}
/* Check if string pointed to by 'entry' can be encoded as an integer.
* Stores the integer value in 'v' and its encoding in 'encoding'.
*
* 检查 entry 中指向的字符串能否被编码为整数。
*
* 如果可以的话,
* 将编码后的整数保存在指针 v 的值中,并将编码的方式保存在指针 encoding 的值中。
*
* 注意,这里的 entry 和前面代表节点的 entry 不是一个意思。
*
* T = O(N)
*/
static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {
long long value;
// 忽略太长或太短的字符串
if (entrylen >= 32 || entrylen == 0) return 0;
// 尝试转换
// T = O(N)
if (string2ll((char*)entry,entrylen,&value)) {
/* Great, the string can be encoded. Check what's the smallest
* of our encoding types that can hold this value. */
// 转换成功,以从小到大的顺序检查适合值 value 的编码方式
if (value >= 0 && value <= 12) {
*encoding = ZIP_INT_IMM_MIN+value;
} else if (value >= INT8_MIN && value <= INT8_MAX) {
*encoding = ZIP_INT_8B;
} else if (value >= INT16_MIN && value <= INT16_MAX) {
*encoding = ZIP_INT_16B;
} else if (value >= INT24_MIN && value <= INT24_MAX) {
*encoding = ZIP_INT_24B;
} else if (value >= INT32_MIN && value <= INT32_MAX) {
*encoding = ZIP_INT_32B;
} else {
*encoding = ZIP_INT_64B;
}
// 记录值到指针
*v = value;
// 返回转换成功标识
return 1;
}
// 转换失败
return 0;
}
/* Store integer 'value' at 'p', encoded as 'encoding'
*
* 以 encoding 指定的编码方式,将整数值 value 写入到 p 。
*
* T = O(1)
*/
static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encoding) {
int16_t i16;
int32_t i32;
int64_t i64;
if (encoding == ZIP_INT_8B) {
((int8_t*)p)[0] = (int8_t)value;
} else if (encoding == ZIP_INT_16B) {
i16 = value;
memcpy(p,&i16,sizeof(i16));
memrev16ifbe(p);
} else if (encoding == ZIP_INT_24B) {
i32 = value<<8;
memrev32ifbe(&i32);
memcpy(p,((uint8_t*)&i32)+1,sizeof(i32)-sizeof(uint8_t));
} else if (encoding == ZIP_INT_32B) {
i32 = value;
memcpy(p,&i32,sizeof(i32));
memrev32ifbe(p);
} else if (encoding == ZIP_INT_64B) {
i64 = value;
memcpy(p,&i64,sizeof(i64));
memrev64ifbe(p);
} else if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX) {
/* Nothing to do, the value is stored in the encoding itself. */
} else {
assert(NULL);
}
}
/* Read integer encoded as 'encoding' from 'p'
*
* 以 encoding 指定的编码方式,读取并返回指针 p 中的整数值。
*
* T = O(1)
*/
static int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {
int16_t i16;
int32_t i32;
int64_t i64, ret = 0;
if (encoding == ZIP_INT_8B) {
ret = ((int8_t*)p)[0];
} else if (encoding == ZIP_INT_16B) {
memcpy(&i16,p,sizeof(i16));
memrev16ifbe(&i16);
ret = i16;
} else if (encoding == ZIP_INT_32B) {
memcpy(&i32,p,sizeof(i32));
memrev32ifbe(&i32);
ret = i32;
} else if (encoding == ZIP_INT_24B) {
i32 = 0;
memcpy(((uint8_t*)&i32)+1,p,sizeof(i32)-sizeof(uint8_t));
memrev32ifbe(&i32);
ret = i32>>8;
} else if (encoding == ZIP_INT_64B) {
memcpy(&i64,p,sizeof(i64));
memrev64ifbe(&i64);
ret = i64;
} else if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX) {
ret = (encoding & ZIP_INT_IMM_MASK)-1;
} else {
assert(NULL);
}
return ret;
}
/* Return a struct with all information about an entry.
*
* 将 p 所指向的列表节点的信息全部保存到 zlentry 中,并返回该 zlentry 。
*
* T = O(1)
*/
static zlentry zipEntry(unsigned char *p) {
zlentry e;
// e.prevrawlensize 保存着编码前一个节点的长度所需的字节数
// e.prevrawlen 保存着前一个节点的长度
// T = O(1)
ZIP_DECODE_PREVLEN(p, e.prevrawlensize, e.prevrawlen);
// p + e.prevrawlensize 将指针移动到列表节点本身
// e.encoding 保存着节点值的编码类型
// e.lensize 保存着编码节点值长度所需的字节数
// e.len 保存着节点值的长度
// T = O(1)
ZIP_DECODE_LENGTH(p + e.prevrawlensize, e.encoding, e.lensize, e.len);
// 计算头结点的字节数
e.headersize = e.prevrawlensize + e.lensize;
// 记录指针
e.p = p;
return e;
}
/* Create a new empty ziplist.
*
* 创建并返回一个新的 ziplist
*
* T = O(1)
*/
unsigned char *ziplistNew(void) {
// ZIPLIST_HEADER_SIZE 是 ziplist 表头的大小
// 1 字节是表末端 ZIP_END 的大小
unsigned int bytes = ZIPLIST_HEADER_SIZE+1;
// 为表头和表末端分配空间
unsigned char *zl = zmalloc(bytes);
// 初始化表属性
ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
ZIPLIST_LENGTH(zl) = 0;
// 设置表末端
zl[bytes-1] = ZIP_END;
return zl;
}
/* Resize the ziplist.
*
* 调整 ziplist 的大小为 len 字节。
*
* 当 ziplist 原有的大小小于 len 时,扩展 ziplist 不会改变 ziplist 原有的元素。
*
* T = O(N)
*/
static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
// 用 zrealloc ,扩展时不改变现有元素
zl = zrealloc(zl,len);
// 更新 bytes 属性
ZIPLIST_BYTES(zl) = intrev32ifbe(len);
// 重新设置表末端
zl[len-1] = ZIP_END;
return zl;
}
/* When an entry is inserted, we need to set the prevlen field of the next
* entry to equal the length of the inserted entry. It can occur that this
* length cannot be encoded in 1 byte and the next entry needs to be grow
* a bit larger to hold the 5-byte encoded prevlen. This can be done for free,
* because this only happens when an entry is already being inserted (which
* causes a realloc and memmove). However, encoding the prevlen may require
* that this entry is grown as well. This effect may cascade throughout
* the ziplist when there are consecutive entries with a size close to
* ZIP_BIGLEN, so we need to check that the prevlen can be encoded in every
* consecutive entry.
*
* 当将一个新节点添加到某个节点之前的时候,
* 如果原节点的 header 空间不足以保存新节点的长度,
* 那么就需要对原节点的 header 空间进行扩展(从 1 字节扩展到 5 字节)。
*
* 但是,当对原节点进行扩展之后,原节点的下一个节点的 prevlen 可能出现空间不足,
* 这种情况在多个连续节点的长度都接近 ZIP_BIGLEN 时可能发生。
*
* 这个函数就用于检查并修复后续节点的空间问题。
*
* Note that this effect can also happen in reverse, where the bytes required
* to encode the prevlen field can shrink. This effect is deliberately ignored,
* because it can cause a "flapping" effect where a chain prevlen fields is
* first grown and then shrunk again after consecutive inserts. Rather, the
* field is allowed to stay larger than necessary, because a large prevlen
* field implies the ziplist is holding large entries anyway.
*
* 反过来说,
* 因为节点的长度变小而引起的连续缩小也是可能出现的,
* 不过,为了避免扩展-缩小-扩展-缩小这样的情况反复出现(flapping,抖动),
* 我们不处理这种情况,而是任由 prevlen 比所需的长度更长。
* The pointer "p" points to the first entry that does NOT need to be
* updated, i.e. consecutive fields MAY need an update.
*
* 注意,程序的检查是针对 p 的后续节点,而不是 p 所指向的节点。
* 因为节点 p 在传入之前已经完成了所需的空间扩展工作。
*
* T = O(N^2)
*/
static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p) {
size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), rawlen, rawlensize;
size_t offset, noffset, extra;
unsigned char *np;
zlentry cur, next;
// T = O(N^2)
while (p[0] != ZIP_END) {
// 将 p 所指向的节点的信息保存到 cur 结构中
cur = zipEntry(p);
// 当前节点的长度
rawlen = cur.headersize + cur.len;
// 计算编码当前节点的长度所需的字节数
// T = O(1)
rawlensize = zipPrevEncodeLength(NULL,rawlen);
/* Abort if there is no next entry. */
// 如果已经没有后续空间需要更新了,跳出
if (p[rawlen] == ZIP_END) break;
// 取出后续节点的信息,保存到 next 结构中
// T = O(1)
next = zipEntry(p+rawlen);
/* Abort when "prevlen" has not changed. */
// 后续节点编码当前节点的空间已经足够,无须再进行任何处理,跳出
// 可以证明,只要遇到一个空间足够的节点,
// 那么这个节点之后的所有节点的空间都是足够的
if (next.prevrawlen == rawlen) break;
if (next.prevrawlensize < rawlensize) {
/* The "prevlen" field of "next" needs more bytes to hold
* the raw length of "cur". */
// 执行到这里,表示 next 空间的大小不足以编码 cur 的长度
// 所以程序需要对 next 节点的(header 部分)空间进行扩展
// 记录 p 的偏移量
offset = p-zl;
// 计算需要增加的节点数量
extra = rawlensize-next.prevrawlensize;
// 扩展 zl 的大小
// T = O(N)
zl = ziplistResize(zl,curlen+extra);
// 还原指针 p
p = zl+offset;
/* Current pointer and offset for next element. */
// 记录下一节点的偏移量
np = p+rawlen;
noffset = np-zl;
/* Update tail offset when next element is not the tail element. */
// 当 next 节点不是表尾节点时,更新列表到表尾节点的偏移量
//
// 不用更新的情况(next 为表尾节点):
//
// | | next | ==> | | new next |
// ^ ^
// | |
// tail tail
//
// 需要更新的情况(next 不是表尾节点):
//
// | next | | ==> | new next | |
// ^ ^
// | |
// old tail old tail
//
// 更新之后:
//
// | new next | |
// ^
// |
// new tail
// T = O(1)
if ((zl+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))) != np) {
ZIPLIST_TAIL_OFFSET(zl) =
intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+extra);
}
/* Move the tail to the back. */
// 向后移动 cur 节点之后的数据,为 cur 的新 header 腾出空间
//
// 示例:
//
// | header | value | ==> | header | | value | ==> | header | value |
// |<-->|
// 为新 header 腾出的空间
// T = O(N)
memmove(np+rawlensize,
np+next.prevrawlensize,
curlen-noffset-next.prevrawlensize-1);
// 将新的前一节点长度值编码进新的 next 节点的 header
// T = O(1)
zipPrevEncodeLength(np,rawlen);
/* Advance the cursor */
// 移动指针,继续处理下个节点
p += rawlen;
curlen += extra;
} else {
if (next.prevrawlensize > rawlensize) {
/* This would result in shrinking, which we want to avoid.
* So, set "rawlen" in the available bytes. */
// 执行到这里,说明 next 节点编码前置节点的 header 空间有 5 字节
// 而编码 rawlen 只需要 1 字节
// 但是程序不会对 next 进行缩小,
// 所以这里只将 rawlen 写入 5 字节的 header 中就算了。
// T = O(1)
zipPrevEncodeLengthForceLarge(p+rawlen,rawlen);
} else {
// 运行到这里,
// 说明 cur 节点的长度正好可以编码到 next 节点的 header 中
// T = O(1)
zipPrevEncodeLength(p+rawlen,rawlen);
}
/* Stop here, as the raw length of "next" has not changed. */
break;
}
}
return zl;
}
/* Delete "num" entries, starting at "p". Returns pointer to the ziplist.
*
* 从位置 p 开始,连续删除 num 个节点。
*
* 函数的返回值为处理删除操作之后的 ziplist 。
*
* T = O(N^2)
*/
static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {
unsigned int i, totlen, deleted = 0;
size_t offset;
int nextdiff = 0;
zlentry first, tail;
// 计算被删除节点总共占用的内存字节数
// 以及被删除节点的总个数
// T = O(N)
first = zipEntry(p);
for (i = 0; p[0] != ZIP_END && i < num; i++) {
p += zipRawEntryLength(p);
deleted++;
}
// totlen 是所有被删除节点总共占用的内存字节数
totlen = p-first.p;
if (totlen > 0) {
if (p[0] != ZIP_END) {
// 执行这里,表示被删除节点之后仍然有节点存在