PostgreSQL的学习心得和知识总结(一百四十)|深入理解PostgreSQL数据库 psql工具 \set 变量内部及HOOK机制


注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《PostgreSQL数据库内核分析》
2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》
3、PostgreSQL数据库仓库链接,点击前往
4、日本著名PostgreSQL数据库专家 铃木启修 网站主页,点击前往
5、参考书籍:《PostgreSQL中文手册》
6、参考书籍:《PostgreSQL指南:内幕探索》,点击前往
7、参考书籍:《事务处理 概念与技术》


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)
5、本文内容基于PostgreSQL master源码开发而成


深入理解PostgreSQL数据库 psql工具 \set 变量内部及HOOK机制

  • 文章快速说明索引
  • 功能使用背景说明
    • 背景
  • 功能使用源码解析
    • ECHO_HIDDEN
    • HIDE_TABLEAM
    • HOOK 机制
    • 设置新的变量



文章快速说明索引

学习目标:

做数据库内核开发久了就会有一种 少年得志,年少轻狂 的错觉,然鹅细细一品觉得自己其实不算特别优秀 远远没有达到自己想要的。也许光鲜的表面掩盖了空洞的内在,每每想到于此,皆有夜半临渊如履薄冰之感。为了睡上几个踏实觉,即日起 暂缓其他基于PostgreSQL数据库的兼容功能开发,近段时间 将着重于学习分享Postgres的基础知识和实践内幕。


学习内容:(详见目录)

1、PostgreSQL数据库 psql工具 \set 变量内部及HOOK机制


学习时间:

2024年04月29日 21:24:00


学习产出:

1、PostgreSQL数据库基础知识回顾 1个
2、CSDN 技术博客 1篇
3、PostgreSQL数据库内核深入学习


注:下面我们所有的学习环境是Centos8+PostgreSQL master +Oracle19C+MySQL8.0

postgres=# select version();
                                                  version                                                   
------------------------------------------------------------------------------------------------------------
 PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21), 64-bit
(1 row)

postgres=#

#-----------------------------------------------------------------------------#

SQL> select * from v$version;          

BANNER        Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
BANNER_FULL	  Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production Version 19.17.0.0.0	
BANNER_LEGACY Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
CON_ID 0


#-----------------------------------------------------------------------------#

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.06 sec)

mysql>

功能使用背景说明

背景

首先看一下示例1(ECHO_HIDDEN),如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.

postgres=# \echo :ECHO_HIDDEN
off
postgres=# \set ECHO_HIDDEN on
postgres=# 
postgres=# \d
/******** QUERY *********/
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
     LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam
WHERE c.relkind IN ('r','p','v','m','S','f','')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname !~ '^pg_toast'
      AND n.nspname <> 'information_schema'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
/************************/

        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | t1   | table | postgres
(1 row)

postgres=# \d+
/******** QUERY *********/
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner",
  CASE c.relpersistence WHEN 'p' THEN 'permanent' WHEN 't' THEN 'temporary' WHEN 'u' THEN 'unlogged' END as "Persistence",
  am.amname as "Access method",
  pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as "Size",
  pg_catalog.obj_description(c.oid, 'pg_class') as "Description"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
     LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam
WHERE c.relkind IN ('r','p','v','m','S','f','')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname !~ '^pg_toast'
      AND n.nspname <> 'information_schema'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
/************************/

                                     List of relations
 Schema | Name | Type  |  Owner   | Persistence | Access method |    Size    | Description 
--------+------+-------+----------+-------------+---------------+------------+-------------
 public | t1   | table | postgres | permanent   | heap          | 8192 bytes | 
(1 row)

postgres=#

同样是这个会话,接着执行示例2(HIDE_TABLEAM),如下:

postgres=# \echo :HIDE_TABLEAM
off
postgres=# \set HIDE_TABLEAM on
postgres=# 
postgres=# \d+
/******** QUERY *********/
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner",
  CASE c.relpersistence WHEN 'p' THEN 'permanent' WHEN 't' THEN 'temporary' WHEN 'u' THEN 'unlogged' END as "Persistence",
  pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as "Size",
  pg_catalog.obj_description(c.oid, 'pg_class') as "Description"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','p','v','m','S','f','')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname !~ '^pg_toast'
      AND n.nspname <> 'information_schema'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
