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 **************************************************************************