redis6.0.5之Rax阅读笔记4-Iterator(迭代器)

  1 /* Optional callback used for iterators and be notified on each rax node,
  2  * including nodes not representing keys. If the callback returns true
  3  * the callback changed the node pointer in the iterator structure, and the
  4  * iterator implementation will have to replace the pointer in the radix tree
  5  * internals. This allows the callback to reallocate the node to perform
  6  * very special operations, normally not needed by normal applications.
  7 这个函数是迭代器可选的回调函数,每个基树的节点都会被通知到,包括哪些不是键的节点。
  8 回调返回真,如果回调改变了迭代器结构中额节点指针。迭代器的实现将替换基树内部的指针。
  9 这个就允许回调函数可以重新分配节点内存执行一个特殊的操作,正常情况下不需要。
 10  * This callback is used to perform very low level analysis of the radix tree
 11  * structure, scanning each possible node (but the root node), or in order to
 12  * reallocate the nodes to reduce the allocation fragmentation (this is the
 13  * Redis application for this callback).
 14 这个回调函数用来执行基树结构的底层分析,扫描每个可能的节点(除了根节点),
 15 或者为了重新分配节点内存从而减少分配的内存碎片(这个就是回调在redis的应用)
 16  * This is currently only supported in forward iterations (raxNext) */
 17 这个函数目前只支持向前的迭代
 18 typedef int (*raxNodeCallback)(raxNode **noderef);
 19 
 20 /* Radix tree iterator state is encapsulated into this data structure. */
 21 基树迭代状态都封装在下面这个数据结构中
 22 #define RAX_ITER_STATIC_LEN 128
 23 #define RAX_ITER_JUST_SEEKED (1<<0) /* Iterator was just seeked. Return current
 24                                        element for the first iteration and
 25                                        clear the flag. */
 26 迭代器被找到,返回当前的第一次迭代当前元素,同时清除标志                                    
 27 #define RAX_ITER_EOF (1<<1)    /* End of iteration reached. */   达到迭代结束
 28 #define RAX_ITER_SAFE (1<<2)   /* Safe iterator, allows operations while
 29                                   iterating. But it is slower. */
 30 安全迭代器,迭代的时候允许操作,但是这个比较慢(这个版本的代码没有看到怎么用)
 31 typedef struct raxIterator {
 32     int flags;
 33     rax *rt;                /* Radix tree we are iterating. */  迭代的基树
 34     unsigned char *key;     /* The current string. */  当前字符串
 35     void *data;             /* Data associated to this key. */   键对应的值
 36     size_t key_len;         /* Current key length. */ 当前长度
 37     size_t key_max;         /* Max key len the current key buffer can hold. */  当前最大的可以缓存键的长度
 38     unsigned char key_static_string[RAX_ITER_STATIC_LEN];  初始化数组
 39     raxNode *node;          /* Current node. Only for unsafe iteration. */  当前节点,只针对不安全迭代
 40     raxStack stack;         /* Stack used for unsafe iteration. */  非安全迭代使用的栈
 41     raxNodeCallback node_cb; /* Optional node callback. Normally set to NULL. */ 可选节点回调函数。正常设置为空
 42 } raxIterator;
 43 
 44 **************************************************************************
 45 /* Initialize a Rax iterator. This call should be performed a single time
 46  * to initialize the iterator, and must be followed by a raxSeek() call,
 47  * otherwise the raxPrev()/raxNext() functions will just return EOF. */
 48 初始化一个rax迭代器。本调用只能在初始化的时候执行一次,而且必须随后调用函数raxSeek(),
 49 否则函数raxPrev()/raxNext()会返回EOF
 50 void raxStart(raxIterator *it, rax *rt) {
 51     it->flags = RAX_ITER_EOF; /* No crash if the iterator is not seeked. */
 52     不至于奔溃如果迭代器没有找到
 53     it->rt = rt;  基树
 54     it->key_len = 0;  
 55     it->key = it->key_static_string;
 56     it->key_max = RAX_ITER_STATIC_LEN; 
 57     it->data = NULL;
 58     it->node_cb = NULL;
 59     raxStackInit(&it->stack);
 60 }
 61 **************************************************************************
 62 /* Append characters at the current key string of the iterator 'it'. This
 63  * is a low level function used to implement the iterator, not callable by
 64  * the user. Returns 0 on out of memory, otherwise 1 is returned. */
 65 在当前迭代器it的键字符串添加字符。这是一个底层的函数用来实现迭代器,
 66 不是由使用者调用(潜在意思就是内部调用,不对外暴露)。
 67 返回0如果OOM,其它情况返回1
 68 int raxIteratorAddChars(raxIterator *it, unsigned char *s, size_t len) {
 69     if (it->key_max < it->key_len+len) { 
 70     如果当前可以容量最大的字符串长度小于当前已存字符串长度和将要添加的字符串长度之和,
 71     意味着需要开辟新的大空间,即扩容
 72         unsigned char *old = (it->key == it->key_static_string) ? NULL :
 73                                                                   it->key;
 74 判断使用的是否是初始化的初始化空间,是说明原来没有在堆上新分配过空间(可以新分配空间),
 75 否则就是分配过(需要在这个基础上扩张)                                                                  
 76         size_t new_max = (it->key_len+len)*2;  空间大小翻倍
 77         it->key = rax_realloc(old,new_max);
 78         if (it->key == NULL) {   内存分配失败
 79             it->key = (!old) ? it->key_static_string : old;
 80             old为空说明原来用的是初始化字符串,不为空就是分配过的堆空间
 81             errno = ENOMEM;
 82             return 0;
 83         }
 84         如果能到这里,表示内存分配成功
 85         if (old == NULL) memcpy(it->key,it->key_static_string,it->key_len);
 86         old为空的情况下。从初始化字符串数组拷贝原来数据到新分配的空间
 87         it->key_max = new_max; 更新最大容量
 88     }
 89     /* Use memmove since there could be an overlap between 's' and
 90      * it->key when we use the current key in order to re-seek. */
 91     在内存充足的情况下,使用函数memmove进行字符串拷贝。
 92     因为在使用当前键在重新查找时,字符串s和it->key之间可能存在重叠
 93     memmove(it->key+it->key_len,s,len);
 94     it->key_len += len; 键长度增加len
 95     return 1;
 96 }
 97 **************************************************************************
 98 /* Remove the specified number of chars from the right of the current
 99  * iterator key. */