/************************/

                             List of relations
 Schema | Name | Type  |  Owner   | Persistence |    Size    | Description 
--------+------+-------+----------+-------------+------------+-------------
 public | t1   | table | postgres | permanent   | 8192 bytes | 
(1 row)

postgres=#

以及示例3,如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.

postgres=# \echo :me
:me
postgres=# 
postgres=# \set me songbaobao
postgres=# 
postgres=# \echo :me
songbaobao
postgres=#

功能使用源码解析

ECHO_HIDDEN

首先,我们先看一下示例1的内部实现,通常下 元命令执行,如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.

postgres=# \d
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | t1   | table | postgres
(1 row)

postgres=#

其内部解析之后,就是 如下执行:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.

postgres=# SELECT n.nspname as "Schema",
postgres-#   c.relname as "Name",
postgres-#   CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as "Type",
postgres-#   pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
postgres-# FROM pg_catalog.pg_class c
postgres-#      LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
postgres-#      LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam
postgres-# WHERE c.relkind IN ('r','p','v','m','S','f','')
postgres-#       AND n.nspname <> 'pg_catalog'
postgres-#       AND n.nspname !~ '^pg_toast'
postgres-#       AND n.nspname <> 'information_schema'
postgres-#   AND pg_catalog.pg_table_is_visible(c.oid)
postgres-# ORDER BY 1,2;
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | t1   | table | postgres
(1 row)

postgres=#

而内部打印的逻辑,如下:

在这里插入图片描述


HIDE_TABLEAM

该参数默认情况下是关闭的,如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.

postgres=# \echo :HIDE_TABLEAM
off
postgres=# \d+
                                     List of relations
 Schema | Name | Type  |  Owner   | Persistence | Access method |    Size    | Description 
--------+------+-------+----------+-------------+---------------+------------+-------------
 public | t1   | table | postgres | permanent   | heap          | 8192 bytes | 
(1 row)

postgres=#

在上面示例2中可以发现,HIDE_TABLEAM = on 的情况下,将不再查询输出Access method,如下:

在这里插入图片描述

两者的差异,如下:

在这里插入图片描述


HOOK 机制

元命令\set变量内部也有一套自己的HOOK机制,如下:

// src/bin/psql/variables.h

/*
 * Data structure representing one variable.
 * 代表一个变量的数据结构
 *
 * Note: if value == NULL then the variable is logically unset, but we are
 * keeping the struct around so as not to forget about its hook function(s).
 * 注意:如果 value == NULL 则该变量在逻辑上未设置,但我们保留该结构以免忘记其钩子函数
 */
struct _variable
{
	char	   *name;
	char	   *value;
	VariableSubstituteHook substitute_hook;
	VariableAssignHook assign_hook;
	struct _variable *next;
};

下面分别看一下这两个Hook,如下:

/*
 * Variables can be given "assign hook" functions.  The assign hook can
 * prevent invalid values from being assigned, and can update internal C
 * variables to keep them in sync with the variable's current value.
 * 变量可以被赋予“分配钩子”函数
 * 分配挂钩可以防止分配无效值,并且可以更新内部 C 变量以使其与变量的当前值保持同步
 *
 * An assign hook function is called before any attempted assignment, with the
 * proposed new value of the variable (or with NULL, if an \unset is being
 * attempted).  If it returns false, the assignment doesn't occur --- it
 * should print an error message with pg_log_error() to tell the user why.
 * 在任何尝试分配之前都会调用分配钩子函数,并使用建议的变量新值(或者如果正在尝试 \unset,则使用 NULL)
 * 如果它返回 false,则分配不会发生 --- 它应该使用 pg_log_error() 打印一条错误消息来告诉用户原因
 *
 * When an assign hook function is installed with SetVariableHooks(), it is
 * called with the variable's current value (or with NULL, if it wasn't set
 * yet).  But its return value is ignored in this case.  The hook should be
 * set before any possibly-invalid value can be assigned.
 * 当使用 SetVariableHooks() 安装分配挂钩函数时,将使用变量的当前值(如果尚未设置,则使用 NULL)调用它
 * 但在这种情况下它的返回值被忽略
 * 应在分配任何可能无效的值之前设置挂钩
 */
