如果禁用递归搜索,与受信任地址之一匹配的原始客户端地址将被请求头字段中由 real_ip_header 指令定义的最后一个地址替换。...如果启用递归搜索,与受信任地址之一匹配的原始客户端地址将被请求头字段中最后一个非受信任地址替换。 ...); if (rlcf->from == NULL) { return NGX_DECLINED; } 如果是NULL,则返回NGX_DECLINED,跳过本模块的其他逻辑...= NGX_OK) { break; } /* 开启了递归模式的情况下,将继续查找下一个X-Forwarded-For头 */ found = 1; } /*...表示在开启递归的情况下,返回从后往前数第一个非受信IP地址 */ */ return found ?
搜索给定结点的父亲 递归思想 给定结点是指给定的是一个指向某个结点的指针(比如p)。 返回值也应该是指针,指向结点p之父亲的指针(找不到时为空)。 a. 算法FindFather b....如果t为空或者p为空,或者p等于t,那么直接返回。 将指针q指向t的第一个子节点。 进入一个循环,只要q不为空: 如果q等于p,表示找到了p的父节点,将result指针指向t,然后返回。...否则,递归调用FindFather函数,传入参数q和p,并将结果存储在result中。 如果result不为空,表示已经找到了父节点,直接返回。 将指针q更新为q的下一个兄弟节点。...,则根据定义返回NULL q指向根结点的左儿子结点,进入循环 如果给定结点是根结点的左儿子,则根节点就是其父亲 在左儿子子树中递归查找 ………… 如果找到了父节点,直接返回 没有找到,则q更新为左儿子的右兄弟...(即下一个个子结点) 继续循环递归查找………… 3.
,它首先会调用 expireIfNeeded判断键是否过期并且需要删除,如果为过期,则调用 lookupKey 方法从 dict 哈希表中查找并返回。...具体解释可以看代码中的详细注释 /* * 查找key的读操作,如果key找不到或者已经逻辑上过期返回 NULL,有一些副作用 * 1 如果key到达过期时间,它会被设备为过期,并且删除 *...来判断键是否过期,然后根据 Redis 是否配置了懒删除来进行同步删除或者异步删除。...= NULL) return now > when; // master时,键未过期直接返回 if (now <= when) return 0; // 键过期,删除键...prepareClientToWrite 函数,将客户端加入到了Redis 的等待写入返回值客户端队列中,也就是 clientspendingwrite 队列。
文章目录 前言 一、Redis客户端结构体简介 二、字符串键函数 1.set系列函数 2.incr decr函数 三、列表键函数 1.添加元素函数 2.设置指定位置索引函数 3.获取列表范围元素的函数...四、哈希键函数 1.获取指定字段的值 2.获取哈希表容量 五、集合键函数 1.向集合添加元素 2.判断元素是否在集合内部 六、有序集合键函数 1.从有序集合删除元素 2.获取指定元素分值 总结...1.添加元素函数 lpush和rpush命令可以在一个列表的左端或者右端添加元素,其实现如下:先根据要添加对象的长度以及列表元素数目判断一下是否需要将压缩列表转为双端链表,然后根据不同的底层实现调用压缩列表和双向链表的...,函数返回 -1 。...* 查找成功时,返回 0 。
一个递归遍历整棵树,用来转换root节点;另一个递归用来返回子树的路径数。 ¶572 另一个树的子树(easy) 双重递归,一发AC。...注意调整左右子树入队的顺序,然后合理放置出队的时机,画图模拟一下。 ¶669 修剪二叉搜索树(easy) 二叉搜索树的左子树的值都小于根结点,右子树的值都大于根结点。 使用递归。...如果p和q分别在两个子树,则返回root;如果p和q在同一个子树,则返回那个子树的结果。递归的结束条件是root为空或root等于p或q。...¶108 将有序数组转换为二叉搜索树(easy) 自己是有点递归的思路的,不过还是看了别人的代码。 以后遇到递归还是先考虑单独写一个函数吧,思考起来也清晰一点。...两个哈希表:一个哈希表键为word,值为val;另一个哈希表键为前缀,值为前缀和。 哈希表+前缀树:前缀树代替第一种方法中的后一个哈希表。 纯前缀树:求sum的时候需要递归。
开始之前我们先看看来 Trie 树的几个常见的应用场景: Google、Baidu 等搜索引擎的搜索提示 ? 代码自动补全 ? IP路由查询使用的最长前缀匹配算法 ?...'a'] == NULL) { node->next[c-'a'] = new Trie(); } node = node->next[c-'a'...]; } node->isEnd = true; } 查找 描述:查找 Trie 中是否存在单词 word 实现:从根结点的子结点开始,一直向下匹配即可,如果出现结点值为空就返回false...只删除了单词"aec" 实现:我们首先要一直递归匹配到 word 的最后一个字符,并将最后一个字符对应结点的isEnd置为false,然后逐步删除并返回上一个结点。...word) { if (node->next[c-'a'] == NULL) { node->next[c-'a'] = new Trie();
), 如果是说明要找的键没找到,返回false 调用compareFn方法比对要查找节点与当前节点的key进行大小比较 如果要查找的节点小于当前节点的key,则递归调用searchNode方法,传当前节点的左子节点和要查找的...,则继续判断key与根节点键的大小,25 递归它的左子树 然后,比较25和21的大小,25 > 21,递归它的右子树 此时,25 === 21,节点已找到,返回true 移除一个节点 移除树中的节点...,橙色线条表示递归调用直至节点为null然后执行回调函数。...接下来,我们通过一个例子来描述下先序遍历的过程: 如上图所示,蓝色字标明了节点的访问顺序,橙色线表示递归调用直至节点为null然后执行回调函数。...如上图所示,蓝色字标示了节点的执行顺序,橙色线表示递归调用直至节点为null然后执行回调函数。
3.切换目标数据库函数 4.设置过期时间函数 5.查找key对应值函数 总结 前言 本文对Redis的数据库文件进行简要介绍,包括数据库的选择,键的新建更新删除、Redis过期策略以及事件通知等。...键空间通知会告诉用户关注的键执行了什么命令,如下所示: 键事件通知会告诉用户关注的命令被那些键执行了,如下所示: 二、数据库相关API 1.数据库通知函数 键空间和键事件通知函数定义在...* * 返回 0 表示键没有过期时间,或者键未过期。 * * 返回 1 表示键已经因为过期而被删除了。...++; return; } } 5.查找key对应值函数 查找key对应值函数实现如下: /* * 从数据库 db 中取出键 key 的值(对象) * * 如果 key...的值存在,那么返回该值;否则,返回 NULL 。
搜索给定结点的父亲 【数据结构】树与二叉树(廿四):树搜索给定结点的父亲(算法FindFather) 3. 搜索指定数据域的结点 a. 算法FindTarget b....算法解析 算法FindTarget在以t为根指针的树中搜索数据成员等于target的节点,类似先根遍历,其时间复杂度为O(n) 。 首先,将result指针设置为空。 如果t为空,直接返回。...如果t的数据成员等于target,表示找到了目标节点,将result指针指向t,然后返回。 将指针p指向t的第一个子节点。...进入一个循环,只要p不为空: 递归调用FindTarget函数,传入参数p和target,并将结果存储在result中。 如果result不为空,表示已经找到了目标节点,直接返回。...>nextBrother = D; C->firstChild = E; E->nextBrother = F; // 要查找的目标值 char targetValue
: 程序首先访问数组的索引 0 , 返回 u.score 值为 1.0 的列表项 “1” ; 然后访问数组的索引 1 , 返回 u.score 值为 2.0 的列表项 “2” ; 最后访问数组的索引 2...c.遍历数组,根据obj指向的的集合元素,以及by指定的-id,查找对应权重键的值。如集合元素为sjx,则查找sjx-id的值,等于3。...d.将查找的权重键的值转换成double类型的浮点数,然后保存在对应数组项的u.score属性中。 f.遍历数组, 将各个数组项的 obj 指针所指向的集合元素作为排序结果返回给客户端。...(c, c->argv[j+1], &limit_start, NULL) !...while((ln = listNext(&li))) { redisSortOperation *sop = ln->value; // 解释并查找键
插入字符串 从根结点往下递归,如果字符串中下一个字母对应的子结点为空,那就新建一个结点再递归,否则的话就直接递归下去。 最后把最后一个结点的 isEnd 设置为 1,表示这个结点是字符串的结束位置。...查询字符串 从根结点往下递归查找,如果字符串还没遍历结束,但是结点已经空了,说明字符串不在字典树中。...否则的话一直查找到最后一个字符,然后看对应结点的 isEnd 是 1 还是 0,如果是 1 ,就存在字符串,否则不存在。...首先整体框架是和查询字符串类似的,从根结点往下递归查询,然后用一个栈保存查询到的结点。 如果查询过程中直接遇到了空结点,就直接返回,因为都不存在字符串,就不用删除了。然后判断最后一个结点的类型。...'a'] == NULL) { node->next[c-'a'] = new Trie(); } node = node
功能对比exists参数格式:EXISTS key [key ...]用于判断某个键是否存在get参数格式:GET key用于获取键对应的值。由上可知,相同的场景只有判断键是否存在。...(c->db, key); if (!...(c,count);}exists和get命令都调用了lookupKeyReadWithFlags,我们看下这个函数的实现:robj *lookupKeyReadWithFlags(redisDb *db...;}可见都是先判断了确认了是否过期(过期key单独保存在另一个dict里面),再没有过期的情况下查找了db库,总体查找时间是一致的。...但是,我们可以发现,get命令返回了键对应的值,exists返回了个数,一般键对应的值较大,传输时间较长。所以相对较慢。结论在判断key是否存在的场景下:exists速度更快,可以忽略类型。
之前的几篇文章介绍了JSON数据类型,相信大家已经对JSON有了一定的了解,上面一篇文章介绍了《MySQL8.0 JSON函数之创建与返回JSON属性(四)》JSON函数的使用;本节中的函数对JSON值执行搜索或比较操作...JSON对象的顶级值中的键,如果给定了path参数,则返回所选路径中的顶级键。...如果顶级值具有嵌套的子对象,则返回值不包括来自这些子对象的键。...此函数相当于JSON_CONTAINS(),它要求所搜索的数组中的所有元素都存在于所搜索的数组中。...如果任何一个json_doc,path或 search_str 参数为NULL,则返回NULL;文档中不存在路径;或找不到搜索字符串。
因此在 watchCommand 函数中首先判断是否执行过 multi 命令,如果执行了 multi 命令则返回错误。...然后调用 watchForKey 来把指定的 key 进行添加,watchForKey 的代码如下: /** * 监控指定的键 */void watchForKey(redisClient *c,...if we are already watching for this key */ // 检查指定的键是否已经被监控 listRewind(c->watched_keys,&li);...Let's add it */ // 指定的键没有被监控 clients =dictFetchValue(c->db->watched_keys,key); if(!...,首先会查找指定的 keys 是否加入监视列表,如果没有加入则进行加入。
: 最优情况下,二叉搜索树近似为完全二叉树,高度为 最差情况下,二叉搜索树退化为类似于单支树,高度为 最优情况下增删查改为 最差情况下增删查改为 综合来讲时间复杂度为 指出二分查找: 二分查找需要在允许下标随机访问的结构中...二分查找需要在有序的结构中 二分查找的时间复杂度为 二分查找对应的结构一般为数组,它挪动数据的时间复杂 二叉搜索树的插入 树为空,直接增新节点,赋值给root指针 树不为空,按照性质,插入值比当前节点大走右边...从根开始查找,key比节点大就走右,比节点小就走左边 最多查找高度次数,走到空还没找到就不存在 不支持插入相等的值,找到x就返回,反之继续查找直到高度次 Node* Find(const K& key...(重点) 先查找是否存在,不存在返回false 若存在有以下四种情况 删除节点的左右孩子均为空 直接删除然后给空 删除节点的左(右)孩子为空,另一边不为空 把节点的父亲对应的孩子节点的指针指向孩子不为空的一边...,然后删除节点 删除节点左右均不为空 找左子树的最大节点(右子树的最小节点)替代删除节点,,然后删除最值节点 bool Erase(const K& key) { Node* par =
以rank方法为例( key在键中的排): 如果用有序数组实现字典,实现rank方法只要查找到给定的key,然后返回下标就可以了。...等于当前结点的键,查找成功并返回对应的值 最后结果有两种: 查找到给定的key,返回对应的值 x迭代至最下方的结点也没有查找到key,因为x.left=x.right=null,在下一次调用get返回-...这段代码的作用有两方面: 沿搜索路径重置结点链接 更新路径上的结点计数器 沿搜索路径重置结点链接 如上文所说, 重置结点链接要结合上下两层递归来看 在递归到最后一个结点前, 下一层递归返回值是x(代码中...实现思路: 查找排名为k的键,如果左子树中的结点数大于k, 那么我们就继续(递归地)在左子树中查找排名为k的键; 如果t等于k,我们就返回根结点中的键,如果t小于k,我们就(递归地)在右子树中查找排名为..., 但由于条件不足无法立即给出判断,所以只能继续向右子树递归floor方法,并取得递归的返回值,判断递归返回的结果是否为null 如果递归返回null,说明右子树没有floor值,所以floor值就是当前结点的键
内存淘汰策略 实际上Redis定义了「8种内存淘汰策略」用来处理redis内存满的情况: 1.noeviction:直接返回错误,不淘汰任何已经存在的redis键 2.allkeys-lru:所有的键使用...当缓存达到容量并有一个新的内存块等待插入时,系统将搜索计数器最低的块并将其从缓存中删除。.../* * * 这个函数是 EXPIRE 、 PEXPIRE 、 EXPIREAT 和 PEXPIREAT 命令的底层实现函数。 * * 命令的第二个参数可能是绝对值,也可能是相对值。...if (lookupKeyRead(c->db,key) == NULL) { addReply(c,shared.czero); return; } /...= NULL); // 根据键取出键的过期时间 de = dictReplaceRaw(db->expires,dictGetKey(kde)); // 设置键的过期时间 /
Guava Cache 中未命中,则再去 Redis 中查询,如果命中则返回数据,并在 Guava Cache 中设置此数据。...基数树是针对稀疏的长整型数据查找的多叉搜索树,能快速且节省空间的完映射,一般用于解决 Hash冲突和 Hash表大小的设计问题,Linux 的内存管理就使用了它。 ?...当某一个 key 被修改或删除时,Redis 会调用 trackingInvalidateKey 方法根据 key 从 TrackingTable 中查找所有对应的客户端ID,然后调用 sendTrackingMessage...= keyobj->ptr; // 省略,如果广播模式的记录基数树不为空,则先处理广播模式 // 1 根据键的指针去 TrackingTable 查找 rax *ids = raxFind...);} 源码如上所示,trackingInvalidateKey 方法主要做了 7 件事情: 根据键的指针去 TrackingTable 查找客户端ID列表; 使用迭代器遍历列表; 根据 clientId
Guava Cache 中未命中,则再去 Redis 中查询,如果命中则返回数据,并在 Guava Cache 中设置此数据。...基数树是针对稀疏的长整型数据查找的多叉搜索树,能快速且节省空间的完映射,一般用于解决 Hash冲突和 Hash表大小的设计问题,Linux 的内存管理就使用了它。...当某一个 key 被修改或删除时,Redis 会调用 trackingInvalidateKey 方法根据 key 从 TrackingTable 中查找所有对应的客户端ID,然后调用 sendTrackingMessage...sdskey = keyobj->ptr; // 省略,如果广播模式的记录基数树不为空,则先处理广播模式 // 1 根据键的指针去 TrackingTable 查找 rax *ids...); } 源码如上所示,trackingInvalidateKey 方法主要做了 7 件事情: 根据键的指针去 TrackingTable 查找客户端ID列表; 使用迭代器遍历列表; 根据 clientId
如下图所示,一条命令执行完成并且返回数据一共涉及三部分,第一步是建立连接阶段,响应了socket的建立,并且创建了client对象;第二步是处理阶段,从socket读取数据到输入缓冲区,然后解析并获得命令...,执行命令并将返回值存储到输出缓冲区中;第三步是数据返回阶段,将返回值从输出缓冲区写到socket中,返回给客户端,最后关闭client。...socket读取事件处理器 当客户端发来命令时,读取事件处理器方法会被执行,对应处理阶段的相关逻辑都会被执行,然后注册socket写事件处理器 当写事件处理器被执行时,就是将返回值写回到socket中。...acceptTcpHandler 函数会首先调用 anetTcpAccept方法,它底层会调用 socket 的 accept 方法,也就是接受客户端来的建立连接请求,然后调用 acceptCommonHandler...; return C_ERR; } /** * 根据 argv[0] 查找对应的 command * 2 命令字典查找指定命令;所有的命令都存储在命令字典中
领取专属 10元无门槛券
手把手带您无忧上云