1.ClickHouse 源码解析: MergeTree Merge 算法
2.PostgreSQL内核Trigger的时机时间一生
3.指标源码有什么用
4.Kswapd 源码解析
5.通达信周期共振MACD指标公式源码副图
6.UOS终极波动指标源码的组成要素:综合三个不同周期的RSI
ClickHouse 源码解析: MergeTree Merge 算法
ClickHouse MergeTree 「Merge 算法」 是对 MergeTree 表引擎进行数据整理的一种算法,也是源码源码 MergeTree 引擎得以高效运行的重要组成部分。
理解 Merge 算法,时机时间首先回顾 MergeTree 相关背景知识。源码源码ClickHouse 在写入时,时机时间将一次写入的源码源码久游网站源码下载数据存放至一个物理磁盘目录,产生一个 Part。时机时间然而,源码源码随着插入次数增多,时机时间查询时数据分布不均,源码源码形成问题。时机时间一种常见想法是源码源码合并小 Part,类似 LSM-tree 思想,时机时间形成大 Part。源码源码
面临合并策略的时机时间选择,"数据插入后立即合并"策略会迅速导致写入成本失控。因此,需要在写入放大与 Part 数量间寻求平衡。ClickHouse 的 Merge 算法便是实现这一平衡的解决方案。
算法通过参数 base 控制参与合并的 Part 数量,形成树形结构。随着合并进行,形成不同层,总层数为 MergeTree 的深度。当树处于均衡状态时,深度与 log(N) 成比例。base 参数用于判断参与合并的 Part 是否满足条件,总大小与最大大小之比需大于等于 base。
执行合并时机在每次插入数据后,但并非每次都会真正执行合并操作。对于给定的多个 Part,选择最适合合并的组合是一个数学问题,ClickHouse 限制为相邻 Part 合并,降低决策复杂度。最终,通过穷举找到最优组合进行合并。
合并过程涉及对有序数组进行多路合并。ClickHouse 使用 Sort-Merge Join 类似算法,通过顺序扫描多个 Part 完成合并过程,保持有序性。算法复杂度为 Θ(M * N),其中 M 为 Part 长度,N 为参与合并的 Part 数量。
对于非主键字段,ClickHouse 提供两种处理方式:Horizontal 和 Vertical。Vertical 分为两个阶段,分别处理非主键字段的合并和输出。
源码解析包括 Merge 触发时机、选择需要合并的 Parts、执行合并等部分。触发时机主要在写入数据时,考虑执行 Mutate 任务后。选择需要合并的rsi源码 Parts 通过 SimpleMergeSelector 实现,考虑了与 TTL 相关的特殊 Merge 类型。执行合并的类为 MergeTask,分为三个阶段:ExecuteAndFinalizeHorizontalPart、VerticalMergeStage。
Merge 算法是 MergeTree 高性能的关键,平衡写入放大与查询性能,是数据整理过程中的必要步骤。此算法通过参数和决策逻辑实现了在不同目标之间的权衡。希望以上信息能帮助你全面理解 Merge 算法。
PostgreSQL内核Trigger的一生
本文简要介绍 PostgreSQL 数据库的 Trigger 从创建、存储、触发、执行、修改到删除的过程,贯穿 Trigger 的一生。
文中引用的函数、结构体来源于 PG 源码,分支为 REL__STABLE,对应的 commit id 如下。此外还引用了 PG 官方文档。
触发器简介
Trigger 即触发器,它可以在特定事件发生时,对数据库中的对象执行特定操作:
根据触发事件的不同,PG 的触发器分为两类:
不同数据库中触发器的分类有所不同,比如 Oracle 分为 DML Trigger 和 System Trigger,SQL Server 分为 DML Trigger、DDL Trigger 和 Login Trigger,不论其如何划分,多数都可以与 PG 的触发器对应上。
创建触发器语法
首先介绍创建触发器的 SQL 和 PLpgSQL 语法。
Trigger
根据 PG 官方文档,创建 Trigger 的语法如下:
下面以表 t1、t2 为例创建一个简单的触发器示例。表的定义如下:
触发器定义如下,是表 t1 上的行级触发器,对 t1 进行 INSERT 之后会触发,并执行 insert_into_t2 函数,将插入到 t1 的数据也插入到 t2。
insert_into_t2 函数定义如下,其中引用了上下文信息 NEW,表示插入到 t1 的数据,并将其插入到 t2。
Event Trigger
创建 Event Trigger 的语法如下,相比 Trigger 的语法要简单很多
以下是 PG 官方文档中的一个简单示例,该 Event Trigger 可以在任何 DDL 语句执行之前触发,并抛出异常,禁止执行任何 DDL 语句。
创建流程
简单介绍创建触发器时 PG 内核中的函数调用流程。
Trigger
CREATE TRIGGER 命令都属于 DDL 语句,所以会进入 DDL 的处理流程,关键的调用路径为: ProcessUtilitySlow-->CreateTrigger-->CreateTriggerFiringOn,CreateTriggerFiringOn 函数代码超过 行,酷站源码因此只介绍其中的关键步骤:
Event Trigger
CREATE EVENT TRIGGER 的关键调用路径为: standard_ProcessUtility-->CreateEventTrigger,该函数流程相对简单很多:
触发器的存储
用户创建的触发器必须持久化到数据库中,具体的存储位置是触发器相关的系统表中。
Trigger
Trigger 存储在 pg_trigger 系统表中,表中的关键字段如下,包含触发器所在的表、触发器名、触发器调用的函数、是否可推迟等属性。总之,通过 CREATE TRIGGER 创建触发器时指定的任何信息都会存储到系统表中。
pg_trigger 系统表的各个字段在内存中用Trigger 结构体表示,定义如下,可见其成员变量与 pg_trigger 的属性是一一对应的。
在内存中的 relcache(表缓存)中也同样保存有 Trigger 的信息:
Event Trigger
Event Trigger 存储在 pg_event_trigger 系统表中,关键字段如下,包含触发器名、调用的函数等信息。与 Trigger 不同的是,这里并不包含触发器所在的表,因为 Event Trigger 不属于任何一个表。
触发过程
触发器会在特定事件场景下被触发,它识别这些事件的方式也很简单,就是在对应事件的代码处调用触发器函数。
Trigger
对于普通的触发器,触发时机是 INSERT、UPDATE、DELETE 等操作之前或者之后,所以在 PG 的执行器阶段触发,多数在 ProcessQuery-->ExecutorRun-->ExecModifyTable 函数中
我们将执行触发操作的函数称为“触发器的执行函数”,各类触发器的执行函数命名格式比较统一,在此列举几种:
以ExecBRInsertTriggers 为例说明触发过程:
Event Trigger
事件触发器支持的事件仅有 ddl_command_start、ddl_command_end、table_rewrite 和 sql_drop 这四类,分别对应四个执行函数,其触发时机说明如下:
以 EventTriggerDDLCommandStart 为例说明触发过程:
调用功能函数
用户在创建触发器的 EXECUTE { FUNCTION | PROCEDURE } function_name 语句中指定了该触发器要执行的功能函数。在触发器被触发后,会执行该函数。
Trigger
在执行器阶段触发时,ResultRelInfo 结构体中存有表上的各项信息,其中就包括表上的触发器、函数等,所以直接从中就可以拿到触发器信息。关键结构体为 ResultRelInfo、TriggerDesc、Trigger,其嵌套关系如下:
将ResultRelInfo 中获取的 Trigger 结构体的全部内容都填充到 TriggerData 结构体,ExecCallTriggerFunc 函数再从 TriggerData 中获取函数 oid,并执行该函数。
TriggerData 结构体定义如下,其中除了 Trigger 以外还保存了各种执行上下文信息,heap 表信息等,rtsp源码与函数的执行有关。
TriggerData 最终会保存到PLpgSQL_execstate 中,这是 PLpgSQL 执行过程中的一个重要结构体:
触发器的功能函数执行的方法与普通的 PLpgSQL 函数、存储过程执行方法是类似的,关键调用路径是: ExecCallTriggerFunc-->plpgsql_call_handler-->plpgsql_exec_trigger-->exec_toplevel_block-->exec_stmt_block-->…………
Event Trigger
对于事件触发器,在触发阶段的EventTriggerCommonSetup 函数中,通过 EventCacheLookup 从缓存中查找触发器功能函数,然后在 EventTriggerInvoke 中根据触发器函数的 oid 进行调用。
EventTriggerCommonSetup 中还会填充 EventTriggerData 结构体,其中保存了调用过程中的一些关键信息:
与普通触发器的 TriggerData 结构一样,EventTriggerData 结构体也会保存到PLpgSQL_execstate 中,在 PLpgSQL 执行过程中使用:
事件触发器的功能函数实际执行步骤与普通触发器也基本相同,关键调用路径为: ExecCallTriggerFunc-->plpgsql_call_handler-->plpgsql_exec_event_trigger-->exec_toplevel_block-->exec_stmt_block-->…………
修改触发器
使用 ALTER 语句修改触发器的定义
Trigger
根据 PG 官方文档,ALTER TRIGGER 的语法如下:
仅支持重命名和修改依赖的插件。
重命名触发器的关键调用流程为:standard_ProcessUtility-->ExecRenameStmt-->renametrig,基本原理也是读取 pg_trigger 系统表的信息,修改以后写回系统表。
修改触发器依赖插件的关键调用流程为:standard_ProcessUtility-->ExecAlterObjectDependsStmt,会修改 pg_depend 系统表。
Event Trigger
根据 PG 官方文档,ALTER EVENT TRIGGER 语法为:
支持对事件触发器进行重命名、禁用、启用、修改 owner 的操作。
ALTER TRIGGER 的关键函数是AlterEventTrigger,其内容较为简单:
删除触发器
使用 DROP 语句删除触发器
Trigger
PG 文档中 DROP TRIGGER 语法如下:
删除触发器的关键函数是RemoveTriggerById,调用流程如下: ProcessUtilitySlow-->ExecDropStmt-->RemoveObjects-->performMultipleDeletions-->deleteObjectsInList-->deleteOneObject-->doDeletion-->RemoveTriggerById
RemoveTriggerById 函数流程:
Event Trigger
PG 文档中 DROP EVENT TRIGGER 语法如下:
删除事件触发器的关键函数是DropObjectById,这是一个公用的函数,可以删除多种类型的对象。
调用流程如下: ProcessUtilitySlow-->ExecDropStmt-->RemoveObjects-->performMultipleDeletions-->deleteObjectsInList-->deleteOneObject-->doDeletion-->DropObjectById
指标源码有什么用
指标源码的用途在于提供量化分析和决策支持。 指标源码是一种编程语言编写的程序代码,用于生成各种技术指标和统计信息。以下是关于指标源码作用的详细解释: 一、量化分析的核心工具 指标源码在量化分析中扮演着重要角色。通过编写特定的代码,可以获取股票、期货等金融市场的各种技术指标,如移动平均线、相对强弱指数等。这些指标有助于分析市场趋势、判断买卖时机,从而辅助投资者做出决策。 二、个性化定制分析策略 指标源码可以根据投资者的需求进行个性化定制。投资者可以根据自己的投资策略、风险偏好等因素,编写符合自身需求的指标代码。这样,投资者可以更加精准地捕捉市场机会,提高投资效率。 三、提高决策效率和准确性 通过指标源码,amcap 源码投资者可以快速生成大量的数据和分析结果,从而更加全面地了解市场状况。这对于需要快速响应市场变化的投资者来说,具有重要意义。此外,基于指标源码的分析结果,可以帮助投资者验证投资策略的有效性,从而提高决策的准确性。 四、技术研究和开发的重要资源 指标源码也是技术研究和开发的重要资源。通过对源码的研究,开发者可以了解各种技术指标的实现原理,从而进行更深入的技术研究和创新。这对于金融领域的科技进步和投资者福利的提升,具有积极的推动作用。 总之,指标源码在量化分析、个性化投资、决策支持以及技术研究和开发等方面都具有重要作用。它有助于投资者更深入地了解市场,提高投资决策的效率和准确性。Kswapd 源码解析
kswapd是Linux内核中的一个内存回收线程,主要用于内存不足时回收内存。初始化函数为kswapd_init,内核为每个节点分配一个kswapd进程。每个节点的pg_data_t结构体中维护四个成员变量,用于管理kswapd线程。
在初始化后,每个节点的kswapd线程进入睡眠状态。唤醒时机主要在被动唤醒和主动唤醒两种场景:被动唤醒是内存分配进程唤醒并完成异步内存回收后,对节点内存环境进行平衡度检查,若平衡则线程短暂休眠ms后主动唤醒。主动唤醒是内存回收策略调用kswapd,对节点进行异步内存回收,让节点达到平衡状态。
内存回收包括快速和直接两种方式,但系统周期性调用kswapd线程平衡不满足要求的节点,因为有些任务内存分配不允许阻塞或激活I/O访问,回收内存相当于亡羊补牢,系统利用空闲时间进行内存回收是必要的。
kswapd线程通过module_init(kswapd_init)创建,一般处于睡眠状态等待被唤醒,当系统内存紧张时,会唤醒kswapd线程,调整不平衡节点至平衡状态。
kswapd函数包含alloc_order、reclaim_order和classzone_idx三个变量,用于控制线程执行流程。kswapd_try_to_sleep函数判断是否睡眠并让出CPU控制权,同时是线程唤醒的入口。balance_pgdat函数是实际内存回收操作,涉及内存分配失败后唤醒kswapd线程,调用此函数对指定节点进行异步内存回收。
kswapd_shrink_node函数通过shrink_node对低于sc->reclaim_idx的非平衡zone区域进行回收。
总结kswapd执行流程,其生命周期与Linux操作系统相似,平时处于睡眠状态让出CPU控制权。在内存紧张时被唤醒,有被动唤醒和周期性主动唤醒两种时机。被动唤醒发生在内存分配任务获取不到内存时,表明系统内存环境紧张,主动唤醒则是内存回收策略的执行。线程周期性唤醒在被动唤醒后的短暂时间内,原因在于系统内存环境紧张,需要在这段时间内进行内存回收。
通达信周期共振MACD指标公式源码副图
在技术分析中,通达信周期共振MACD指标是一个强大的工具,通过结合不同周期的快慢线和信号线,帮助投资者捕捉买卖时机。以下是指标的核心公式和副图的源码解读:</ DIFM:</Ema(C,)- EMA(C,),这是月线周期的DIF(快速移动平均线与慢速移动平均线之差),它用绿色显示,表示长期趋势的潜在变化。 DEAM:</EMA(DIFM,),对DIFM进行周期的平滑处理,为月线MACD线提供稳定的支持,以**显示。 MACD(月):</(DIFM-DEAM)/2,月线MACD值,通过计算DIFM与DEAM的差值除以2,显示月线趋势的强度,以**虚线形式呈现。 DIFW:</EMA(CLOSE,)- EMA(CLOSE,),这是周线的DIF,以蓝色粗线展示,反映短期波动情况。 DEAW:</EMA(DIFW,),对DIFW进行周期平滑处理,为周线MACD提供指导,以**显示。 MACD(周):</(DIFW-DEAW)*2,周线MACD值,通过放大DIFW与DEAW的差值,为交易者提供更精细的短期信号,以**实线呈现。 DIFD:</EMA(C,)- EMA(C,),日线DIF,用紫色细线表示,是快速与慢速日线移动平均线的差异,是短期波动的敏感指标。 DEAD:</EMA(DIFD,9),对DIFD进行9周期平滑处理,形成日线MACD的信号线,以蓝色粗线展示。 MACD(日):</(DIFD-DEAD)*2,日线MACD值,通过调整DIFD与DEAD的差值,揭示日内的买卖信号,以红色虚线显示。 副图可视化:</通过STICKLINE函数,MACD(月)、MACD(周)和MACD(日)以不同粗细和颜色的线条,直观地呈现不同周期的共振效果。 信号判断:</短期安全线:MACD(日)>REF(MACD(日),1) AND MACD(周)>REF(MACD(周),1),当日线和周线同时上穿前一交易日的值,发出买入信号,用红色表示。 短期风险:</(短期安全!=1),当短期安全线不成立时,提示可能存在风险,以白色表示。 中期安全线:</MACD(周)>REF(MACD(周),1) AND MACD(月)>REF(MACD(月),1),周线与月线同时上穿,为中期看涨信号,用蓝紫色表示。 中期风险:</(中期安全!=1),当中期安全线不成立时,表明中期趋势可能反转,以绿色显示。 辅助线:</DIF2线(紫色细线)显示日线DIFD,DIF1线(红色细线)根据短期安全信号调整,DEA1线(绿色粗线)代表DEAD线,DEA2线(蓝紫色粗线)根据中期安全信号调整。 通过这些公式和图形,投资者可以更全面地解读通达信周期共振MACD指标,从而在交易决策中得到有力的支撑。务必结合市场实际情况和图表走势,灵活运用。UOS终极波动指标源码的组成要素:综合三个不同周期的RSI
在金融市场投资中,捕捉价格趋势转折点与波动变化是至关重要的。UOS终极波动指标,由拉里·威廉姆斯创造,综合三个不同周期的相对强弱指标(RSI),通过计算其加权平均值,更准确地反映市场动态。UOS指标的金叉和死叉是交易信号的关键依据,分别表示买入与卖出时机。超买超卖区域则帮助投资者识别市场状态,当数值超过或低于特定阈值时,可能出现调整或反转。使用UOS指标时,建议结合主图分析以提升决策稳健性。以下为UOS指标的源码,适用于文华6、7、8等软件,仅供策略思路拓展,投资需谨慎。
N1:=5;
N2:=;
N3:=;
M:=;
HH:=MAX(HIGH,REF(CLOSE,1));
LL:=MIN(LOW,REF(CLOSE,1));
AA:=SUM(CLOSE-LL,N1)/SUM(HH-LL,N1);
BB:=SUM(CLOSE-LL,N2)/SUM(HH-LL,N2);
CC:=SUM(CLOSE-LL,N3)/SUM(HH-LL,N3);
UOS:(AA/N1+BB/N2+CC/N3)*N1*N2*N3/(N1*N2+N2*N3+N1*N3)*;
MUOS:EMA(UOS,M);
;
;
;
通达信缠论笔买卖点指标公式源码
通达信缠论笔买卖点指标的源码如下:
首先,我们定义几个基础指标:
PL5通过ZIG(3,5)函数计算,颜色为AAAAAA。PL5的移动值PL5:=ZIG(3,5);
EN1和EX1分别判断ZIG(3,5)的三个连续时段的上升趋势,EN1表示上升且前一周期持平,EX1表示ZIG(3,5)等于前一周期值。EN1的计算条件是ZIG(3,5)>REF(ZIG(3,5),1)且前一周期值在第三周期和第二周期之间。
PL、EN2、EX2和PL等指标分别基于更长的周期,用于识别更长期的趋势。
走强和走弱的判断使用BARSLAST函数,分别记录PL5、PL、PL达到相应条件的周期数。
接着,ZTJZ5、ZTJD5、DTJZ5和DTJD5是基于PL的买卖点计数,分别对应不同的趋势和条件组合。
对于PL和EX2,我们同样计算ZTJZ、ZTJD、DTJZ和DTJD,用于更长周期的买卖点标记。
最后,通过DRAWTEXT函数在图表上显示买卖点的标记,如"(Ⅰ)"、"(Ⅱ)"、"(Ⅲ)"、"⑴"、"⑵"等,颜色各异,帮助用户识别关键的买卖时机。
整体来说,这个源码是缠论技术在通达信软件中的具体实现,通过一系列的计算和标记,帮助交易者分析股票的买卖点。"A"、"B"和"C"标识可能的转折点,而"①"到"④"则代表不同类型的买卖信号。
vue3.2 源码浅析:watch、watchEffect、computed区别
要理解Vue 3.2中watch、watchEffect、computed三者的区别,首先需要明确依赖收集和回调函数的概念。Vue应用启动时,会进行初始化操作,期间进行依赖收集;初始化结束后,用户修改响应式数据时,会触发回调函数。
watchEffect()参数中的effect函数在应用启动期间会执行一次,进行依赖收集。watch()参数中的cb函数在应用启动期间默认不会执行,除非更改watch参数中的option值,使得两者等效。
在初始化期间,computed()返回值被引用时,参数中的{ get}函数会执行;未被引用则不执行。这体现了computed()与watch、watchEffect的另一个区别。
从执行时机上看,当被监听数据的值发生改变,computed()的回调函数会立即执行。watch()和watchEffect()的回调函数执行时机由option参数中的{ flush?: 'pre' | 'post' | 'sync' }决定。
此外,computed()有返回值,并且返回值也会被监听;而watch()和watchEffect()没有返回值。
接着,从源码的角度分析,无论是watch()还是watchEffect(),其实现都是通过调用doWatch()函数完成的。doWatch()函数创建依赖收集函数getter,创建调度函数scheduler,然后创建ReactiveEffect,并进行依赖收集。当修改被监听数据时,会触发schedule函数,根据{ flush}决定回调函数的执行时机。
对于computed(),其源码从参数的option中获取getter和setter函数,返回一个ComputedRefImpl类型的对象。在构造函数中创建effect对象,但不进行依赖收集。依赖收集工作在调用get value()时完成。首次调用get value()后,修改被监听数据,会触发triggerRefValue(this),进而通过get value()计算返回值。
综上所述,了解Vue 3.2中watch、watchEffect、computed的区别,需要从原理和源码两方面入手。掌握这些知识点,有助于更深入地理解Vue的响应式系统和数据监听机制。
Vue3源码系列 (四) ref
一般而言,reactive用于定义响应式对象,而ref则用于定义响应式原始值。前文已介绍reactive,了解到通过Proxy对目标对象进行代理实现响应式,非对象原始值的响应式问题则由ref解决。
ref和shallowRef各有三种重载,参数不同,都返回Ref/ShallowRef类型的值。createRef函数用于创建响应式值,类似reactive,createRef也是通过createReactiveObject创建响应式对象。而createRef返回RefImpl实例。
RefImpl是ref的核心内容,构造函数接收两个参数,value是传入的原始值,__v_isShallow用于区分深层/浅层响应式,isShallow()函数利用这个属性做判断。在Ref中,_value属性存储实际值,dep属性存储依赖,在class的getter中通过trackRefValue(this)收集依赖,在setter中调用triggerRefValue(this, newVal)。
trackRefValue用于收集Ref依赖,接收RefBase类型值,在ref函数中接收RefImpl实例。shouldTrack用于暂停和恢复捕获依赖的标志,activeEffect标记当前活跃的effect。内部调用trackEffects函数收集依赖,该函数来自effect模块。
triggerRefValue函数用于触发Ref的响应式更新,triggerEffects函数来自effect模块。
Vue3还提供了自定义的Ref,可以传入getter和setter,自由选择track和trigger时机。
在setup函数中返回参数时,使用toRef创建ObjectRefImpl实例对响应式对象的某个属性进行解构。
ObjectRefImpl通过_object属性引用原始响应式对象,在getter中通过_object访问值,依赖收集由_object完成;在setter中,通过引用_object达到赋值操作,从而在_object中触发更新。toRef判断入参是否是Ref,是则直接返回,否则返回ObjectRefImpl。toRefs对传入的对象/数组进行遍历并执行toRef解构。