100 从当前迭代器键的右边移除特定数字的字符
101 void raxIteratorDelChars(raxIterator *it, size_t count) {
102     it->key_len -= count; 只是减去键长度,后面的字符还是存在的
103 }
104 **************************************************************************
105 /* Do an iteration step towards the next element. At the end of the step the
106  * iterator key will represent the (new) current key. If it is not possible
107  * to step in the specified direction since there are no longer elements, the
108  * iterator is flagged with RAX_ITER_EOF.
109 做一个向前迭代步骤到下一个元素。在这个步骤的结尾,迭代器的键将表示当前键(即新找到的键)
110 如果在特定方向不能向前进,因为那里没有元素了,迭代器被标记为RAX_ITER_EOF
111  * If 'noup' is true the function starts directly scanning for the next
112  * lexicographically smaller children, and the current node is already assumed
113  * to be the parent of the last key node, so the first operation to go back to
114  * the parent will be skipped. This option is used by raxSeek() when
115  * implementing seeking a non existing element with the ">" or "<" options:
116  * the starting node is not a key in that particular case, so we start the scan
117  * from a node that does not represent the key set.
118 如果noup的值为真,那么这个函数从下一个字典序较小的子节点开始扫描,
119 当前节点被假设为最后一个一个键节点的父节点,所以第一步操作回溯到父节点课可以跳过。
120 这个选项被函数raxSeek在实现使用>或者<符号查找不存在元素的时候:在这个特殊情况下,
121 开始节点不是一个键,所以我们从一个不属于键表示的集合开始扫描
122  * The function returns 1 on success or 0 on out of memory. */
123 本函数正常返回1如果出现OOM返回0
124 int raxIteratorNextStep(raxIterator *it, int noup) {
125     if (it->flags & RAX_ITER_EOF) { 如果标志是RAX_ITER_EOF,结束迭代
126         return 1;
127     } else if (it->flags & RAX_ITER_JUST_SEEKED) {  
128     如果标志是RAX_ITER_JUST_SEEKED,清除标志,返回
129         it->flags &= ~RAX_ITER_JUST_SEEKED;
130         return 1;
131     }
132     /* Save key len, stack items and the node where we are currently
133      * so that on iterator EOF we can restore the current key and state. */
134     保存当前的键的长度,栈元素和节点。
135     这样在迭代结束的时候我们可以恢复当前的节点和状态
136     size_t orig_key_len = it->key_len;
137     size_t orig_stack_items = it->stack.items;
138     raxNode *orig_node = it->node;
139 
140     while(1) {
141         int children = it->node->iscompr ? 1 : it->node->size; 子节点个数
142         if (!noup && children) {  
143         noup为真的意思就是不向上回溯,只查当前节点下面的子树,!noup表示可以向上回溯
144             debugf("GO DEEPER\n");
145             /* Seek the lexicographically smaller key in this subtree, which
146              * is the first one found always going torwards the first child
147              * of every successive node. */
148 在子树中查找字典序较小的键,对这些连续的节点来说,第一个被找到的总是每个节点的第一个孩子
149             if (!raxStackPush(&it->stack,it->node)) return 0;  压栈
150             raxNode **cp = raxNodeFirstChildPtr(it->node); 
151             第一个子节点(因为第一个子节点字典序上最小,遍历从小到大)
152             if (!raxIteratorAddChars(it,it->node->data,
153                 it->node->iscompr ? it->node->size : 1)) return 0; 拼接迭代器字符串
154                 
155             memcpy(&it->node,cp,sizeof(it->node));  迭代子节点,供循环使用
156             
157             /* Call the node callback if any, and replace the node pointer
158              * if the callback returns true. */
159 如果存在回调函数,调用节点的回调函数,替换节点的指针如果回调函数返回为真
160             if (it->node_cb && it->node_cb(&it->node))
161                 memcpy(cp,&it->node,sizeof(it->node));
162                 
163             /* For "next" step, stop every time we find a key along the
164              * way, since the key is lexicograhically smaller compared to
165              * what follows in the sub-children. */
166              对下一步,我们每次都停在沿着这条上的一个键节点,
167              因为这个键在词典序上小于接下来的子节点上的键
168              (意思就是我们是按照字典序从小到大进行遍历的,后面发现的键都大于这个键,)
169             if (it->node->iskey) {
170                 it->data = raxGetData(it->node);  获取当前这个键的值,返回
171                 return 1;
172             }
173         } else {
174             /* If we finished exporing the previous sub-tree, switch to the
175              * new one: go upper until a node is found where there are
176              * children representing keys lexicographically greater than the
177              * current key. */
178              如果我们结束了遍历当前的子树,切换到一个新的子树,一直向上回溯直到找到
179              一个子节点表示的键,字典序上大于当前的键
180             while(1) {
181                 int old_noup = noup;
182 
183                 /* Already on head? Can't go up, iteration finished. */
184                 已经到达头节点,不能再向上,迭代结束
185                 if (!noup && it->node == it->rt->head) {  已经到头节点
186                     it->flags |= RAX_ITER_EOF;  设置结束标志
187                     it->stack.items = orig_stack_items;  恢复初始状态
188                     it->key_len = orig_key_len;
189                     it->node = orig_node;
190                     return 1;
191                 }
192                 /* If there are no children at the current node, try parent's
193                  * next child. */
194                  如果当前节点没有子节点,尝试父节点的另外一个子节点
195                 unsigned char prevchild = it->key[it->key_len-1];
196                 if (!noup) {
197                     it->node = raxStackPop(&it->stack);  
198                     这里的作用是没有找到的情况下,一直往上退,直到头节点
199                 } else {
200                     noup = 0;
201                 }
202                 /* Adjust the current key to represent the node we are
203                  * at. */
204                  调整当前键来表示我们的所在的节点
205                 int todel = it->node->iscompr ? it->node->size : 1;
206                 raxIteratorDelChars(it,todel);  退掉相应的字符个数
207 
208                 /* Try visiting the next child if there was at least one
209                  * additional child. */
210                  尝试遍历下一个子节点,如果至少还存在额外一个子节点
211                 if (!it->node->iscompr && it->node->size > (old_noup ? 0 : 1)) {
212                 非压缩节点  多余一个子节点点或者在不向上回溯的情况下跳过父节点这一步骤
213                     raxNode **cp = raxNodeFirstChildPtr(it->node);
214                     int i = 0;
215                     while (i < it->node->size) { 查找比之前的子节点字典序上大的第一个子节点
216                         debugf("SCAN NEXT %c\n", it->node->data[i]);
217                         if (it->node->data[i] > prevchild) break;
218                         i++;  下一个字符
219                         cp++; 下一个节点
220                     }
221                     if (i != it->node->size) {  
222                     不等于,意味着提前退出,即找到了所要求的的字符,否则就会循环到结尾位置
223                         debugf("SCAN found a new node\n");
224                         raxIteratorAddChars(it,it->node->data+i,1); 拼接新的字符串
225                         if (!raxStackPush(&it->stack,it->node)) return 0; 重新压栈
226                         
227                         memcpy(&it->node,cp,sizeof(it->node)); 将找到的节点赋值给当前节点
228                         
229                         /* Call the node callback if any, and replace the node
230                          * pointer if the callback returns true. */
231                 如果存在回调函数,调用节点的回调函数,替换节点的指针如果回调函数返回为真
232                         if (it->node_cb && it->node_cb(&it->node))
233                             memcpy(cp,&it->node,sizeof(it->node));
234                             
235                         if (it->node->iskey) { 如果是一个键
236                             it->data = raxGetData(it->node); 获取这个键的值,返回
237                             return 1;
238                         }
239                         break;
240                     }
241                 }
242             }
243         }
244     }
245 }
246 **************************************************************************
247 /* Like raxIteratorNextStep() but implements an iteration step moving
248  * to the lexicographically previous element. The 'noup' option has a similar
249  * effect to the one of raxIteratorNextStep(). */
250 类似函数raxIteratorNextStep,实现了一个字典序上回退的迭代器。
251 这个noup标志的作用类似函数raxIteratorNextStep中的那个(noup).
252 我们这里只注释不同于函数raxIteratorNextStep部分
253 int raxIteratorPrevStep(raxIterator *it, int noup) {
254     if (it->flags & RAX_ITER_EOF) {
255         return 1;
256     } else if (it->flags & RAX_ITER_JUST_SEEKED) {
257         it->flags &= ~RAX_ITER_JUST_SEEKED;
258         return 1;
259     }
260 
261     /* Save key len, stack items and the node where we are currently
262      * so that on iterator EOF we can restore the current key and state. */
263     size_t orig_key_len = it->key_len;
264     size_t orig_stack_items = it->stack.items;
265     raxNode *orig_node = it->node;
266 
267     while(1) {
268         int old_noup = noup;
269 
270         /* Already on head? Can't go up, iteration finished. */
271         if (!noup && it->node == it->rt->head) {
272             it->flags |= RAX_ITER_EOF;
273             it->stack.items = orig_stack_items;
274             it->key_len = orig_key_len;
275             it->node = orig_node;
276             return 1;
277         }
278 
279         unsigned char prevchild = it->key[it->key_len-1];
280         if (!noup) {
281             it->node = raxStackPop(&it->stack);
282         } else {
283             noup = 0;
284         }
285 
286         /* Adjust the current key to represent the node we are
287          * at. */
288         int todel = it->node->iscompr ? it->node->size : 1;
289         raxIteratorDelChars(it,todel);
290 
291         /* Try visiting the prev child if there is at least one
292          * child. */
293         if (!it->node->iscompr && it->node->size > (old_noup ? 0 : 1)) {
294         这里的作用是从后往前查找,第一个小于当前节点的子节点
295             raxNode **cp = raxNodeLastChildPtr(it->node);
296             int i = it->node->size-1;
297             while (i >= 0) {  从后往前
298                 debugf("SCAN PREV %c\n", it->node->data[i]);
299                 if (it->node->data[i] < prevchild) break;  小于当前子节点
300                 i--;
301                 cp--;
302             }
303             /* If we found a new subtree to explore in this node,
304              * go deeper following all the last children in order to
305              * find the key lexicographically greater. */
306              如果我们在这个节点发现了一棵新子树,在子树最深处找到字典序最大的那个键值
307             if (i != -1) { 不等于-1表示找到了一个满足条件的节点
308                 debugf("SCAN found a new node\n");
309                 /* Enter the node we just found. */
310                 if (!raxIteratorAddChars(it,it->node->data+i,1)) return 0; 拼接找到节点的字符串
311                 if (!raxStackPush(&it->stack,it->node)) return 0;
312                 memcpy(&it->node,cp,sizeof(it->node));
313                 /* Seek sub-tree max. */
314                 if (!raxSeekGreatest(it)) return 0;  找当前节点下面字典序上最大的键
315             }
316         }
317 
318         /* Return the key: this could be the key we found scanning a new
319          * subtree, or if we did not find a new subtree to explore here,
320          * before giving up with this node, check if it's a key itself. */
321          返回找到的键:这个值可能是我们从新的子树扫描找到的
322          或者我们没有找到一棵新子树,在要离开这个节点前,判断这个节点本身是否是一个键
323         if (it->node->iskey) {
324             it->data = raxGetData(it->node);
325             return 1;
326         }
327     }
328 }
329 **************************************************************************
330 /* Seek an iterator at the specified element.
331  * Return 0 if the seek failed for syntax error or out of memory. Otherwise
332  * 1 is returned. When 0 is returned for out of memory, errno is set to
333  * the ENOMEM value. */
334 在特定元素查找迭代器,返回0如果因为格式原因或者OOM查找失败。
335 其它情况下返回1.因为OOM返回0的时候,errno的值被设置
336 int raxSeek(raxIterator *it, const char *op, unsigned char *ele, size_t len) {
337     int eq = 0, lt = 0, gt = 0, first = 0, last = 0;
338     初始化参数
339     it->stack.items = 0; /* Just resetting. Intialized by raxStart(). */
340     it->flags |= RAX_ITER_JUST_SEEKED;
341     it->flags &= ~RAX_ITER_EOF;
342     it->key_len = 0;
343     it->node = NULL;
344 
345     /* Set flags according to the operator used to perform the seek. */
346     根据查找符号设置标志去执行查找
347     if (op[0] == '>') {
348         gt = 1;  大于
349         if (op[1] == '=') eq = 1;  等于
350     } else if (op[0] == '<') {
351         lt = 1;  小于
352         if (op[1] == '=') eq = 1; 等于
353     } else if (op[0] == '=') {
354         eq = 1; 等于
355     } else if (op[0] == '^') {
356         first = 1; 从头开始
357     } else if (op[0] == '$') {
358         last = 1;  从尾部开始
359     } else {
360         errno = 0;  不认识的查找格式
361         return 0; /* Error. */
362     }
363 
364     /* If there are no elements, set the EOF condition immediately and
365      * return. */
366 树中没有元素,直接设置结束条件同时返回
367     if (it->rt->numele == 0) {
368         it->flags |= RAX_ITER_EOF;
369         return 1;
370     }
371 
372     if (first) { 将从头开始转化为大于等于空元素
373         /* Seeking the first key greater or equal to the empty string
374          * is equivalent to seeking the smaller key available. */
375          查找第一个大于等于空字符串的键,等同于查找能找到的满足条件的最小的键
376         return raxSeek(it,">=",NULL,0);
377     }
378 
379     if (last) { 如果是从尾巴开始查找
380         /* Find the greatest key taking always the last child till a
381          * final node is found. */
382          最大的键总是在每个节点的最后子节点这个分支上。查找直到没有最后一个节点为止
383         it->node = it->rt->head;
384         if (!raxSeekGreatest(it)) return 0; 从树的头节点开始查找,找出最大的键
385         assert(it->node->iskey);
386         it->data = raxGetData(it->node);  
387         return 1;
388     }
389 
390     /* We need to seek the specified key. What we do here is to actually
391      * perform a lookup, and later invoke the prev/next key code that
392      * we already use for iteration. */
393     int splitpos = 0;
394     size_t i = raxLowWalk(it->rt,ele,len,&it->node,NULL,&splitpos,&it->stack);
395     查找树中是否存在这样的节点
396 
397     /* Return OOM on incomplete stack info. */
398     if (it->stack.oom) return 0;
399 
400     if (eq && i == len && (!it->node->iscompr || splitpos == 0) &&
401         it->node->iskey)
402     {符号中有等号 非压缩节点或者压缩节点但是不在中间 并且是一个键
403      那么我们就根据要求找到了这个节点
404         /* We found our node, since the key matches and we have an
405          * "equal" condition. */
406         if (!raxIteratorAddChars(it,ele,len)) return 0; /* OOM. */  
407         添加查找字符串就可以返回了
408         it->data = raxGetData(it->node);
409     } else if (lt || gt) {
410         /* Exact key not found or eq flag not set. We have to set as current
411          * key the one represented by the node we stopped at, and perform
412          * a next/prev operation to seek. To reconstruct the key at this node
413          * we start from the parent and go to the current node, accumulating
414          * the characters found along the way. */
415 精准的键没有找到或者等号没有设置,我们必须设置停下的节点作为当前的节点,
416 然后执行前进或者后退操作去寻找。为了重建这个节点的键,我们需要从父节点开始知道当前节点,
417 累积这路上遇到的所有字符
418         if (!raxStackPush(&it->stack,it->node)) return 0; 
419         for (size_t j = 1; j < it->stack.items; j++) { 从头开始拼接字符串
420             raxNode *parent = it->stack.stack[j-1];
421             raxNode *child = it->stack.stack[j];
422             if (parent->iscompr) { 压缩节点
423                 if (!raxIteratorAddChars(it,parent->data,parent->size))
424                     return 0;
425             } else { 非压缩节点
426                 raxNode **cp = raxNodeFirstChildPtr(parent);
427                 unsigned char *p = parent->data;
428                 while(1) {
429                     raxNode *aux;
430                     memcpy(&aux,cp,sizeof(aux));
431                     if (aux == child) break; 找到对应的子节点位置
432                     cp++; 节点指针加1
433                     p++;字符指针加1
434                 }
435                 if (!raxIteratorAddChars(it,p,1)) return 0; 
436                 添加这个节点的字符到迭代器键中
437             }
438         }
439         raxStackPop(&it->stack);
440 
441         /* We need to set the iterator in the correct state to call next/prev
442          * step in order to seek the desired element. */
443     我们需要设置迭代器在正确的状态,从而调用向前/向后操作查找目标元素
444         debugf("After initial seek: i=%d len=%d key=%.*s\n",
445             (int)i, (int)len, (int)it->key_len, it->key);
446         if (i != len && !it->node->iscompr) {  没有精确匹配 并且 非压缩节点
447             /* If we stopped in the middle of a normal node because of a
448              * mismatch, add the mismatching character to the current key
449              * and call the iterator with the 'noup' flag so that it will try
450              * to seek the next/prev child in the current node directly based
451              * on the mismatching character. */
452 我们停留在了一个正常节点的中间,添加不匹配字符到当前的节点,
453 并且调用带有noup标志的迭代器,这样就可以基于不匹配字符在当前节点尝试查找next/prev子节点。
454             if (!raxIteratorAddChars(it,ele+i,1)) return 0; 
455             先将当前节点的字符添加到迭代器的键中
456             debugf("Seek normal node on mismatch: %.*s\n",
457                 (int)it->key_len, (char*)it->key);
458 
459             it->flags &= ~RAX_ITER_JUST_SEEKED;
460             if (lt && !raxIteratorPrevStep(it,1)) return 0; 如果是小于,那么后退一步
461             if (gt && !raxIteratorNextStep(it,1)) return 0; 如果是大于,那么前进一步
462             it->flags |= RAX_ITER_JUST_SEEKED; /* Ignore next call. */
463         } else if (i != len && it->node->iscompr) {
464         停留在了一个压缩节点的中间
465             debugf("Compressed mismatch: %.*s\n",
466                 (int)it->key_len, (char*)it->key);
467             /* In case of a mismatch within a compressed node. */    
468             int nodechar = it->node->data[splitpos];
469             int keychar = ele[i];
470             it->flags &= ~RAX_ITER_JUST_SEEKED;
471             if (gt) {
472                 /* If the key the compressed node represents is greater
473                  * than our seek element, continue forward, otherwise set the
474                  * state in order to go back to the next sub-tree. */
475                  如果压缩节点表示的键大于我们要查找的键,继续向前一步。
476                  否则设置迭代器的状态回溯接下来的子树。
477                 if (nodechar > keychar) {
478                   那么下一个遇到的节点就是我们所需要的
479                     if (!raxIteratorNextStep(it,0)) return 0;
480                 } else {
481                     if (!raxIteratorAddChars(it,it->node->data,it->node->size))     return 0;
482                     因为在下面的步骤中有一个删除上述拼接字符串的操作
483                     (在函数raxIteratorNextStep(it,1))有如下操作
484                         int todel = it->node->iscompr ? it->node->size : 1;
485                         raxIteratorDelChars(it,todel);
486                     )
487                     
488                     if (!raxIteratorNextStep(it,1)) return 0; 
489                     查找停止节点的父节点下,大于停止节点所在的子树的第一个节点(子树最小节点)
490                     (该子树的全部节点都是大于我们所有查找元素的)
491                 }
492             }
493             if (lt) {
494                 /* If the key the compressed node represents is smaller
495                  * than our seek element, seek the greater key in this
496                  * subtree, otherwise set the state in order to go back to
497                  * the previous sub-tree. */
498                 如果压缩节点的键小于我们要查找的元素,
499                 把子树中最大的键找出来(这个键就是小于我们要查找的最接近的一个键)。
500                 否则设置迭代器状态返回到之前的子树,(即从子树中查找最小值,那就是最接近所寻找元素)
501                 if (nodechar < keychar) {    小于当前节点的当前字符            
502                     if (!raxSeekGreatest(it)) return 0;   
503                     找子树中最大的键就是要小于要查找元素的最接近元素
504                     it->data = raxGetData(it->node);
505                 } else {
506                     if (!raxIteratorAddChars(it,it->node->data,it->node->size)) return 0;
507                     这里的作用同上述gt情况一样
508                     if (!raxIteratorPrevStep(it,1)) return 0;
509                     查找停止节点的父节点下,小于停止节点所在的子树的最后一个节点(子树最大节点)
510                 }
511             }
512             it->flags |= RAX_ITER_JUST_SEEKED; /* Ignore next call. */ 
513             设置表示已经找到,下次查找的时候直接返回即可
514         } else {  长度等于的情况下
515             debugf("No mismatch: %.*s\n",
516                 (int)it->key_len, (char*)it->key);
517             /* If there was no mismatch we are into a node representing the
518              * key, (but which is not a key or the seek operator does not
519              * include 'eq'), or we stopped in the middle of a compressed node
520              * after processing all the key. Continue iterating as this was
521              * a legitimate key we stopped at. */
522              如果全部匹配停留在一个节点的键上(排除该节点不是键或者没有相等的查找操作),
523              或者如果我们处理了整个键,但是停留在一个压缩节点的内部。
524              继续迭代,因为我们停留在一个合法的键上
525             it->flags &= ~RAX_ITER_JUST_SEEKED;
526             if (it->node->iscompr && it->node->iskey && splitpos && lt) {
527                     压缩节点   是键   在内部   符号是小于
528                 /* If we stopped in the middle of a compressed node with
529                  * perfect match, and the condition is to seek a key "<" than
530                  * the specified one, then if this node is a key it already
531                  * represents our match. For instance we may have nodes:
532                  如果我们全部匹配,但是停留在一个压缩节点的内部,查询的条件是小于特定的值,
533                  那么这个节点就是我们要查找的节点。举例如下
534                  * "f" -> "oobar" = 1 -> "" = 2
535                  *
536                  * Representing keys "f" = 1, "foobar" = 2. A seek for
537                  * the key < "foo" will stop in the middle of the "oobar"
538                  * node, but will be our match, representing the key "f".
539                  表示键 "f" = 1, "foobar" = 2.如果查找键小于"foo"将会停止在"oobar"节点中,
540                  但是签好匹配我们所需,即表示键"f"
541                  * So in that case, we don't seek backward. */
542                  在这种情况下,我们不需要回溯,直接取数据即可
543                 it->data = raxGetData(it->node);
544             } else {
545                 if (gt && !raxIteratorNextStep(it,0)) return 0; 大于就向前一步
546                 if (lt && !raxIteratorPrevStep(it,0)) return 0;  小于就退后一步
547             }
548             it->flags |= RAX_ITER_JUST_SEEKED; /* Ignore next call. */
549             设置表示已经找到,下次查找的时候直接返回即可
550         }
551     } else {
552         /* If we are here just eq was set but no match was found. */
553         如果设置了相等,但是没有匹配找到,就返回结束
554         it->flags |= RAX_ITER_EOF;
555         return 1;
556     }
557     return 1;
558 }
559 **************************************************************************
560 /* Seek the greatest key in the subtree at the current node. Return 0 on
561  * out of memory, otherwise 1. This is an helper function for different
562  * iteration functions below. */
563 在当前节点的子树中查找最大的键,如果OOM返回0,否则返回1. 
564 这个为了下面多个不同迭代函数的一个帮助函数
565 int raxSeekGreatest(raxIterator *it) {
566     while(it->node->size) {  存在元素
567         if (it->node->iscompr) {  压缩节点
568             if (!raxIteratorAddChars(it,it->node->data,
569                 it->node->size)) return 0;  全部拷贝
570         } else {
571             if (!raxIteratorAddChars(it,it->node->data+it->node->size-1,1))
572                 return 0; 非压缩节点,只拷贝最后一个字符
573         }
574         raxNode **cp = raxNodeLastChildPtr(it->node); 查找最大的子节点
575         if (!raxStackPush(&it->stack,it->node)) return 0;  将父节点入栈
576         memcpy(&it->node,cp,sizeof(it->node)); 用子节点代替父节点,继续循环,直到结束
577     }
578     return 1;
579 }
580 **************************************************************************
581 /* Go to the next element in the scope of the iterator 'it'.
582  * If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
583  * returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
584 到达迭代器it范围内的下一个元素。
585 如果遇到结尾或者OOM,返回0,否则返回1
586 在返回0的情况中,如果是OOM,还需要设置标志errno为ENOMEM
587 int raxNext(raxIterator *it) {
588     if (!raxIteratorNextStep(it,0)) {
589         errno = ENOMEM;
590         return 0;
591     }
592     if (it->flags & RAX_ITER_EOF) {
593         errno = 0;
594         return 0;
595     }
596     return 1;
597 }
598 **************************************************************************
599 /* Go to the previous element in the scope of the iterator 'it'.
600  * If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
601  * returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
602 到达迭代器it范围内的前一个元素
603 如果遇到结尾或者OOM,返回0,否则返回1
604 在返回0的情况中,如果是OOM,还需要设置标志errno为ENOMEM
605 int raxPrev(raxIterator *it) {
606     if (!raxIteratorPrevStep(it,0)) {
607         errno = ENOMEM;
608         return 0;
609     }
610     if (it->flags & RAX_ITER_EOF) {
611         errno = 0;
612         return 0;
613     }
614     return 1;
615 }
616 **************************************************************************
617 /* Perform a random walk starting in the current position of the iterator.
618  * Return 0 if the tree is empty or on out of memory. Otherwise 1 is returned
619  * and the iterator is set to the node reached after doing a random walk
620  * of 'steps' steps. If the 'steps' argument is 0, the random walk is performed
621  * using a random number of steps between 1 and two times the logarithm of
622  * the number of elements.
623 执行随机遍历从迭代器的当前位置开始。返回0如果树是空的或者发生OOM,否则返回1,
624 迭代器设置成经过随机遍历steps步数到达的节点。如果参数steps为0,那么随机遍历使用的步数
625 为在1到对元素总数取对数两倍长的一个随机的数字。
626  * NOTE: if you use this function to generate random elements from the radix
627  * tree, expect a disappointing distribution. A random walk produces good
628  * random elements if the tree is not sparse, however in the case of a radix
629  * tree certain keys will be reported much more often than others. At least
630  * this function should be able to expore every possible element eventually. */
631 提示:如果你使用这个函数从基树去生成随机元素,期待一个没有规律的分布。
632 一个随机遍历可以产生很好的随机元素,如果基树不是稀疏的,然而在某种情况下,
633 基树中特定的键会比其它键有跟多遍历到的机会。至少这个函数最终应该可以遍历到每个可能的元素
634 int raxRandomWalk(raxIterator *it, size_t steps) {
635    无元素直接返回
636     if (it->rt->numele == 0) {
637         it->flags |= RAX_ITER_EOF;
638         return 0;
639     }
640 
641     if (steps == 0) {  如果没有设置随机步数值
642         size_t fle = 1+floor(log(it->rt->numele));对数取下整 加 1
643         fle *= 2;
644         steps = 1 + rand() % fle;
645     }
646 
647     raxNode *n = it->node;  初始节点就是当前迭代器中的节点
648     while(steps > 0 || !n->iskey) {   还有遍历的步数 或者  不是当前节点不是键 
649         int numchildren = n->iscompr ? 1 : n->size; 根据是否是压缩节点获取子节点个数
650         int r = rand() % (numchildren+(n != it->rt->head));  头结点不用回溯
651 
652         if (r == numchildren) {  如果恰好是子节点个个数
653             /* Go up to parent. */  到达父节点
654             n = raxStackPop(&it->stack);
655             int todel = n->iscompr ? n->size : 1;
656             raxIteratorDelChars(it,todel);
657         } else {
658             /* Select a random child. */ 从子节点中随机选择一个节点
659             if (n->iscompr) { 压缩节点没有选择机会,只有一个子节点
660                 if (!raxIteratorAddChars(it,n->data,n->size)) return 0;
661             } else { 非压缩节点根据随机值拼接
662                 if (!raxIteratorAddChars(it,n->data+r,1)) return 0;
663             }
664             raxNode **cp = raxNodeFirstChildPtr(n)+r; 指针指向选中的子节点指针
665             if (!raxStackPush(&it->stack,n)) return 0; 将父节点入栈
666             memcpy(&n,cp,sizeof(n)); 将子节点设置为当前节点
667         }
668         if (n->iskey) steps--;  如果这个节点是键,刚好遍历了一个键,步数减去1
669     }
670     it->node = n;  迭代器指向当前遍历到的节点
671     it->data = raxGetData(it->node); 获取键对应的数据
672     return 1;
673 }
674 **************************************************************************
675 /* Free the iterator. */ 释放迭代器
676 对于申请的内存,全部释放
677 void raxStop(raxIterator *it) {
678     if (it->key != it->key_static_string) rax_free(it->key);
679     raxStackFree(&it->stack);
680 }
681 **************************************************************************
682 /* Return if the iterator is in an EOF state. This happens when raxSeek()
683  * failed to seek an appropriate element, so that raxNext() or raxPrev()
684  * will return zero, or when an EOF condition was reached while iterating
685  * with raxNext() and raxPrev(). */
686 如果迭代器处于EOF状态就返回。这个情况发生在当函数raxSeek查找合适元素失败的时候,
687 所以函数raxNext() 或 raxPrev()返回0或者在raxNext() 和 raxPrev()迭代中满足EOF条件
688 int raxEOF(raxIterator *it) {
689     return it->flags & RAX_ITER_EOF;  设置迭代结束标志
690 }
691 **************************************************************************
692 /* Return the number of elements inside the radix tree. */
693 返回基树中的总元素个数
694 uint64_t raxSize(rax *rax) {
695     return rax->numele;
696 }
697 **************************************************************************
698 /* Compare the key currently pointed by the iterator to the specified
699  * key according to the specified operator. Returns 1 if the comparison is
700  * true, otherwise 0 is returned. */
701 用指定的操作符比较迭代器当前指向的当前键和指定的键。返回1如果比较成功(即满足比较条件),否则返回0
702 int raxCompare(raxIterator *iter, const char *op, unsigned char *key, size_t key_len) {
703     int eq = 0, lt = 0, gt = 0;
704 
705     if (op[0] == '=' || op[1] == '=') eq = 1;
706     if (op[0] == '>') gt = 1;
707     else if (op[0] == '<') lt = 1;
708     else if (op[1] != '=') return 0; /* Syntax error. */
709 
710     size_t minlen = key_len < iter->key_len ? key_len : iter->key_len; 找出短的字符串长度
711     int cmp = memcmp(iter->key,key,minlen); 比较字符串大小
712 
713     /* Handle == */
714     if (lt == 0 && gt == 0) return cmp == 0 && key_len == iter->key_len; 相等的情况
715 
716     /* Handle >, >=, <, <= */
717     if (cmp == 0) { 相等
718         /* Same prefix: longer wins. */ 同样前缀,长的赢
719         if (eq && key_len == iter->key_len) return 1;  相等
720         else if (lt) return iter->key_len < key_len; 
721         小于的情况,如果迭代其中的字符串短,那么就满足小的条件,返回1,否则返回0
722         else if (gt) return iter->key_len > key_len;
723         大于的情况,如果迭代其中的字符串长,那么就满足大的条件,返回1,否则返回0
724         else return 0; /* Avoid warning, just 'eq' is handled before. */
725     } else if (cmp > 0) { 大于的情况
726         return gt ? 1 : 0; 如果是大于就刚好是1
727     } else /* (cmp < 0) */ { 小于的情况
728         return lt ? 1 : 0; 如果是小于就刚好是1
729     }
730 }
731 **************************************************************************

 

posted on 2021-01-18 21:36  子虚乌有  阅读(212)  评论(0)    收藏  举报