typedef bool (*VariableAssignHook) (const char *newval);
/*
 * Variables can also be given "substitute hook" functions.  The substitute
 * hook can replace values (including NULL) with other values, allowing
 * normalization of variable contents.  For example, for a boolean variable,
 * we wish to interpret "\unset FOO" as "\set FOO off", and we can do that
 * by installing a substitute hook.  (We can use the same substitute hook
 * for all bool or nearly-bool variables, which is why this responsibility
 * isn't part of the assign hook.)
 * 变量也可以被赋予“替代钩子”函数
 * 替代钩子可以用其他值替换值(包括 NULL),从而允许变量内容规范化
 * 例如,对于布尔变量,我们希望将“\unset FOO”解释为“\set FOO off”,我们可以通过安装替代钩子来做到这一点
 * (我们可以对所有布尔或近布尔变量使用相同的替代钩子,这就是为什么此责任不是分配钩子的一部分)
 *
 * The substitute hook is called before any attempted assignment, and before
 * the assign hook if any, passing the proposed new value of the variable as a
 * malloc'd string (or NULL, if an \unset is being attempted).  It can return
 * the same value, or a different malloc'd string, or modify the string
 * in-place.  It should free the passed-in value if it's not returning it.
 * The substitute hook generally should not complain about erroneous values;
 * that's a job for the assign hook.
 * 在任何尝试分配之前以及分配钩子(如果有)之前调用替代钩子,将变量的建议新值作为 malloc 字符串传递(或 NULL,如果正在尝试 \unset)
 * 它可以返回相同的值,或不同的 malloc 字符串,或就地修改字符串
 * 如果它不返回传入的值,它应该释放它
 * 替代钩子通常不应该抱怨错误的值;这是分配钩子的工作
 *
 * When a substitute hook is installed with SetVariableHooks(), it is applied
 * to the variable's current value (typically NULL, if it wasn't set yet).
 * That also happens before applying the assign hook.
 * 当使用 SetVariableHooks() 安装替代钩子时,它将应用于变量的当前值(通常为 NULL,如果尚未设置)
 * 这也会发生在应用分配挂钩之前
 */
typedef char *(*VariableSubstituteHook) (char *newval);

下面我们来看一个简单的例子,如下:

// src/bin/psql/startup.c

static void
EstablishVariableSpace(void)
{
	pset.vars = CreateVariableSpace();

	SetVariableHooks(pset.vars, "AUTOCOMMIT",
					 bool_substitute_hook,
					 autocommit_hook);
	...
	SetVariableHooks(pset.vars, "HIDE_TABLEAM",
					 bool_substitute_hook,
					 hide_tableam_hook);
}
/*
 * Substitute hooks and assign hooks for psql variables.
 * 用钩子替换 psql 变量并为 psql 变量分配钩子
 *
 * This isn't an amazingly good place for them, but neither is anywhere else.
 * 这对他们来说不是一个令人惊奇的好地方,但其他地方也不是
 *
 * By policy, every special variable that controls any psql behavior should
 * have one or both hooks, even if they're just no-ops.  This ensures that
 * the variable will remain present in variables.c's list even when unset,
 * which ensures that it's known to tab completion.
 * 根据策略,控制任何 psql 行为的每个特殊变量都应该有一个或两个钩子,即使它们只是无操作
 * 这确保了即使未设置,变量也将保留在 Variables.c 的列表中,从而确保知道它可以完成 Tab 键补全
 */

static char *
bool_substitute_hook(char *newval)
{
	if (newval == NULL)
	{
		/* "\unset FOO" becomes "\set FOO off" */
		newval = pg_strdup("off");
	}
	else if (newval[0] == '\0')
	{
		/* "\set FOO" becomes "\set FOO on" */
		pg_free(newval);
		newval = pg_strdup("on");
	}
	return newval;
}
static bool
autocommit_hook(const char *newval)
{
	return ParseVariableBool(newval, "AUTOCOMMIT", &pset.autocommit);
}

