自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(800)
  • 收藏
  • 关注

原创 PHP7内核剖析 学习笔记 第九章 PHP基础语法的实现

zend_brk_cont_element结构保存在zend_op_array->brk_cont_array数组中(每个循环的结构都存在里面,包括非嵌套的循环和每层嵌套的循环),zend_op_array->last_brk_cont是此数组中第一个可用位置,每申请一个zend_brk_cont_element结构,last_brk_cont就加1,然后将数组扩容。zend_brk_cont_element的parent字段记录的就是父层循环的zend_brk_cont_element在数组中的位置。

2025-05-30 23:40:54 765

原创 LeetCode 395.至少有K个重复字符的最长子串

如果字符串s的长度为n,则此算法时间复杂度为O(26*(n + 26)),因为循环了26次,每次循环中需要初始化长为26的cnt数组,以及遍历s;给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k。如果字符串s的长度为n,则此算法时间复杂度为O(26*n),因为每层递归都会去除某种字符,而字符种类为26;解释:最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。2.当前窗口内,同种字符不足K个的字符数。

2025-05-29 22:24:12 434

原创 LeetCode 1040.移动石子直到连续II

先定义石子的最大距离为stones[n-1]-stones[0],对于最大值,我们应该每次移动都使得石子的最大距离减小1,即像跳棋一样,每次都将两端的某个石子移动到距离自己最近的中间位置,如128,首先将位置1的石子移动到2后面,即238,然后再将位置2的石子移动到3后面,即348,同理,后面几步为458、568、678,到678石子就连续了,这种方式每一步使得石子的最大距离都减少了1,移动总步数最大,值为初始情况下两端石子的中间空闲位置的数量,即5。我们可以移动一次,4 -> 8,游戏结束。

2025-05-25 18:28:46 871

原创 PHP7内核剖析 学习笔记 第八章 命名空间

