-
Notifications
You must be signed in to change notification settings - Fork 263
/
t_zset.c
3509 lines (3111 loc) · 136 KB
/
t_zset.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
/*
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis 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.
*/
/*-----------------------------------------------------------------------------
* Sorted set API
*----------------------------------------------------------------------------*/
/* ZSETs are ordered sets using two data structures to hold the same elements
* in order to get O(log(N)) INSERT and REMOVE operations into a sorted
* data structure.
*
* The elements are added to a hash table mapping Redis objects to scores.
* At the same time the elements are added to a skip list mapping scores
* to Redis objects (so objects are sorted by scores in this "view"). */
/* This skiplist implementation is almost a C translation of the original
* algorithm described by William Pugh in "Skip Lists: A Probabilistic
* Alternative to Balanced Trees", modified in three ways:
* a) this implementation allows for repeated scores.
* b) the comparison is not just by key (our 'score') but by satellite data.
* c) there is a back pointer, so it's a doubly linked list with the back
* pointers being only at "level 1". This allows to traverse the list
* from tail to head, useful for ZREVRANGE. */
#include "server.h"
#include <math.h>
static int zslLexValueGteMin(robj *value, zlexrangespec *spec);
static int zslLexValueLteMax(robj *value, zlexrangespec *spec);
//创建一个层数level,分数为score,对象为obj的跳跃表节点
zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel)); //分配空间
zn->score = score;//设置分数
zn->obj = obj; //设置对象
return zn; //返回节点地址
}
//创建返回一个跳跃表 表头zskiplist
zskiplist *zslCreate(void) {
int j;
zskiplist *zsl;
zsl = zmalloc(sizeof(*zsl));//分配空间
zsl->level = 1;//设置默认层数
zsl->length = 0;//设置跳跃表长度
//创建一个层数为32,分数为0,没有obj的跳跃表头节点
zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
//跳跃表头节点初始化
for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
zsl->header->level[j].forward = NULL;//将跳跃表头节点的所有前进指针forward设置为NULL
zsl->header->level[j].span = 0;//将跳跃表头节点的所有跨度span设置为0
}
zsl->header->backward = NULL;//跳跃表头节点的后退指针backward置为NULL
zsl->tail = NULL;//表头指向跳跃表尾节点的指针置为NULL
return zsl;
}
void zslFreeNode(zskiplistNode *node) {//释放一个跳跃表节点
decrRefCount(node->obj);//该节点对象的引用计数减1
zfree(node);//释放该该节点空间
}
void zslFree(zskiplist *zsl) {//释放跳跃表表头zsl,以及跳跃表节点
zskiplistNode *node = zsl->header->level[0].forward, *next;
zfree(zsl->header);//释放跳跃表的头节点
while(node) {//释放其他节点
next = node->level[0].forward;//备份下一个节点地址
zslFreeNode(node);//释放节点空间
node = next;//指向下一个节点
}
zfree(zsl);//释放表头
}
/* Returns a random level for the new skiplist node we are going to create.
* The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
* (both inclusive), with a powerlaw-alike distribution where higher
* levels are less likely to be returned. */
int zslRandomLevel(void) {//返回一个随机层数值
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))//ZSKIPLIST_P(0.25)
level += 1;//返回一个1到ZSKIPLIST_MAXLEVEL(32)之间的值
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
//创建一个节点,分数为score,对象为obj,插入到zsl表头管理的跳跃表中,并返回新节点的地址
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned int rank[ZSKIPLIST_MAXLEVEL];
int i, level;
serverAssert(!isnan(score));
x = zsl->header;//获取跳跃表头结点地址,从头节点开始一层一层遍历
for (i = zsl->level-1; i >= 0; i--) {//遍历头节点的每个level,从下标最大层减1到0
/* store rank that is crossed to reach the insert position */
rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];//更新rank[i]为i+1所跨越的节点数,但是最外一层为0
//这个while循环是查找的过程,沿着x指针遍历跳跃表,满足以下条件则要继续在当层往前走
while (x->level[i].forward && //当前层的前进指针不为空且
(x->level[i].forward->score < score ||//当前的要插入的score大于当前层的score或
(x->level[i].forward->score == score &&//当前score等于要插入的score且
compareStringObjects(x->level[i].forward->obj,obj) < 0))) {//当前层的对象与要插入的obj不等
rank[i] += x->level[i].span;//记录该层一共跨越了多少节点 加上 上一层遍历所跨越的节点数
x = x->level[i].forward;//指向下一个节点
}
//while循环跳出时,用update[i]记录第i层所遍历到的最后一个节点,遍历到i=0时,就要在该节点后要插入节点
update[i] = x;
}
/* we assume the key is not already inside, since we allow duplicated
* scores, and the re-insertion of score and redis object should never
* happen since the caller of zslInsert() should test in the hash table
* if the element is already inside or not.
* zslInsert() 的调用者会确保同分值且同成员的元素不会出现,
* 所以这里不需要进一步进行检查,可以直接创建新元素。
*/
level = zslRandomLevel();//获得一个随机的层数
if (level > zsl->level) {//如果大于当前所有节点最大的层数时
for (i = zsl->level; i < level; i++) {
rank[i] = 0;//将大于等于原来zsl->level层以上的rank[]设置为0
update[i] = zsl->header;//将大于等于原来zsl->level层以上update[i]指向头结点
update[i]->level[i].span = zsl->length;//update[i]已经指向头结点,将第i层的跨度设置为length
//length代表跳跃表的节点数量
}
zsl->level = level;//更新表中的最大成数值
}
x = zslCreateNode(level,score,obj); //创建一个节点
for (i = 0; i < level; i++) { //遍历每一层
x->level[i].forward = update[i]->level[i].forward;//设置新节点的前进指针为查找时(while循环)每一层最后一个节点的的前进指针
update[i]->level[i].forward = x;//再把查找时每层的最后一个节点的前进指针设置为新创建的节点地址
/* update span covered by update[i] as x is inserted here */
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);//更新插入节点的跨度值
update[i]->level[i].span = (rank[0] - rank[i]) + 1; //更新插入节点前一个节点的跨度值
}
/* increment span for untouched levels */
for (i = level; i < zsl->level; i++) {//如果插入节点的level小于原来的zsl->level才会执行
update[i]->level[i].span++;//因为高度没有达到这些层,所以只需将查找时每层最后一个节点的值的跨度加1
}
//设置插入节点的后退指针,就是查找时最下层的最后一个节点,该节点的地址记录在update[0]中
//如果插入在第二个节点,也就是头结点后的位置就将后退指针设置为NULL
x->backward = (update[0] == zsl->header) ? NULL : update[0];
if (x->level[0].forward)//如果x节点不是最尾部的节点
x->level[0].forward->backward = x;//就将x节点后面的节点的后退节点设置成为x地址
else
zsl->tail = x;//否则更新表头的tail指针,指向最尾部的节点x
zsl->length++;//跳跃表节点计数器加1
return x; //返回x地址
}
/* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
//被zslDelete, zslDeleteByScore and zslDeleteByRank使用的内部函数
void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {//删除节点
int i;
//设置前进指针和跨度
for (i = 0; i < zsl->level; i++) {//遍历下标为0到跳跃表最大层数-1的层
if (update[i]->level[i].forward == x) {//如果找到该节点
update[i]->level[i].span += x->level[i].span - 1;//将前一个节点的跨度减1
update[i]->level[i].forward = x->level[i].forward;
//前一个节点的前进指针指向被删除的节点的后一个节点,跳过该节点
} else {
update[i]->level[i].span -= 1;//在第i层没找到,只将该层的最后一个节点的跨度减1
}
}
//设置后退指针
if (x->level[0].forward) { //如果被删除的前进节点不为空,后面还有节点
x->level[0].forward->backward = x->backward;//就将后面节点的后退指针指向被删除节点x的回退指针
} else {
zsl->tail = x->backward;//否则直接将被删除的x节点的后退节点设置为表头的tail指针
}
//更新跳跃表最大层数
while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
zsl->level--;
zsl->length--;//节点计数器减1
}
/* Delete an element with matching score/object from the skiplist. */
int zslDelete(zskiplist *zsl, double score, robj *obj) {//删除score和obj的节点
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
int i;
//下面的循环类似于zslInsert的查找部分
x = zsl->header; //获取跳跃表头结点地址,从头节点开始一层一层遍历
for (i = zsl->level-1; i >= 0; i--) { //遍历头节点的每个level,从下标最大层减1到0
//这个while循环是查找的过程,沿着x指针遍历跳跃表,满足以下条件则要继续在当层往前走
while (x->level[i].forward && //当前层的前进指针不为空且
(x->level[i].forward->score < score ||//当前的要插入的score大于当前层的score或
(x->level[i].forward->score == score &&//当前score等于要插入的score且
compareStringObjects(x->level[i].forward->obj,obj) < 0)))//当前层的对象与要插入的obj不等
x = x->level[i].forward; //指向下一个节点
//while循环跳出时,用update[i]记录第i层所遍历到的最后一个节点,遍历到i=0时,就要在该节点后要插入节点
update[i] = x;
}
/* We may have multiple elements with the same score, what we need
* is to find the element with both the right score and object. */
x = x->level[0].forward;//获取x的后面一个节点
if (x && score == x->score && equalStringObjects(x->obj,obj)) {//如果是要被删除的节点
zslDeleteNode(zsl, x, update);//删除该节点
zslFreeNode(x);//释放空间
return 1;//删除成功
}
return 0; /* not found */
}
//value 是否大于(或大于等于)范围 spec 中的 min 项
//如果返回1表示value大于等于min,否则返回0
static int zslValueGteMin(double value, zrangespec *spec) {
return spec->minex ? (value > spec->min) : (value >= spec->min);
}
//value是否小于或小于等于范围 spec 中的max
//返回1表示value小于等于max,否则返回0
int zslValueLteMax(double value, zrangespec *spec) {
return spec->maxex ? (value < spec->max) : (value <= spec->max);
}
/* Returns if there is a part of the zset is in range. */
int zslIsInRange(zskiplist *zsl, zrangespec *range) {//如果range范围包含在跳跃表的范围返回1,否则返回0
zskiplistNode *x;
/* Test for ranges that will always be empty. */
if (range->min > range->max ||
(range->min == range->max && (range->minex || range->maxex)))//排除错误范围,或0范围
return 0;
//最高分
x = zsl->tail;
if (x == NULL || !zslValueGteMin(x->score,range))//最大分值比range的min还小,返回0,取非,则return 0
return 0;
//最低分
x = zsl->header->level[0].forward;
if (x == NULL || !zslValueLteMax(x->score,range))//最小分值比range的最大分值还要大,return 0
return 0;
return 1; //最大值大于min,最小值小于max且min小于max返回1
}
/* Find the first node that is contained in the specified range.
* Returns NULL when no element is contained in the range. */
zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range) {//返回第一个分数在range范围内的节点
zskiplistNode *x;
int i;
/* If everything is out of range, return early. */
if (!zslIsInRange(zsl,range)) return NULL; //如果不在范围内,则返回NULL,确保至少有一个节点符号range
//判断下限
x = zsl->header;//遍历跳跃表
for (i = zsl->level-1; i >= 0; i--) {//遍历每一层
/* Go forward while *OUT* of range. */
while (x->level[i].forward && //如果该层有下一个节点且
!zslValueGteMin(x->level[i].forward->score,range))//当前节点的score还小于(小于等于)range的min
x = x->level[i].forward;//继续指向下一个节点
}
/* This is an inner range, so the next node cannot be NULL. */
x = x->level[0].forward;//找到目标节点
serverAssert(x != NULL);//保证能找到
/* Check if score <= max. */
//判断上限
if (!zslValueLteMax(x->score,range)) return NULL;//该节点的分值如果比max还要大,就返回NULL
return x;
}
/* Find the last node that is contained in the specified range.
* Returns NULL when no element is contained in the range. */
zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range) {//返回最后一个分数在range范围内的节点
zskiplistNode *x;
int i;
/* If everything is out of range, return early. */
if (!zslIsInRange(zsl,range)) return NULL;//如果不在范围内,则返回NULL,确保至少有一个节点符号range
//判断上限
x = zsl->header;//遍历跳跃表
for (i = zsl->level-1; i >= 0; i--) {//遍历每一层
/* Go forward while *IN* range. */
while (x->level[i].forward &&//如果该层有下一个节点且
zslValueLteMax(x->level[i].forward->score,range))//当前节点的score小于(小于等于)max
x = x->level[i].forward;//继续指向下一个节点
}
/* This is an inner range, so this node cannot be NULL. */
serverAssert(x != NULL);//保证能找到
/* Check if score >= min. */
//判断下限
if (!zslValueGteMin(x->score,range)) return NULL;//如果找到的节点的分值比range的min还要小
return x;
}
/* Delete all the elements with score between min and max from the skiplist.
* Min and max are inclusive, so a score >= min || score <= max is deleted.
* Note that this function takes the reference to the hash table view of the
* sorted set, in order to remove the elements from the hash table too. */
//删除所有分值介于min和max之间(包括min和max)的节点,并且将字典中的对象也删除(字典和跳跃表同时表示有序集合)
unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dict) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned long removed = 0;
int i;
//找到删除节点中的最小值的节点,大于等于min的
x = zsl->header;//遍历头结点的每一层
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward && (range->minex ? //当前层的前进指针不为空
x->level[i].forward->score <= range->min : //分数小于(小于等于)min,继续前进
x->level[i].forward->score < range->min))
x = x->level[i].forward; //指向下一个节点
update[i] = x;//记录要删除的节点的前一个节点的地址
}
/* Current node is the last with score < or <= min. */
x = x->level[0].forward;//获得被删除节点的地址
/* Delete nodes while in range. */
//删除一直删到最大值的节点,该值小于等于max的
while (x &&
(range->maxex ? x->score < range->max : x->score <= range->max))//只要分值小于等于max就删除
{
zskiplistNode *next = x->level[0].forward;//备份被删除节点的下一个节点
zslDeleteNode(zsl,x,update);//删除当前的节点
dictDelete(dict,x->obj);//将字典中的对象也删除了
zslFreeNode(x);//释放空间
removed++; //计数器加1
x = next;//指向下一个节点
}
return removed;
}
//删除字典序的范围range之间的节点,并且将字典中的对象也删除
unsigned long zslDeleteRangeByLex(zskiplist *zsl, zlexrangespec *range, dict *dict) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned long removed = 0;//计数器
int i;
x = zsl->header;//遍历头结点的每一层
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward &&//当前层的前进指针不为空且
!zslLexValueGteMin(x->level[i].forward->obj,range))//obj对象字典序小于range的min
x = x->level[i].forward;//前进指向下一个节点
update[i] = x;//记录要删除的节点的前一个节点的地址
}
/* Current node is the last with score < or <= min. */
x = x->level[0].forward;//获得被删除节点的地址
/* Delete nodes while in range. */
while (x && zslLexValueLteMax(x->obj,range)) {//只要obj字典序还小于max就一直删除
zskiplistNode *next = x->level[0].forward;//备份被删除节点的下一个节点
zslDeleteNode(zsl,x,update);//删除当前的节点
dictDelete(dict,x->obj);//将字典中的对象也删除了
zslFreeNode(x);//释放空间
removed++;//计数器加1
x = next;//指向下一个节点
}
return removed;//返回被删除的节点个数
}
/* Delete all the elements with rank between start and end from the skiplist.
* Start and end are inclusive. Note that start and end need to be 1-based */
//删除跳跃表中所有给定排位内的节点
unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned long traversed = 0, removed = 0;
int i;
x = zsl->header;//遍历头结点的每一层
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward && (traversed + x->level[i].span) < start) {//还没到start起始的位置,则向前走
traversed += x->level[i].span;//更新走的跨度
x = x->level[i].forward;//指向下一个节点
}
update[i] = x;//记录要删除的节点的前一个节点的地址
}
traversed++;//因为找到的是要删除节点的前一个节点,所以traversed还要加1,此时的位置就是start的位置
x = x->level[0].forward;//前进一个节点
while (x && traversed <= end) {//从start开始删除到end
zskiplistNode *next = x->level[0].forward;//备份下一节点的地址
zslDeleteNode(zsl,x,update);//从跳跃表中删除节点
dictDelete(dict,x->obj);//从字典中删除obj对象
zslFreeNode(x);//释放空间
removed++;//被删除节点计数器加1
traversed++;//更新traversed
x = next;//指向下一个节点
}
return removed;//返回被删除的节点个数
}
/* Find the rank for an element by both score and key.
* Returns 0 when the element cannot be found, rank otherwise.
* Note that the rank is 1-based due to the span of zsl->header to the
* first element. */
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) {//查找score和o对象在跳跃表中的排位
zskiplistNode *x;
unsigned long rank = 0;
int i;
x = zsl->header;//遍历头结点的每一层
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward &&
(x->level[i].forward->score < score ||//只要分值还小于给定的score或者
(x->level[i].forward->score == score &&//分值相等但是对象小于给定对象o
compareStringObjects(x->level[i].forward->obj,o) <= 0))) {
rank += x->level[i].span;//更新排位值
x = x->level[i].forward;//指向下一个节点
}
/* x might be equal to zsl->header, so test if obj is non-NULL */
//确保在第i层找到分值相同,且对象相同时才会返回排位值
if (x->obj && equalStringObjects(x->obj,o)) {
return rank;
}
}
return 0;//没找到
}
/* Finds an element by its rank. The rank argument needs to be 1-based. */
zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) {//返回排位为rank的节点地址
zskiplistNode *x;
unsigned long traversed = 0;//排位值,跨越过的节点数
int i;
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) {//遍历头结点的每一层
while (x->level[i].forward && (traversed + x->level[i].span) <= rank)//知道traversed还没到到达rank
{
traversed += x->level[i].span;//每次跟新排位值
x = x->level[i].forward;//指向下一个节点
}
if (traversed == rank) { //跨越的节点数等于排位值,返回节点地址
return x;
}
}
return NULL;
}
/* Populate the rangespec according to the objects min and max. */
static int zslParseRange(robj *min, robj *max, zrangespec *spec) {//设置spec中的min和max值
char *eptr;
spec->minex = spec->maxex = 0;
/* Parse the min-max interval. If one of the values is prefixed
* by the "(" character, it's considered "open". For instance
* ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
* ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
//处理最小值min
if (min->encoding == OBJ_ENCODING_INT) {//如果该对象是用整数实现的
spec->min = (long)min->ptr;//设置min值
} else {//如果对象是用字符串实现的
if (((char*)min->ptr)[0] == '(') { //左开
spec->min = strtod((char*)min->ptr+1,&eptr);//将字符串转换为double类型的值,eptr用来存储不和条件的字符串地址
if (eptr[0] != '\0' || isnan(spec->min)) return C_ERR;//isnan()函数用来判断min是否是一个数字 Not A Number
spec->minex = 1;//1表示开区间,不包含
} else {
spec->min = strtod((char*)min->ptr,&eptr);
if (eptr[0] != '\0' || isnan(spec->min)) return C_ERR;//ptr中有非数字字符或min不是数字,返回REDIS_ERR(-1)
}
}
//处理最大值max
if (max->encoding == OBJ_ENCODING_INT) {//如果该对象是用整数实现的
spec->max = (long)max->ptr; //设置max值
} else {
if (((char*)max->ptr)[0] == '(') {
spec->max = strtod((char*)max->ptr+1,&eptr);//将字符串转换为double类型的值,eptr用来存储不和条件的字符串地址
if (eptr[0] != '\0' || isnan(spec->max)) return C_ERR;//ptr中有非数字字符或min不是数字,返回REDIS_ERR(-1)
spec->maxex = 1;//1表示开区间,不包含
} else {
spec->max = strtod((char*)max->ptr,&eptr);
if (eptr[0] != '\0' || isnan(spec->max)) return C_ERR;//ptr中有非数字字符或min不是数字,返回REDIS_ERR(-1)
}
}
return C_OK; //处理成功,返回0
}
/* ------------------------ Lexicographic ranges ---------------------------- */
/* Parse max or min argument of ZRANGEBYLEX.
* (foo means foo (open interval)
* [foo means foo (closed interval)
* - means the min string possible
* + means the max string possible
*
* If the string is valid the *dest pointer is set to the redis object
* that will be used for the comparision, and ex will be set to 0 or 1
* respectively if the item is exclusive or inclusive. C_OK will be
* returned.
*
* If the string is not a valid range C_ERR is returned, and the value
* of *dest and *ex is undefined. */
// 解析ZRANGEBYLEX命令的最大值和最小值参数
int zslParseLexRangeItem(robj *item, robj **dest, int *ex) {//解析字典序的对象
char *c = item->ptr;
switch(c[0]) {
case '+': //+ 意味这值最大的字符串
if (c[1] != '\0') return C_ERR;
*ex = 0;
*dest = shared.maxstring;
incrRefCount(shared.maxstring);
return C_OK;
case '-': //- 意味这值最小的字符串
if (c[1] != '\0') return C_ERR;
*ex = 0;
*dest = shared.minstring;
incrRefCount(shared.minstring);
return C_OK;
case '(': //( 意味这是左开区间
*ex = 1;
*dest = createStringObject(c+1,sdslen(c)-1);
return C_OK;
case '[': //[ 意味这左闭区间
*ex = 0;
*dest = createStringObject(c+1,sdslen(c)-1);
return C_OK;
default:
return C_ERR;
}
}
/* Populate the rangespec according to the objects min and max.
*
* Return C_OK on success. On error C_ERR is returned.
* When OK is returned the structure must be freed with zslFreeLexRange(),
* otherwise no release is needed. */
//根据最大值对象和最小值对象设置
static int zslParseLexRange(robj *min, robj *max, zlexrangespec *spec) {
/* The range can't be valid if objects are integer encoded.
* Every item must start with ( or [. */
// 最大值对象和最小值对象不能是整数编码,因为第一个字符是( or [. */
if (min->encoding == OBJ_ENCODING_INT ||
max->encoding == OBJ_ENCODING_INT) return C_ERR;
spec->min = spec->max = NULL; //初始化最大值和最小值
//解析最小值和最大值,如果任意出错则释放最小值和最大值空间,返回-1
//解析成功,则设置spec的成员
if (zslParseLexRangeItem(min, &spec->min, &spec->minex) == C_ERR ||
zslParseLexRangeItem(max, &spec->max, &spec->maxex) == C_ERR) {
if (spec->min) decrRefCount(spec->min);
if (spec->max) decrRefCount(spec->max);
return C_ERR;
} else {
return C_OK;
}
}
/* Free a lex range structure, must be called only after zelParseLexRange()
* populated the structure with success (C_OK returned). */
// 释放一个zlexrangespec结构中的对象空间
void zslFreeLexRange(zlexrangespec *spec) {
decrRefCount(spec->min);
decrRefCount(spec->max);
}
/* This is just a wrapper to compareStringObjects() that is able to
* handle shared.minstring and shared.maxstring as the equivalent of
* -inf and +inf for strings */
// 比较两个对象,能够处理shared.minstring and shared.maxstring的情况,相等返回0
int compareStringObjectsForLexRange(robj *a, robj *b) {
if (a == b) return 0; /* This makes sure that we handle inf,inf and
-inf,-inf ASAP. One special case less. */
if (a == shared.minstring || b == shared.maxstring) return -1;
if (a == shared.maxstring || b == shared.minstring) return 1;
return compareStringObjects(a,b);
}
// 比较value对象和规定的分数范围的最小值,返回1表示大于spec最小值
static int zslLexValueGteMin(robj *value, zlexrangespec *spec) {
return spec->minex ? //minex为1,则不包含
(compareStringObjectsForLexRange(value,spec->min) > 0) :
(compareStringObjectsForLexRange(value,spec->min) >= 0);
}
// 比较value对象和规定的分数范围的最大值,返回1表示小于spec最大值
static int zslLexValueLteMax(robj *value, zlexrangespec *spec) {
return spec->maxex ?
(compareStringObjectsForLexRange(value,spec->max) < 0) :
(compareStringObjectsForLexRange(value,spec->max) <= 0);
}
/* Returns if there is a part of the zset is in the lex range. */
// 返回一个zset是否有一部分在range的范围内
int zslIsInLexRange(zskiplist *zsl, zlexrangespec *range) {
zskiplistNode *x;
/* Test for ranges that will always be empty. */
// 测试range的范围是否合法
if (compareStringObjectsForLexRange(range->min,range->max) > 1 ||
(compareStringObjects(range->min,range->max) == 0 &&
(range->minex || range->maxex)))
return 0;
x = zsl->tail;
// !查看跳跃表的尾节点的对象是否比range的最小值还大,
if (x == NULL || !zslLexValueGteMin(x->obj,range))
return 0; //表示zset没有一部分在range范围
x = zsl->header->level[0].forward;
// !查看跳跃表的头节点的对象是否比range的最大值还小,
if (x == NULL || !zslLexValueLteMax(x->obj,range))
return 0; //表示zset没有一部分在range范围
return 1;
}
/* Find the first node that is contained in the specified lex range.
* Returns NULL when no element is contained in the range. */
// 返回第一个包含在range范围内的节点的地址
zskiplistNode *zslFirstInLexRange(zskiplist *zsl, zlexrangespec *range) {
zskiplistNode *x;
int i;
/* If everything is out of range, return early. */
// zsl是否有一部分包含在range内,没有则返回NULL
if (!zslIsInLexRange(zsl,range)) return NULL;
x = zsl->header;//遍历每一层
for (i = zsl->level-1; i >= 0; i--) {
/* Go forward while *OUT* of range. */
// 一直前进寻找,当某一个节点比range的最小值大时,停止寻找
while (x->level[i].forward &&
!zslLexValueGteMin(x->level[i].forward->obj,range))
x = x->level[i].forward;
}
/* This is an inner range, so the next node cannot be NULL. */
// 保存当前节点地址
x = x->level[0].forward;
serverAssert(x != NULL);
/* Check if score <= max. */
// 检查当前节点是否超过最大值,超过则返回NULL
if (!zslLexValueLteMax(x->obj,range)) return NULL;
return x;
}
/* Find the last node that is contained in the specified range.
* Returns NULL when no element is contained in the range. */
// 返回最后一个包含在range范围内的节点的地址
zskiplistNode *zslLastInLexRange(zskiplist *zsl, zlexrangespec *range) {
zskiplistNode *x;
int i;
/* If everything is out of range, return early. */
// zsl是否有一部分包含在range内,没有则返回NULL
if (!zslIsInLexRange(zsl,range)) return NULL;
x = zsl->header;//遍历每一层
for (i = zsl->level-1; i >= 0; i--) {
/* Go forward while *IN* range. */
// 一直前进寻找,当某一个节点比range的最大值大时,停止寻找
while (x->level[i].forward &&
zslLexValueLteMax(x->level[i].forward->obj,range))
x = x->level[i].forward;
}
/* This is an inner range, so this node cannot be NULL. */
serverAssert(x != NULL);
/* Check if score >= min. */
// 检查当前节点是否小于最小值,小于则返回NULL
if (!zslLexValueGteMin(x->obj,range)) return NULL;
return x;
}
/*-----------------------------------------------------------------------------
* Ziplist-backed sorted set API
* 压缩列表实现的有序列表API
*----------------------------------------------------------------------------*/
// 从sptr指向的entry中取出有序集合的分值
double zzlGetScore(unsigned char *sptr) {
unsigned char *vstr;
unsigned int vlen;
long long vlong;
char buf[128];
double score;
serverAssert(sptr != NULL);
// 将sptr指向的entry保存到参数中
serverAssert(ziplistGet(sptr,&vstr,&vlen,&vlong));
// 如果是字符串类型的值
if (vstr) {
// 拷贝到buf中
memcpy(buf,vstr,vlen);
buf[vlen] = '\0';
// 转换成double类型
score = strtod(buf,NULL);
// 整数值
} else {
score = vlong;
}
return score; //返回分值
}
/* Return a ziplist element as a Redis string object.
* This simple abstraction can be used to simplifies some code at the
* cost of some performance. */
// 返回一个sptr指向entry所构建的字符串类型的对象地址
robj *ziplistGetObject(unsigned char *sptr) {
unsigned char *vstr;
unsigned int vlen;
long long vlong;
serverAssert(sptr != NULL);
// 将sptr指向的entry保存到参数中
serverAssert(ziplistGet(sptr,&vstr,&vlen,&vlong));
// 根据不同类型的值,创建返回字符串对象
if (vstr) {
return createStringObject((char*)vstr,vlen);
} else {
return createStringObjectFromLongLong(vlong);
}
}
/* Compare element in sorted set with given element. */
// 比较eptr和cstr指向的元素,返回0表示相等,正整数表示eptr比cstr大
int zzlCompareElements(unsigned char *eptr, unsigned char *cstr, unsigned int clen) {
unsigned char *vstr;
unsigned int vlen;
long long vlong;
unsigned char vbuf[32];
int minlen, cmp;
// 将eptr指向的entry保存到参数中
serverAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
// 如果是整数值
if (vstr == NULL) {
/* Store string representation of long long in buf. */
// 将整数值转换为字符串,保存在vbuf中
vlen = ll2string((char*)vbuf,sizeof(vbuf),vlong);
vstr = vbuf;
}
// 比较最小长度
minlen = (vlen < clen) ? vlen : clen;
// 比较
cmp = memcmp(vstr,cstr,minlen);
if (cmp == 0) return vlen-clen; //minlen长度的子串相等,返回长度差值
return cmp; //返回结果
}
// 返回有序集合的元素个数
unsigned int zzlLength(unsigned char *zl) {
return ziplistLen(zl)/2;
}
/* Move to next entry based on the values in eptr and sptr. Both are set to
* NULL when there is no next entry. */
// 将当前的元素指针eptr和当前元素分值的指针sptr都指向下一个元素和元素的分值
void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
unsigned char *_eptr, *_sptr;
serverAssert(*eptr != NULL && *sptr != NULL);
// 下一个元素的地址为当前元素分值的下一个entry
_eptr = ziplistNext(zl,*sptr);
// 下一个entry不为空
if (_eptr != NULL) {
// 下一个元素分值的地址为下一个元素的下一个entry
_sptr = ziplistNext(zl,_eptr);
serverAssert(_sptr != NULL);
} else {
/* No next entry. */
_sptr = NULL;
}
//保存到参数中返回
*eptr = _eptr;
*sptr = _sptr;
}
/* Move to the previous entry based on the values in eptr and sptr. Both are
* set to NULL when there is no next entry. */
// 将当前的元素指针eptr和当前元素分值的指针sptr都指向上一个元素和元素的分值
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
unsigned char *_eptr, *_sptr;
serverAssert(*eptr != NULL && *sptr != NULL);
// 上一个元素分值的地址为当前一个元素的上一个entry
_sptr = ziplistPrev(zl,*eptr);
// 上一个entry不为空
if (_sptr != NULL) {
// 上一个元素的地址为上一个元素分值的上一个entry
_eptr = ziplistPrev(zl,_sptr);
serverAssert(_eptr != NULL);
} else {
/* No previous entry. */
_eptr = NULL;
}
// 保存到参数中返回
*eptr = _eptr;
*sptr = _sptr;
}
/* Returns if there is a part of the zset is in range. Should only be used
* internally by zzlFirstInRange and zzlLastInRange. */
// 判断ziplist中是否有entry节点在range范围之内,有一个则返回1,否则返回0
int zzlIsInRange(unsigned char *zl, zrangespec *range) {
unsigned char *p;
double score;
/* Test for ranges that will always be empty. */
// 测试range是否合法
if (range->min > range->max ||
(range->min == range->max && (range->minex || range->maxex)))
return 0;
// 保存ziplist总最后一个entry节点的地址,保存着有序集合的最大分值
p = ziplistIndex(zl,-1); /* Last score. */
if (p == NULL) return 0; /* Empty sorted set */
// 取出有序集合的最大分值
score = zzlGetScore(p);
// 如果最大分值比range的最小最小,返回0
if (!zslValueGteMin(score,range))
return 0;
// 保存ziplist总第一个entry节点的地址,保存着有序集合的最小分值
p = ziplistIndex(zl,1); /* First score. */
serverAssert(p != NULL);
// 取出有序集合的最小分值
score = zzlGetScore(p);
// 如果最小分值比range的最大最大,返回0
if (!zslValueLteMax(score,range))
return 0;
// ziplist中是至少有一个entry节点在range范围之内
return 1;
}
/* Find pointer to the first element contained in the specified range.
* Returns NULL when no element is contained in the range. */
// 返回第一个满足range范围的entry节点的地址
unsigned char *zzlFirstInRange(unsigned char *zl, zrangespec *range) {
unsigned char *eptr = ziplistIndex(zl,0), *sptr; //保存首元素的地址,从前往后遍历
double score;
/* If everything is out of range, return early. */
// 先判断是否至少有一个entry符合range,没有返回NULL
if (!zzlIsInRange(zl,range)) return NULL;
// 遍历ziplist的所有entry
while (eptr != NULL) {
// 保存当前元素分值的entry地址
sptr = ziplistNext(zl,eptr);
serverAssert(sptr != NULL);
// 取出当前元素的分值
score = zzlGetScore(sptr);
// 如果分值大于range的最小值
if (zslValueGteMin(score,range)) {
/* Check if score <= max. */
// 分值还小于range的最大值
if (zslValueLteMax(score,range))
// 返回当前节点的地址
return eptr;
return NULL;
}
/* Move to next element. */
// 指向下一个节点
eptr = ziplistNext(zl,sptr);
}
return NULL;
}
/* Find pointer to the last element contained in the specified range.
* Returns NULL when no element is contained in the range. */
// 返回最后一个满足range范围的entry节点的地址
unsigned char *zzlLastInRange(unsigned char *zl, zrangespec *range) {
unsigned char *eptr = ziplistIndex(zl,-2), *sptr;//保存尾元素的地址,从后往前遍历
double score;
/* If everything is out of range, return early. */
// 先判断是否至少有一个entry符合range,没有返回NULL
if (!zzlIsInRange(zl,range)) return NULL;
// 遍历ziplist的所有entry
while (eptr != NULL) {
// 保存当前元素分值的entry地址
sptr = ziplistNext(zl,eptr);
serverAssert(sptr != NULL);
// 取出当前元素的分值
score = zzlGetScore(sptr);
// 如果分值小于range的最大值
if (zslValueLteMax(score,range)) {
/* Check if score >= min. */
// 分值还大于range的最小值
if (zslValueGteMin(score,range))
// 返回当前节点的地址
return eptr;
return NULL;
}
/* Move to previous element by moving to the score of previous element.
* When this returns NULL, we know there also is no element. */
// 指向前一个元素和元素的分值
sptr = ziplistPrev(zl,eptr);
if (sptr != NULL)
serverAssert((eptr = ziplistPrev(zl,sptr)) != NULL);
else
eptr = NULL;
}
return NULL;
}
// 比较p指向的entry的值和规定范围spec,返回1表示大于spec的最大值
static int zzlLexValueGteMin(unsigned char *p, zlexrangespec *spec) {
robj *value = ziplistGetObject(p); //将entry节点构建成一个ziplist对象
int res = zslLexValueGteMin(value,spec); //比较
decrRefCount(value);
return res;
}
// 比较p指向的entry的值和规定范围spec,返回1表示小于spec的最小值
static int zzlLexValueLteMax(unsigned char *p, zlexrangespec *spec) {
robj *value = ziplistGetObject(p); //将entry节点构建成一个ziplist对象
int res = zslLexValueLteMax(value,spec); //比较
decrRefCount(value);
return res;
}
/* Returns if there is a part of the zset is in range. Should only be used
* internally by zzlFirstInRange and zzlLastInRange. */
// 判断ziplist中是否有entry节点在range范围之内,有一个则返回1,否则返回0
int zzlIsInLexRange(unsigned char *zl, zlexrangespec *range) {
unsigned char *p;
/* Test for ranges that will always be empty. */
// 测试字典序范围是否合法
if (compareStringObjectsForLexRange(range->min,range->max) > 1 ||
(compareStringObjects(range->min,range->max) == 0 &&
(range->minex || range->maxex)))
return 0;
// 最后一个元素的地址
p = ziplistIndex(zl,-2); /* Last element. */
if (p == NULL) return 0;
// 小于range的最小值,返回0
if (!zzlLexValueGteMin(p,range))
return 0;
// 第一个元素地址
p = ziplistIndex(zl,0); /* First element. */
serverAssert(p != NULL);
// 大于range的最大值,返回0
if (!zzlLexValueLteMax(p,range))
return 0;
return 1;
}
/* Find pointer to the first element contained in the specified lex range.
* Returns NULL when no element is contained in the range. */
// 返回第一个满足range范围的元素的地址
unsigned char *zzlFirstInLexRange(unsigned char *zl, zlexrangespec *range) {
unsigned char *eptr = ziplistIndex(zl,0), *sptr; //第一个元素节点地址,从前往后遍历
/* If everything is out of range, return early. */
// 判断ziplist中是否有entry节点在range范围之内,有一个则返回1,否则返回0
if (!zzlIsInLexRange(zl,range)) return NULL;
// 遍历所有元素节点
while (eptr != NULL) {
// 大于最小值且小于最大值,返回当前节点地址
if (zzlLexValueGteMin(eptr,range)) {
/* Check if score <= max. */
if (zzlLexValueLteMax(eptr,range))
return eptr;
return NULL;
}