...

static bool
hide_tableam_hook(const char *newval)
{
	return ParseVariableBool(newval, "HIDE_TABLEAM", &pset.hide_tableam);
}

在这里插入图片描述


设置新的变量

在这里插入图片描述

此时的函数堆栈,如下:

SetVariable(VariableSpace space, const char * name, const char * value) (\home\postgres\postgres\src\bin\psql\variables.c:289)
exec_command_set(PsqlScanState scan_state, _Bool active_branch) (\home\postgres\postgres\src\bin\psql\command.c:2406)
exec_command(const char * cmd, PsqlScanState scan_state, ConditionalStack cstack, PQExpBuffer query_buf, PQExpBuffer previous_buf) (\home\postgres\postgres\src\bin\psql\command.c:395)
HandleSlashCmds(PsqlScanState scan_state, ConditionalStack cstack, PQExpBuffer query_buf, PQExpBuffer previous_buf) (\home\postgres\postgres\src\bin\psql\command.c:231)
MainLoop(FILE * source) (\home\postgres\postgres\src\bin\psql\mainloop.c:496)
main(int argc, char ** argv) (\home\postgres\postgres\src\bin\psql\startup.c:462)

接下来,echo输出 如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/583577.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【能力展现】魔改ZXING源码实现商业级DM码检测能力

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; 什么是DM码 dataMatrix是一种二维码&#xff0c;原名datacode&#xff0c;由美国国际资料公司于1989年发明。dataMatrix二维码…

GuildFi升级为Zentry的背后 链游公会的探索与转型

​链游即区块链游戏&#xff0c;指依托区块链技术构建的游戏产品。其与传统游戏的最大区别在于区块链的去中心化特性对玩家的资产有着天然的确权行为&#xff0c;因此玩家在链游中的资产是作为玩家的个人资产存在。较于 GameFi 来说&#xff0c;链游的包含范围更大&#xff0c;…

吴恩达机器学习笔记:第 8 周-14降维(Dimensionality Reduction) 14.3-14.5

目录 第 8 周 14、 降维(Dimensionality Reduction)14.3 主成分分析问题14.4 主成分分析算法14.5 选择主成分的数量 第 8 周 14、 降维(Dimensionality Reduction) 14.3 主成分分析问题 主成分分析(PCA)是最常见的降维算法。 在 PCA 中&#xff0c;我们要做的是找到一个方向…

【高校科研前沿】华东师大白开旭教授博士研究生李珂为一作在RSE发表团队最新成果:基于波谱特征优化的全球大气甲烷智能反演技术

文章简介 论文名称&#xff1a;Developing unbiased estimation of atmospheric methane via machine learning and multiobjective programming based on TROPOMI and GOSAT data&#xff08;基于TROPOMI和GOSAT数据&#xff0c;通过机器学习和多目标规划实现大气甲烷的无偏估…

OS复习笔记ch5-1

引言 讲解完进程和线程之后&#xff0c;我们就要来到进程的并发控制这里&#xff0c;这一章和下一章是考试喜欢考察的点&#xff0c;有可能会出大题&#xff0c;面试也有可能会被频繁问到&#xff0c;所以章节内容较多。请小伙伴们慢慢食用&#xff0c;看完之后多思考加强消化…

【JPE】顶刊测算-工业智能化数据(附stata代码)

数据来源&#xff1a;国家TJ局、CEC2008、IFR数据 时间跨度&#xff1a;2006-2019年 数据范围&#xff1a;各省、地级市 数据指标&#xff1a; 本数据集展示了2006-2019年各省、各地级市的共工业智能化水平的数据。本数据集包含三种构建工业机器人密度来反映工业智能化水平的方…

基于Springboot的数字化农家乐管理平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的数字化农家乐管理平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

Apache Seata基于改良版雪花算法的分布式UUID生成器分析2