准确地说,名字加前缀是通过zend_prefix_with_ns()获取的,其中如果发现FC(current_namespace)非空,则将其名字前加上FC(current_namespace)作为前缀,接下来注册到EG(class_table)、EG(function_table)中的名字就是修改后的名字了。,表示使用当前命名空间,此时zend_resolve_class_name函数中的zend_prefix_with_ns函数的处理如下:如果当前脚本定义了namespace(否则按原始名称解析。

2025-05-23 20:25:26 927

原创 PHP7内核剖析 学习笔记 第七章 面向对象

实际上,default_properties_table、default_static_members_table数组只是用来存储属性值的,并不是保存属性信息的,这里说的属性信息包括属性的访问权限(public、protected、private)、属性名、静态属性值的存储下标、非静态属性的内存offset等,这些信息通过zend_property_info结构存储,该结构通过zend_class_entry->properties_info符号表存储,这是一个哈希表,key就是属性名。

2025-05-22 23:34:10 1095

原创 LeetCode 2968.执行操作使频率分数最大

因此,当新加进来一个数时,它对操作次数的贡献总是它自己的值,并且当一个数加入时,中位数会变为负数,可以用s5减去s4的值,即。将子数组里所有数字都变为q,所需的操作次数就是蓝色和绿色部分的面积,蓝色部分的面积可以用矩形面积减去前三个数字的前缀和得到,绿色部分的面积可以用后三个数字的前缀和减去下面的矩形得到。当左边的数字出滑窗时,左边的数字对总操作次数的贡献为nums[left],因为它原本对操作次数的贡献为负,出滑窗时要加上它,并且中位数由正变为负,即总贡献为。,同理,如果有五个元素,则操作次数s5为。

2025-04-07 00:53:58 315

原创 LeetCode 3413.收集连续K个袋子可以获得的最多硬币数量

给你一个二维数组 coins,其中 coins[i] = [li, ri, ci] 表示从坐标 li 到 ri 的每个袋子中都有 ci 枚硬币。选择坐标为 [3, 4, 5, 6] 的袋子可以获得最多硬币:2 + 0 + 4 + 4 = 10。输入: coins = [[8,10,1],[1,3,2],[5,6,4]], k = 4。选择坐标为 [1, 2] 的袋子可以获得最多硬币:3 + 3 = 6。输入: coins = [[1,10,3]], k = 2。数组 coins 中的区间互不重叠。

2025-04-05 01:08:52 203

原创 LeetCode 3444.使数组包含目标值倍数的最小增量

题目想要让target中每个数都能在nums中找到一个倍数,比如target中有两个数3、5,那么需要nums中有一个数是3、5的最小公倍数的倍数,即15的倍数,如果target中的数是5、10,那么需要nums中有一个数是10的倍数,因此我们可以先计算出target中所有非空子集的最小公倍数,然后用暴力法dp,我们可以遍历nums中的所有数字,当前数字可以进行增加操作,也可以不进行增加操作,如果不对当前数字进行增加操作,就相当于nums中少了一个数字,问题变成了规模更小的同样问题;

2025-02-09 21:58:49 348

原创 LeetCode 3443.K次修改后的最大曼哈顿距离

题目要计算移动过程中,距离原点最大的曼哈顿距离,我们可以对移动过程中的每一位置进行查看,看当前位置经过最多k次修改后的最大曼哈顿距离,然后找出所有位置中经过修改后的距离最大值即可。将 s[1] 从 ‘S’ 改为 ‘N’ ,将 s[4] 从 ‘E’ 改为 ‘W’。将 s[2] 从 ‘S’ 改为 ‘N’ ,字符串 s 变为 “NWNE”。如果字符串s的长度为n,此方法时间复杂度为O(n),空间复杂度为O(1)。s 仅由 ‘N’、‘S’、‘E’ 和 ‘W’。‘S’:向南移动 1 个单位。

2025-02-06 00:43:23 244

原创 LeetCode 3442.奇偶频次间的最大差值 I

先遍历一遍字符串s,统计每个字母的出现次数,然后找出出现次数中,最大的奇数和最小的偶数,相减即可。字符 ‘a’ 出现 奇数次 ,次数为 5;字符 ‘b’ 出现 偶数次 ,次数为 2。字符 ‘a’ 出现 奇数次 ,次数为 3;字符 ‘c’ 出现 偶数次 ,次数为 2。返回 最大 差值,计算方法是出现 奇数次 字符的次数 减去 出现 偶数次 字符的次数。如果n是字符串s的长度,则此方法时间复杂度为O(n),空间复杂度为O(1)。s 至少由一个出现奇数次的字符和一个出现偶数次的字符组成。

2025-02-05 22:10:45 273

原创 PHP7内核剖析 学习笔记 第六章 函数

编译时,如果函数指定了返回值类型,则也为返回值创建一个zend_arg_info结构,该结构与参数的zend_arg_info结构保存在一起,即zend_op_array->arg_info数组中,返回值的zend_arg_info结构的保存位置为zend_op_array->arg_info[-1],即zend_op_array->arg_info指向的是参数开始的位置,而返回值的zend_arg_info结构在参数开始位置的前一位置。

2025-01-26 16:22:30 1232

原创 PHP7内核剖析 学习笔记 第五章 PHP的编译与执行(2)

5.4PHP的执行ZendVM执行器由指令处理handler与调度器组成:指令处理handler是每条opcode定义的具体处理过程,根据操作数的不同类型,每种opcode可定义25个handler,执行时,由执行器调用相应的handler完成指令的处理;调度器负责控制指令的执行,以及执行器的上下文切换,由调度器发起handler的执行。5.4.1handler的定义所有opcode的处理handler定义在Zend/zend_vm_def.h中,定义时不需要为每一条opcode定义25个handler

2025-01-19 00:55:32 667

原创 PHP7内核剖析 学习笔记 第五章 PHP的编译与执行(1)

PHP的编译与执行是两个相对独立的阶段,编译的流程为词法分析、语法分析、抽象语法树的生成,执行阶段则是根据编译阶段输出的产物(即opline指令)进行执行。5.1 语言的编译与执行计算机只认识机器语言,无法理解人类定义的编程语言,因此需要将编程语言翻译为机器语言,这个翻译过程称为编译。根据编译的时机不同,编程语言可分为编译型、解释型。编译型语言在程序运行前提前编译为计算机可执行的二进制文件,在执行时直接执行机器指令,这种类型语言的典型代表就是C、C++、Golang;解释型语言是程序在运行时由解释器边

2025-01-10 23:05:01 1319

原创 PHP7内核剖析 学习笔记 第四章 内存管理(2)

所有线程的tsrm_tls_entry结构保存在tsrm_tls_table数组中,该数组是一个全局变量,操作这个变量时需要加锁。然后根据线程id从tsrm_tls_table数组中获取tsrm_tls_entry,这里需要对取到的tsrm_tls_entry遍历,比较线程id,以找到该线程的tsrm_tls_entry,如果没有找到则表示线程还未分配tsrm_tls_entry,进入第2步进行分配,如果找到了则表示已经分配了tsrm_tls_entry,进入第3步返回storage中对应的资源。

2024-12-28 15:57:02 1009

原创 PHP7内核剖析 学习笔记 第四章 内存管理(1)

PHP中的变量不需要手动释放,内核实现了变量的内存管理,包括内存的分配与回收。4.1 变量的自动GC机制C/C++语言中,如果想在堆上分配变量,需要手动进行内存的分配与释放,变量的内存管理是一件非常烦琐的事情,稍有不慎就可能导致不可预知的错误。现代高级语言普遍提供了变量的自动GC机制,由语言自己进行管理,这使得开发者不需要再去关心变量的分配与释放,PHP也实现了这种机制,PHP中可直接通过$声明一个变量,使用完也不需要手动销毁,内核自己清楚什么时间该进行释放。我们先自己思考下如何实现自动GC,最简单的

2024-12-24 21:45:15 1003

原创 PHP7内核剖析 学习笔记 第三章 数据类型

type_info实际是将v结构的4个成员组合到了一起,v中的成员各站一个字节,总共4个字节,type_info也是4个字节,每个字节对应v的一个成员,可直接通过type_info位移获取v成员的值。如果发现中间映射表中要设置的位置已经被之前插入的元素占用了(值不等于初始化的-1),那么会把已经存在的值保存到新插入的Bucket中(实际是将Bucket的zval成员的u2.next指针指向已经存在的Bucket),然后将中间映射表中的值更新为新Bucket的存储位置,即每次都会把冲突的元素插到开头。

2024-12-14 18:36:56 1118

原创 PHP7内核剖析 学习笔记 第二章 SAPI

其中Cli和Fpm是完整实现的应用程序,它们有定义自己的main函数,方便我们从入口开始逐步分析PHP的处理,尤其是单进程的Cli,非常方便调试,本书后面章节基本都是以Cli模式为例的。fpm_init()中主要的处理就是上面介绍的几个init过程,完成这些初始化操作后就是最关键的fpm_run()操作了,此环节将fork子进程,启动进程管理器,执行后master进程将不会返回main()函数,之后各worker进程会返回,也就是说main()函数中调用fpm_run()之后的操作均是worker进程的。

2024-12-08 21:01:08 1016

原创 PHP7内核剖析 学习笔记 第一章 PHP基础架构

这个版本被命名为PHP2,已经有了今日PHP的一些雏形,类似Perl的变量命名方式(Perl也用$声明标量变量,标量变量可以存储单一的值,如整数、浮点数、字符串,此外Perl中还有用@声明的数组变量和%声明的散列变量)、表单处理功能、嵌入到HTML中执行的能力。在编译阶段,PHP脚本将经历从PHP源代码到抽象语法树再到opline指令的转化过程,最终生成的opline指令就是Zend引擎可识别的执行指令,这些指令接着被执行器执行,这就是PHP代码解释执行的过程,本书介绍的大部分内容都是关于这两个阶段的。

2024-12-04 21:35:06 753

原创 Redis设计与实现 学习笔记 第二十四章 监视器

例如,客户端c10086向服务器发送MONITOR命令,那么这个客户端的REDIS_MONITOR标志会被打开,且这个客户端本身会被添加到monitors链表的表尾。服务器在每次处理命令请求前,都会调用replicationFeedMonitors函数,由这个函数将被处理的命令请求的相关信息发送给各个监视器。1.客户端可通过执行MONITOR命令,将客户端转换成监视器,接收并打印服务器处理的每个命令请求的相关信息。4.每次处理命令请求时,服务器都会遍历monitors链表,将相关信息发送给监视器。

2024-11-30 00:43:42 205

原创 Redis设计与实现 学习笔记 第二十三章 慢查询日志

每次执行命令的之前和之后,程序都会记录微秒格式的当前UNIX时间戳,这两个时间戳之间的差就是服务器执行命令所耗费的时长,服务器会将这个时长作为参数之一传送给slowlogPushEntryIfNeeded函数,此函数会检查是否需要为这次执行的命令创建慢查询日志。服务器使用先进先出方式保存多条慢查询日志,当服务器存储的慢查询日志数量等于slowlog-max-len选项的值时,服务器在添加一条新的慢查询日志前,会先将最旧的一条慢查询日志删除。

2024-11-30 00:27:15 727

原创 Redis设计与实现 学习笔记 第二十二章 二进制位数组

2.查表法的效果还受到CPU缓存的限制,对于固定大小的CPU缓存来说,创建的表越大,CPU缓存能保存的内容相比整个表格的比例就越少,查表时出现缓存不命中(cache miss)的情况就越多,缓存的换入和换出操作就会越频繁,最终影响查表法的实际效率。由于以上两个原因,我们可以得出结论,查表法是一种比遍历算法更好的统计办法,但受限于查表法带来的内存压力,以及缓存不命中可能带来的影响,我们只能考虑创建键长为8或16位的表,而这两种表带来的效率提升,对于处理非常长的位数组来说仍然远远不够。

2024-11-28 22:35:29 687

原创 Redis设计与实现 学习笔记 第二十一章 排序

SORT命令为每个被排序的键都创建一个与键长度相同的数组,数组的每个项都是一个redisSortObject结构,根据SORT命令使用的选项不同,程序使用redisSortObject结构的方式也不同。8.当SORT命令使用了GET选项时,命令会根据排序结果集中的元素,以及GET选项给定的模式,查找并返回其他键的值,而不是返回被排序的元素。但通过使用GET选项,我们可以让SORT命令对键进行排序后,根据被排序的元素,以及GET选项指定的模式,查找并返回某些键的值。

2024-11-24 23:40:39 796

原创 Redis设计与实现 学习笔记 第二十章 Lua脚本

主服务器清空repl_scriptcache_dict字典,可以强制自己向所有从服务器传播脚本,从而确保新的从服务器不会出现脚本未找到错误。repl_scriptcache_dict字典的键是一个个Lua脚本的SHA1校验和,而字典的值则全部都是NULL,当一个校验和出现在repl_scriptcache_dict字典时,说明这个校验和对应的Lua脚本已经传播给了所有从服务器,主服务器可以直接向从服务器传播包含这个SHA1校验和的EVALSHA命令,而不必担心从服务器会出现脚本未找到错误。

2024-11-23 17:20:29 1534

原创 Redis设计与实现 学习笔记 第十九章 事务

所有对数据库进行修改的命令,如SET、LPUSH(将一个或多个值插入到列表头部)、SADD、ZREM(移除有序集合中的一个或多个成员,不存在的成员将被忽略)、DEL、FLUSHDB(清空数据库中的所有key)等,在执行后都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有,那么touchWatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事务安全性已经被破坏。

2024-11-18 22:44:33 663

原创 Redis设计与实现 学习笔记 第十八章 发布与订阅

因为服务器状态中的pubsub_patterns链表记录了所有模式的订阅关系,所以为了将消息发送给所有与channel频道相匹配的模式的订阅者,PUBLISH命令要做的就是遍历整个pubsub_patterns链表,查找那些与channel频道相匹配的模式,并将消息发送给订阅了这些模式的客户端。通过执行SUBSCRIBE命令,客户端可订阅一个或多个频道,从而成为这些频道的订阅者(subscriber):每当有其他客户端向被订阅的频道发送消息(message)时,频道的所有订阅者都会收到这条消息。

2024-11-17 13:40:56 1035

原创 Redis设计与实现 学习笔记 第十七章 集群

2.PING消息:集群里的每个节点默认每隔一秒就会从已知节点列表中随机选出五个节点,然后对这五个节点中最长时间没有发送过PING消息的节点发送PING消息,以此来检测被选中的节点是否在线。另外,一个节点也可以通过向集群广播自己的PONG消息来让集群中的其他节点刷新关于这个节点的认识,例如当一次故障转移操作成功执行后,新的主节点会向集群广播一条PONG消息,以此来让集群中的其他节点立即知道这个节点已经变成了主节点,并且接管了已下线节点负责的槽。

2024-11-13 22:34:12 1369

原创 Redis设计与实现 学习笔记 第十六章 Sentinel

8.源Sentinel接收到目标Sentinel返回的命令回复后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同,那么源Sentinel继续取出回复中的leader_runid参数,如果leader_runid参数的值和源Sentinel的运行ID一致,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。9.如果有某个Sentinel被半数以上Sentinel设置成了局部领头Sentinel,那么这个Sentinel成为领头Sentinel。

2024-11-07 21:19:36 963

原创 Redis设计与实现 学习笔记 第十五章 复制

如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么当从服务器向主服务器发送REPLCONF ACK命令时,主服务器将发觉从服务器的复制偏移量少于自己的复制偏移量,然后主服务器就会根据从服务器提交的复制偏移量,在复制积压缓冲区里找到从服务器缺少的数据,并将这些数据重新发给从服务器。3.当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。

2024-11-03 16:03:04 786

原创 Redis设计与实现 学习笔记 第十四章 服务器

3.检查服务器设置的AOF重写条件是否满足,如果条件满足,且服务器没有在执行其他持久化操作,那么服务器将开始一次新的BGREWRITEAOF操作(虽然3是在rdb_child_pid和aof_child_pid属性都为-1时进行的检查,但由于1和2的存在,服务器还是会检查一下是否正在进行持久化操作)。命令的参数个数为-3,表示命令接受三个或以上数量的参数;命令的标识为“wm”,表示SET命令是一个写入命令,且在执行这个命令前,服务器应该对内存占用情况进行检查,因为这个命令可能会占用大量内存。

2024-10-31 19:52:29 752

原创 Redis设计与实现 学习笔记 第十三章 客户端

但timeout选项也有例外情况:如果客户端是主服务器(打开了REDIS_MASTER标志)、从服务器(打开了REDIS_SLAVE标志)、正在被BLPOP等命令阻塞(打开了REDIS_BLOCKED标志)、正在执行SUBSCRIBE(订阅某个频道)和PSUBSCRIBE(订阅一个或多个符合给定匹配模式的频道)等订阅命令,那么即使客户端的空转时间超过了timeout选项的值,客户端也不会被服务器关闭。1.在主从服务器进行复制操作时,主服务器会成为从服务器的客户端,而从服务器也会成为主服务器的客户端。

2024-10-27 21:21:29 808

原创 Redis设计与实现 学习笔记 第十二章 事件

3.对文件事件和时间事件的处理都是同步、有序、原子地执行的,服务器不会中途中断事件处理,也不会对事件进行抢占,因此,不管是文件事件的处理器,还是时间事件的处理器,它们都会尽可能减少程序的阻塞时间,并在有需要时主动让出执行权,从而降低造成事件饥饿的可能性。当回复能发送时,将产生AE_WRITABLE事件,触发命令回复处理器执行,当命令回复处理器将全部回复写入套接字后,将不再监听客户端套接字的AE_WRITABLE事件。正常情况下,服务器几乎是将无序链表退化成一个指针来使用,因此不会影响事件执行的性能。

2024-10-26 20:35:28 813

原创 Redis设计与实现 学习笔记 第十一章 AOF持久化

上面介绍的aof_rewrite函数会进行大量的写入操作,所以调用这个函数的线程将被长时间阻塞,因为Redis使用单个线程来处理命令请求,所以如果服务器直接调用aof_rewrite函数,那么在AOF重写期间,服务器将无法处理客户端发来的命令请求。因为AOF持久化是通过保存被执行的写命令来记录数据库状态的,所以随着时间流逝,AOF文件中的内容会越来越多,文件也会越来越大,如果不加以控制,体积过大的AOF文件可能对Redis服务器或宿主机造成影响,且AOF文件越大,还原所需时间就越多。

2024-10-25 23:17:09 781

原创 Redis设计与实现 学习笔记 第十章 RDB持久化

其中,REDIS_RDB_ENC_LZF常量标志着字符串已被LZF算法压缩过了,程序读入到这个常量时,会根据compressed_len(字符串被压缩后的长度)、origin_len(字符串被压缩前的长度)、compressed_string(被压缩后的字符串)对字符串进行解压。如果TYPE值为REDIS_RDB_TYPE_SET_INTSET,那么value保存的就是一个整数集合对象,RDB文件保存这种对象的方法是:先将整数集合转换为字符串对象,然后将这个字符串对象保存到RDB文件里。

2024-10-23 22:45:48 998

原创 Redis设计与实现 学习笔记 第九章 数据库

例如,对于一些和时间有关的数据,比如日志(log),在某个时间点后,对它们的访问会大大减少,甚至不再访问,如果这类过期数据大量积压在数据库中,用户以为服务器已经自动将它们删除了,但实际上这些键仍存在,且键占用的内存也没有释放,那造成的后果是非常严重的。但定时策略对CPU时间最不友好,在过期键比较多的情况下,删除过期键的行为可能会占用相当一部分CPU时间,在内存不紧张但CPU时间非常紧张的情况下,将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。

2024-10-20 21:05:42 879

原创 Redis设计与实现 学习笔记 第八章 对象

注意,linkedlist编码的列表对象在底层的双端链表结构中包含了多个字符串对象,这种嵌套字符串对象的行为在稍后介绍的哈希对象、集合对象、有序集合对象中都会出现,字符串对象是Redis五种类型的对象中唯一会被其他四种类型对象嵌套的对象。通过encoding属性来设定对象使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。

2024-10-17 23:20:35 1055

原创 Redis设计与实现 学习笔记 第七章 压缩列表

如果e1至eN都是大小介于250至253字节的节点,big节点的长度大于等于254字节,而small节点的长度小于254字节,那么当我们将small节点从压缩列表中删除后,为了让e1的previous_entry_length属性可以记录big节点的长度,程序将扩展e1的空间,并由此引发之后的连锁更新。2.如果前一节点的长度大于等于254字节,那么previsou_entry_length属性长为5字节:第一字节被设置为0xFE(十进制254),之后四字节则用于保存前一节点的长度。

2024-10-12 23:24:17 1228

原创 Redis设计与实现 学习笔记 第六章 整数集合

虽然contents数组保存的四个值中,只有第一个是真正需要用int64_t来保存的,其他三个值都可以用int16_t来保存,但根据整数集合的升级规则,当向一个底层为int16_t的整数集合添加一个int64_t类型的整数值时,整数集合已有的所有元素都会被转换成int64_t类型。要让一个数组可以同时保存int16_t、int32_t、int64_t三种类型的整数,最简单的做法是直接使用int64_t类型的数组作为整数集合的底层实现,但这样一来保存小整数时比较浪费内存。

2024-10-10 00:01:35 550

原创 Redis设计与实现 学习笔记 第五章 跳跃表

在同一个跳跃表中,各个节点保存的成员对象必须是唯一的,但是多个节点保存的分值却可以是相同的:分值相同的节点将按照成员对象在字典序中的大小来排序,成员对象较小的节点会排在前面(靠近表头的方向),而成员对象较大的节点则会排在后面(靠近表尾的方向)。再举个例子,图5-5用虚线标记了在跳跃表中查找分值为2.0、成员对象为o2的节点时,沿途经历的层:在查找节点的过程中,程序经过了两个跨度为1的节点,因此可以计算出,目标节点在跳跃表中的排位为2。在跳跃表中,节点按各自保存的分值从小到大排列。

2024-10-04 12:16:38 773

原创 Redis设计与实现 学习笔记 第四章 字典

根据BGSAVE命令或BGREWRITEAOF命令是否正在执行,服务器执行扩展操作所需的负载因子并不相同,这是因为在执行这两个命令的过程中,Redis需要创建子进程,而大多数操作系统都采用写时复制(copy-on-write)技术来优化子进程的使用效率,所以在子进程存在期间,服务器会提高执行扩展操作所需的负载因子,从而尽可能避免在子进程存在期间进行哈希表扩展操作,这可以避免不必要的内存写入操作,最大限度节约内存。

2024-10-03 00:26:52 609

原创 Redis设计与实现 学习笔记 第三章 链表

5.多态:链表节点使用void *指针来保存节点值,且可以通过list结构的dup、free、match三个属性为节点值设置类型特定函数,所以链表可用于保存各种不同类型的值。4.带链表长度计数器:程序使用list结构的len属性来对list持有的链表节点进行计数,程序获取链表中节点数量的复杂度为O(1)。2.每个链表节点由一个ListNode结构来表示,每个节点都有一个指向前置节点和后置节点的指针,所以Redis的链表实现是双端链表。3.match函数用于对比链表节点保存的值和另一个输入值是否相等;

2024-10-01 21:49:33 900

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除