title: 关于新版雪花算法的答疑 author: selfishlover keywords: [Seata, snowflake, UUID, page split] date: 2021/06/21 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 关于新版雪花算法的答疑 在上一篇关于新版雪花算法的解析中…

web前端学习笔记4

4. 盒子模型 4.0 代码地址 https://gitee.com/qiangge95243611/java118/tree/master/web/day044.1 什么是盒子模型(Box Model) 所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。 CSS盒模型本质上是一个盒子,封装周围的HTML元素,…

在Docker中部署Java应用:Java版本隔离的实践案例

在Docker中部署Java应用&#xff1a;Java版本隔离的实践案例 人生就是一场又一场的相遇&#xff0c;一个明媚&#xff0c;一个忧伤&#xff0c;一个华丽&#xff0c;一个冒险&#xff0c;一个倔强&#xff0c;一个柔软&#xff0c;最后那个正在成长。 背景需求 在软件开发和部…

Debian 12 -bash: netstat: command not found 解决办法

问题表现&#xff1a; debian 12系统中&#xff0c;不能使用 netstat命令 处理办法&#xff1a; netstat 命令就的net-tools中&#xff0c;把net-tools工具安装上就好了。 apt-get install netstat 安装之后就可以使用netstat 命令了&#xff0c;如查询端口情况&#xff1a; …

基于SpringBoot+Vue高校宣讲会管理系统设计与实现

项目介绍&#xff1a; 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装高校宣讲会管理系统软件来发挥其高效地信息…

C# Web控件与数据感应之 Control 类

目录 关于数据感应 Control 类 范例运行环境 simpleDataListEx方法 设计 实现 调用示例 数据源 调用 小结 关于数据感应 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;Web控件与数据源之间的交互&#xff0c;诸如 ListControl 类类型控件&#xff0c;在…

pytest教程-35-钩子函数-pytest_unconfigure

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_configure钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_unconfigure钩子函数的使用方法。 pytest_unconfigure(config) 是一个 pytest 钩子函数&#xff0c;它在 pytest 退…

【linux运维】vim基础应用

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了学习基本的shell编程和linux命令&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于b站大学——linux运维课程进行的&#xff0c;…

【MHA】MySQL高可用MHA源码1-主库故障监控

1 阅读之前的准备工作 1 一个IDE工具 &#xff0c;博主自己尝试了vscode安装perl的插件&#xff0c;但是函数 、变量 、模块等都不能跳转&#xff0c;阅读起来不是很方便。后来尝试使用了pycharm安装perl插件&#xff0c;阅读支持跳转&#xff0c;自己也能写一些简单的测试样例…

[iOS]组件化开发

一、组件化开发基础 1.组件定义 在软件开发中&#xff0c;一个组件是指一个独立的、可替换的软件单元&#xff0c;它封装了一组相关的功能。组件通过定义的接口与外界交互&#xff0c;并且这些接口隔离了组件内部的实现细节。在Swift语言中&#xff0c;组件可以是一个模块、一…

CCF-CSP真题题解:201312-2 ISBN号码

201312-2 ISBN号码 #include <iostream> #include <cstring> #include <algorithm> using namespace std;string s;int main() {cin >> s;int num 0;for (int i 0, p 1; i < s.size() - 1; i)if (s[i] ! -) {num (s[i] - 0) * p;p;}num % 11;ch…

win11 自带分区磁盘管理,右键U盘 删除卷,显示不支持该请求

win11 自带分区磁盘管理&#xff0c;右键U盘 删除卷&#xff0c;显示不支持该请求&#xff0c;打开cmd 输入下面命令 1.diskpart 2.list disk 3.sel disk (U盘盘符编号) 4.clean

Linux vi\vim编辑器

vi/vim编辑器 一、vi\vim 编辑器的三种工作模式1.命令模式&#xff08;Command mode&#xff09;2.输入模式&#xff08;Insert mode&#xff09;3.底线命令模式&#xff08;Last line mode&#xff09; 二、参考 vi\vim 是 visual interface 的简称&#xff0c;是 Linux 中最经…