Wsl 常见问题记录

wsl 使用种简单的问题记录
Read more →

orca 简记

docker GreenPlum 源码编译
Read more →

Postgres Hash Join

Postgre hash join 总结
Read more →

源码编译 OpenTenBase 速通版

docker OpenTenBase 源码编译
Read more →

cmake 速查模板

cmake 速查模板,自用
Read more →

gdb 要点简记

gdb 中的一些常用方法,一些常用的命令,记忆 gdb 的 python 扩展的使用方法
Read more →

Postgres 技术内幕,Optimizer过程分析

深度优化探索文章的读书笔记
Read more →

宏使用模板速查

宏模板,自用
Read more →

执行计划代价计算规则梳理

pg中各个算子的代价计算
Read more →

Postgres Executor

Postgres 执行器 及其扩展 总结
Read more →

事务知识简记

事务分析记录,源码分析,关键技术点简记,唬人专用
Read more →

Bison Note

bison 文档重点记录
Read more →

Libpqxx

libpqxx分析
Read more →

内存管理

Read more →

RocksDB源码分析

RocksDB 源码总结分析
Read more →

postgres Parser

Postgres parser 模块解析,目的是为了学习parser实现机制。编译原理以及bison和flex的使用
Read more →

Locks

PG 中锁的分析
Read more →

vacuum 和 analyze 过程分析

AntDB VACUUM 流程
Read more →

Postgres Optimizer

本文从源码级别进行优化器的分析,对Postgres优化器代码调研,具体包括他的数据结构,以及具体的代码架构实现以及核心算法等
Read more →

Postgres Storage

存储 # 内存 # 共享内存 本地内存 缓存 内存上下文 缓存空间管理 数据块的缓存,减少磁盘IO,有共享缓存和进程缓存 Cache 数据块之外的缓存,例如系统表 系统表缓存不会缓存整个表,是以block为单位缓存? 虚拟文件描述符 系统中文件有打开的上限,使用VFD可以突破这种限制,本质上是一个LRU缓存 空闲空间定位 快速定位磁盘中的空闲空间以插入数据 进程间通信 使用共享内存或者信号量通信 读取过程 # 从系统表中读取表的元数据信息构造元组信息 尝试从缓存读取数据 使用SMGR从磁盘读取数据到缓存中,SMGR是一个抽象层,用于实现不同存储介质的管理 SMGR和存储介质之间使用VFD来管理文件描述符,以突破系统的FD限制 标记删除,vacuum清理数据 FSM记录空闲空间 磁盘 # 表文件 SMGR VFD FSM select * from pg_relation_filepath(‘idx’); Page 结构 # 工具汇总说明 create extension pageinspect; get_raw_page(relname text, fork text, blkno int) 返回执行表的page,text指定类型,默认是main,代表普通page,使用fsm或者vm查看其他类型,可以省略 page_header(page bytea) 查看page头,输入是page数组,使用上面的函数的输出作为参数 fsm_page_contents(page bytea) returns text 查看fsm页面结构 SELECT fsm_page_contents(get_raw_page('t1', 'fsm', 0)); === HEAP相关 heap_page_items(page bytea) 查看page的具体信息 heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer) returns record 查看mask的具体含义,具体的使用方法为 SELECT * FROM heap_page_items(get_raw_page('a', 0)), LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) WHERE t_infomask IS NOT NULL OR t_infomask2 IS NOT NULL order by lp desc; 输出为 t_infomask2 | t_infomask | t_hoff | t_bits | t_oid | t_data | raw_flags | combined_flags -------------+------------+--------+----------+-------+------------+--------------------------------------------------------------------------+---------------- 3 | 2305 | 24 | 10000000 | | \x02000000 | {HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID} | {} 8195 | 1281 | 24 | 10000000 | | \x01000000 | {HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_KEYS_UPDATED} | {} 主要目的是查看数据的mask的信息 === Btree相关 bt_metap(relname text) 查看btree元数据信息 bt_page_stats(relname text, blkno int) 查看btree page的统计信息 bt_page_items(relname text, blkno int) 或者 bt_page_items(page bytea) returns setof record 查看具体的信息,可以指定index或者直接使用page byte typedef struct PageHeaderData { /* XXX LSN is member of *any* block, not only page-organized ones */ PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog record for last change to this page */ uint16 pd_checksum; /* checksum */ uint16 pd_flags; /* flag bits, see below */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */ } PageHeaderData; void PageInit(Page page, Size pageSize, Size specialSize) { PageHeader p = (PageHeader) page; specialSize = MAXALIGN(specialSize); Assert(pageSize == BLCKSZ); Assert(pageSize > specialSize + SizeOfPageHeaderData); /* Make sure all fields of page are zero, as well as unused space */ MemSet(p, 0, pageSize); p->pd_flags = 0; p->pd_lower = SizeOfPageHeaderData; p->pd_upper = pageSize - specialSize; p->pd_special = pageSize - specialSize; PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION); /* p->pd_prune_xid = InvalidTransactionId; done by above MemSet */ } 大小为 pageSize,默认为8k,最开始是PageHeader,
Read more →

数据库文章资源汇总

爬虫 # import requests from bs4 import BeautifulSoup prefix = 'http://mysql.taobao.org' # 获取文章名和url(文章名,url) def query_name_url(url: str): resp = requests.get(url) soup = BeautifulSoup(resp.content.decode('utf-8'), "html.parser") tags = soup.findAll('a', {'target': {'_top'}}) urls = [v for v in tags if v['href'].find('/monthly/') != -1] return [(str(v.string).strip(), prefix + v['href']) for v in urls] # 获取所有月报链接(月报名,url) def query_monthly_url(): resp = requests.get('http://mysql.taobao.org/monthly/') soup = BeautifulSoup(resp.content.decode('utf-8'), "html.parser") tags = soup.findAll('a', {'class': {'main'}}) urls = [v for v in tags if v['href'].find('/monthly/') != -1] return [(str(v.string).strip(), prefix + v['href']) for v in urls] # 获取所有文章名、URL和对应的月报链接(文章类型,文章名,url,月报名,url) def query_all_name_url(): result = [] monthly_urls = query_monthly_url() for data1 in monthly_urls: name_urls = query_name_url(data1[1]) for data2 in name_urls: result.
Read more →

15445课程笔记

https://15445.courses.cs.cmu.edu/fall2021/notes/02-advancedsql.pdf output control 控制输出结果,例如order,limit等 窗口函数 CTE Common Table Expressions,把一个语句的输出视为一张临时表参与下面的语句的运算 WITH cte1 (col1) AS (SELECT 1), cte2 (col2) AS (SELECT 2) SELECT * FROM cte1, cte2; Database Storage # 数据库的存储介质当前还是磁盘,IO慢 数据库存储要点之一是使用缓存维护数据在磁盘和内存之间的数据交换,以实现数据的快速读写 顺序读写和随机读写 顺序读写的意思是需要定位到读写的位置才能操作,例如链表。 随机读写的意思是可以直接定位到读写的位置,例如数组。 由于磁盘上随机读写速度不如顺序读写,所以当前数据库还是需要想办法使用顺序读写,例如LSM,GFS等架构都是因为这个原因导致的 磁盘和内存中数据的组织格式 # 数据全部在磁盘上,按page组织数据,内存中使用buffer pool维护缓存,磁盘中有一个page专门维护page的位置信息,使用的时候先读取此page到内存,然后 然后读取其他page到buffer pool,使用buffer pool维护page的置换情况,例如LRU,或者其他算法 可以参考lab1和slide,还是比较明显的 buffer pool中的page可以用于上层的数据运算 使用mmap可以完成类似的操作,但是实际上在使用中,如果在发生缺页中断的时候,mmap需要进行置换操作,所以会阻碍程序进程。且mmap是通用的组件,所以没有对数据库 的使用场景进行一些优化, You never want to use mmap in your DBMS if you need to write. The DBMS (almost) always wants to control things itself and can do a better job at it since it knows more about the data being accessed and the queries being processed. The operating system is not your friend. 最好是需要什么就自己实现什么, 数据组织形式 # 文件
Read more →

Raft

译文 原文 有用的飞书文档 和其他的算法相比 Strong leader 日志只能从领导者发送到其他节点 Leader election 随机计时器选举领导,在心跳机制上加上一些额外的工作 Membership changes 角色变换 Replicated state machines # 复制状态机一般基于日志实现,通俗的理解只要所有的机器按照相同的顺序执行指令,那么每个节点的状态都是确定的,所以需要把指令日志复制到其他节点上去,这就是一致性算法的工作 如果只是要求最终所有的节点都执行一样顺序的指令,而不要求实时性,则可以限定 只有一个节点可以进行写操作,因为只有写操作才可以改变系统的状态 写节点同步指令到其他节点,最终所有节点指令顺序一致 一致性算法的共有特性 安全性 不会返回一个错误结果,只要是在非拜占庭错误情况下,包括网络延迟,乱序,丢包,分区,冗余等都可以保障正确性 可用性 集群只要大多数机器可以正常通信,就可以确保可用,失败节点可以忽略或者后续恢复状态,大多数指的是半数以上 不依赖时序保证一致性 时钟错误或者消息延迟只有在极端情况下才会导致可用性 慢节点不会影响消息的反馈,消息可以快速的响应 拜占庭将军问题 Paxos # 难以理解 没有公认的可以实现的基础架构,大部分系统从Paxos开始,在遇到问题的时候自行想办法解决,导致最后的系统实现只能是类似Paxos的算法 Raft # 管理复制状态机的一种算法,他会在集群中选举一个leader,之后会复制所有的日志到其他节点实现一致性 他可以分解为三个问题 领导选举 一个新的领导人需要被选举出来,当先存的领导人宕机的时候 日志复制 领导人必须从客户端接收日志然后复制到集群中的其他节点,并且强制要求其他节点的日志保持和自己相同 安全性 在 Raft 中安全性的关键是在图 3 中展示的状态机安全:如果有任何的服务器节点已经应用了一个确定的日志条目到它的状态机中,那么其他服务器节点不能在同一个日志索引位置应用一个不同的指令 可以在这个网站查看实例 节点有三种状态 Follower Candidate Leader 他们之间的转换关系如下图 任期在 Raft 算法中充当逻辑时钟的作用,这会允许服务器节点查明一些过期的信息比如陈旧的领导者。每一个节点存储一个当前任期号,这一编号在整个时期内单调的增长。当服务器之间通信的时候会交换当前任期号;如果一个服务器的当前任期号比其他人小,那么他会更新自己的编号到较大的编号值。如果一个候选人或者领导者发现自己的任期号过期了,那么他会立即恢复成跟随者状态。如果一个节点接收到一个包含过期的任期号的请求,那么他会直接拒绝这个请求。 下面是详细的细节参数 下面的参数要求在节点上持久存在 currentTerm 服务器最后一次知道的任期号,初始化为 0,持续递增 votedFor 当前获得选票的候选人的Id log[] 日志条目集;每一个条目包含一个用户状态机执行的指令,和收到时的任期号 下面的参数在节点上是随时变化的 commitIndex 已知的最大的已经被提交的日志条目的索引值 lastApplied 最后被应用到状态机的日志条目索引值,初始化为 0,持续递增 下面的参数需要在leader重新选举之后变化的 nextIndex[] 对于每一个服务器,需要发送给他的下一个日志条目的索引值,初始化为领导人最后索引值加一 matchIndex[] 对于每一个服务器,已经复制给他的日志的最高索引值 这篇图表示的是rpc的参数信息以及返回值,由领导人负责调用来复制日志指令;也会用作heartbeat 参数 term 领导人的任期号 leaderId 领导人的 Id,以便于跟随者重定向请求 prevLogIndex 新的日志条目紧随之前的索引值 prevLogTerm prevLogIndex 条目的任期号 entries[] 准备存储的日志条目,表示心跳时为空;一次性发送多个是为了提高效率 leaderCommit 领导人已经提交的日志的索引值 返回值 term 当前的任期号,用于领导人去更新自己 success 跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真 如果 term < currentTerm 就返回 false 如果日志在 prevLogIndex 位置处的日志条目的任期号和 prevLogTerm 不匹配,则返回 false 如果已经已经存在的日志条目和新的产生冲突(相同偏移量但是任期号不同),删除这一条和之后所有的 附加任何在已有的日志中不存在的条目 如果 leaderCommit > commitIndex,令 commitIndex 等于 leaderCommit 和 新日志条目索引值中较小的一个 由候选人负责调用用来征集选票
Read more →

GFS

Read more →

Mapreduce

利用普通机器组成的大规模计算集群进行并行的,高容错,高性能的数据处理函数框架 原始论文点这里,论文翻译点这里,有时间的话,自行对比翻译和原文 最终实现的目标是–实现一个分布式系统,对程序员隐藏底层分布式细节,程序员只需要定义map和reduce 函数即可。 map reduce实现为简单的kv输出,其中map接受源数据,生成kv的中间结果,中间结果保存在worker节点上。 reduce负责处理map产生的中间结果的kv数据,只是简单的数据处理过程. 他最先是受到lisp中map和reduce原语的启发,再加上当时Google现实的处理大量数据的需求,从他们现有的系统抽象而来的。 在论文中,使用了一个单词统计的案例,此时实现map函数用来分割文本,切分出最基本的单词。然后再使用reduce进行聚合操作, // 输出单词以及出现的次数,map端输出1 map(String key,String value): // key: 文档名 // value: 文档内容 for each word w in value: EmitIntermediate(w,"1"); // 针对相同的key,次数+1 reduce(String key, Iterator values): // key: 一个单词 // value: 计数值列表 int result = 0; for each v in values: result += ParseInt(v); Emit(AsString(result)); 执行过程 文件划分 主节点划分任务 按照划分的任务启动worker,执行map任务 worker节点的数据生成为中间结果,保存在本节点 所有map任务执行完成之后,reduce得到对应中间节点的文件路径,通过rpc读取文件,进行reduce任务 reduce任务完成之后,最终结果写入目标文件 一个mr任务完成之后,回得到n(reduce)个结果文件,可以按照需求处理文件,可以直接使用,或者继续作为其他mr的输入,mr任务是可以嵌套的。 主节点 记录map和reduce任务的状态,例如是否开始,是否结束,执行时间等 协调工作节点,确定工作状态。确定任务是否需要重试,是否需要back up等 容错性 工作节点失败 主机点定时检测工作节点状态,如果无法链接,此时需要把此丢失的工作节点上的所有的任务重新安排到其他节点上执行。包括已完成的map任务,因为mr任务是需要等所有map任务结束之后才能执行reduce任务,其map任务的数据在保存在worker节点上的。所以需要重新执行map任务。至于reduce任务,由于他的输出之最终的数据结果,且需要记录到文件。所以为了避免重复的数据产生,已完成的reduce任务不重试,前提是输出数据已经保存到其他节点上。 主节点错误 一般是直接重试整个mr任务,因为mr的主节点应该是需要选择集群中比较可靠的节点,此时有理由怀疑其他节点也可能出现问题,所以此时选择整个重新执行,当然也可以恢复主节点,从记录的回复点重新执行 backup task mr中由于任务切分不一定均衡或者不同节点计算能力不同,有的任务执行格外慢,此时可以在其他空闲节点上执行相同的任务,此时集群中可能有多个相同的任务,最终哪一个任务先完成,主节点就会终止其他未完成的工作节点。 上面就是原始的mr描述,理所当然的可以想到一些提升的地方 平均的划分任务文件,尽量任务均衡 流式计算,在中间结果产生的时候,直接保存中间文件到reduce节点,避免最后集中处理中间结果时候的网络带宽消耗 本地计算mr,有的mr任务没必要在不同节点上执行,直接划分到一个节点或把的某些任务划分到一个节点上,实现本地计算。避免网络IO 提前进行reduce操作,可以使用reduce任务提前处理中间结果,减少中间结果的大小 记录计算节点的状态,多次执行任务的时候,可以记录某节点的处理速度,在下一个mr任务划分的时候,按照此信息划分任务 https://www.zhihu.com/question/303101438 map和reduce之间是完全串行的,如果有多个MR任务嵌套的话,由于每个mr必须实现map和reduce,会导致链路过长,实现和调试困难 性能无法达到要求 6.824 LAB # 先掌握go,重点为go的协程,管道,以及channel 代码框架已经给出来了,需要自己实现分布式的worker和master 可以先实现简单的无状态的mr,可以通过test-mr.sh中的前面的测试 worker # map和reduce的执行节点,需要从master获得任务,按照任务的类型,执行不同的job func Worker(mapf func(string, string) []KeyValue, reducef func(string, []string) string) { for { job := getJob() if job.
Read more →

A Tour of Go速通

2022-05-17 基础语法 2022-05-24 复合类型,goroutine,channel 基础语法 # Packages # go使用Packages维护模块,使用import导入模块,import最后一个元素才是需要导入的模块 import ( "fmt" "math/rand" ) import 可以单独一个导入一个模块,也可以批量导入, 与之对应的是export,go不显示声明export,首字母大写的变量或方法自动export,外部只能使用导出的变量或者方法,类似c++中类的私有和共有的概念。 Functions # 与c++或者Java或者其他语言不同的是,go的函数签名格式为func func_name(parm1 [type], parm2 [type]....) retype {},先声明名字,再声明变量的类型,参数列表中有多个参数且类型一致的时候,前面的参数类型可以省略,只需要保留之后一个 func add(x, y int) int { return x + y } 且go可以很轻易的实现多返回值的功能,如下 func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) } 上面的功能在c++中需要使用结构体或者tuple或者Paris才能实现。 go的return还可以使用不带参数的 “naked” return,此时要求函数签名中的return参数必须有名字,且在函数体中必须为参数赋值,此时使用return直接返回,参数可以直接传递到外部,但是需要注意的时候,如果函数体过于庞大且有多个出口,不建议使用,难于阅读 func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return } 变量 # 使用var声明变量,声明多个变量的时候可以类似参数列表中的参数,前面参数不需要声明类型。初始化的时候按顺序初始化,且初始化的参数个数必须前后一致 var i, j, k int = 1,2,0 // true var i, j, k int = 1,2 // false 初始化的时候还可以省略类型,程序会进行参数推导。 函数内部还可以使用 :=替换var声明变量,此时必须初始化,但是在函数体外部,由于go规定,每条语句必须由特定的关键字开头,所以外部不可使用此语法。
Read more →

Coursenote

随堂笔记 # Why do people build distributed systems? to increase capacity via parallel processing to tolerate faults via replication to match distribution of physical devices e.g. sensors to achieve security via isolation 分布式的困难点: 大量的并发操作 具有容错性 难于实现 Lab 1: distributed big-data framework (like MapReduce) Lab 2: fault tolerance library using replication (Raft) Lab 3: a simple fault-tolerant database Lab 4: scalable database performance via sharding A big goal: hide the complexity of distribution from applications. Topic: fault tolerance 1000s of servers, big network -> always something broken We’d like to hide these failures from the application. “High availability”: service continues despite failures
Read more →

LevelDB源码阅读

leveldb 源码总结分析
Read more →

VolcanoOptimizer

NOTE # 论文阅读笔记The Volcano Optimizer Generator: Extensibility and Efficient Search 可扩展 面向对象 自顶向下 剪枝 原型是EXODUS, Volcano是对他的改进 可以单独使用的优化器 优化搜索时间和搜索空间 可扩展 可以使用启发式算法和有效的代价模型来扩展和减少搜索空间,【剪枝】 灵活的成本计算模型 一个框架,优化器生成器,可以由“optimizer implementor”自行实现关键函数,整个优化器框架的输入是AST,输出是一个执行计划,算子的集合 SQL是基于关系代数,Volcano把关系表达式分为逻辑表达式和物理表达式,逻辑表达式之间使用transformation进行转换,物理表达式使用基于代价的implementation和逻辑表达式映射的,关系不一定是意义对应的,例如scan可以同时一起实现projection 在表达式进行转换的时候可以使用condition进行模式判断,满足条件的时候可以进行变换 表达式使用特征描述输出, enforcers会强制添加某属性,用于指导优化器进行优化,例如指定表的scan方式 Logical Operator Operator set,也就是可以描述在目标data model上可以执行的代数运算合 Transformation rules + Condition,对每条等价变换规则,在满足condition时才可以应用 Logical properties : 逻辑属性,用来描述代数运算的输出所具有的一些特征,这些特征与运算的具体执行方式无关,是逻辑的,例如输出的行数,结果集的schema等 Physical Operator Algorithm + Enforcer set,即可应用的物理实现算法 + 可添加的Enforcer集合 Implementation rules + Condition,满足Condition的前提下,可以尝试该物理算法 Cost model + Cost formula,基于cost选择最优的物理算法 Physical property,与logical property对应,物理属性是选择了特定的算法实现后,输出的数据所具有的物理上的特性,例如数据是否有序、是否具有唯一性,数据在多机上的分布情况等,不同的物理算法,会决定执行该operator产生的物理属性,例如sort merge join会在join key上产生有序属性 Applicability function : 决定一个物理算法,其输出是否可以满足要求父算子对自身的physical property要求,且决定它对自身的输入具有什么样的physical property要求 Enforcer是search engine中一个重要的概念,它用来强制产生某种物理属性。例如上层是join算子,在枚举时会考虑使用sort merge join的物理执行方式(Implementation),但当递归到下层时,子节点可以选择table scan(无序输出),或者index scan(目标序输出),当选择table scan时,由于输出不满足父算子对自身输出的物理属性要求,就可以通过Order Enforcer来产生目标输出,Enforcer表示了排序这个操作,同时也包含了排序操作会产生的代价。 The Search Engine # 搜索实现 // PhysProp:: 此LogExpr锁具有的物理属性的要求 FindBestPlan (LogExpr, PhysProp, Limit) // 如果可以在look-up table找到满足的计划,则代表以及算过,直接返回 if the pair LogExpr and PhysProp is in the look-up table if the cost in the look-up table < Limit return Plan and Cost else return failure /* else: optimization required */ // 否则进行优化,由三种优化方式 // 1.
Read more →

Columbia Optimizer

Read more →

现代C++白皮书

Read more →

Envs

hugo # wget https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_0.92.1_Linux-64bit.deb https://github.91chi.fun/https://github.com//gohugoio/hugo/releases/download/v0.92.2/hugo_extended_0.92.2_Linux-64bit.deb sudo dpkg -i hugo*.deb 140.82.113.3 aria2c -s 5 https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_0.92.1_Linux-64bit.deb https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_0.92.1_Linux-64bit.deb 可以使用aria2下载,ubuntu使用apt install aria2直接安装工具,使用-s开启多路下载 aria2c -s 5 https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_0.92.1_Linux-64bit.deb manager用户 https://www.jianshu.com/p/a76a93e8c662 Unix # 分区问题,集群上多块磁盘分区挂载到指定目录 fdisk disk 可以对一个磁盘进行分区的添加和删除等操作 p d w h 添加磁盘挂载 lsblk -f 查看磁盘 mkfs.xfs -f -n ftype=1 /dev/sdb1 格式化磁盘 mount /dev/sdb1 /var/lib/docker 挂载 xfs_info /dev/sdb1 | grep ftype=1 blkid /dev/sdb1 查看UUID UUID=<UUID> /var/lib/docker xfs defaults 0 0 写进/etc/fstab 问题Couldn't find device with uuid 4mhUbb-Ls1h-jp0d-JuJK-C38V-T3tX-f7s2IN 原因未知,疑似但是这个UUID是前面挂载的分区格式化之前的UUID,所以可能是挂载的时候出了什么问题,但是之前对其他机器操作无问题,此问题只出现在集群中的一两太机器上。 解决: 使用 vgreduce --removemissing --verbose lvname 解决,但是需要视情况而定,需要知道自己在做什么 其中会使用的命令 lsblk vgscan pvscan cat /etc/lvm/archive/* | less 查看UUID和盘符之前的关系 lvextend -L +300G /dev/mapper/centos-root 扩展分区大小 xfs_growfs /dev/mapper/centos-root 扩展且生效 lvremove /dev/mapper/centos-home 删除lv lvcreate -L 100G -n /dev/mapper/centos-home 创建lv mkdf.
Read more →

Docker

docker 常用命令速查,私用
Read more →

C++ Primer Plus

编译器 # 把高级语言编译成可执行语言工具,分为前端后后端,前端值得是高级语言的解析,后端是指翻译解析之后的结果为机器语言 多文件 ** 连接 多文件编译可以有两种方式,一是直接编译为一个可以执行文件,二是按模块或者按文件编译为库,然后连接到执行文件 连接方式有两种, 一是静态连接,把所有的库文件打包到最后的生成文件中,优点是不需要额外的依赖外部环境,独立性强,缺点是文件体积大 二是动态链接,为了解决静态链接的缺点,执行文件在执行到库相关的代码的时候才加载库,有一点需要注意的是,程序运行的时候,在使用到动态库的时候才映射动态库到内存空间中。原理是编译待援在编译的时候,会更具声明生成函数的调用逻辑,但是只是一个地址跳转语句,所以,只要不调用,就不会有问题,当调用到了。才会加载库然后映射库的地址,这个完整的过程称为重定向。 动态连接 C语言编程透视 声明 声明是为了在编译的时候编译器能进行完整的上下文编译。他需要更具声明来确定编译信息,否则编译器无法确定编译中的语句信息,声明可以辅助完成这个情况, 所以理论上编译的时候是可以不需要实现的,可以在其他编译单元中实现声明的函数,其声明的文件可以不引用头文件,即两个编译单元完全可以无任何联系,除了声明之外,在连接的时候,连接器会根据编译出来的信息去确定函数调用情况,这里有一个问题,按上述的描述,是一个声明对应一个实现,如果有一个声明对应多个实现呢 == : 会有覆盖问题,如果多个动态链接库都有同一个声明的实现,则连接的时候连接第一个,后面的则忽略,这也提醒我们,在大型项目中,避免同名全局函数或者变量,使用namespace或者static限制作用域, g++ -o tt ../main.cpp -ldl ./libhellolib.so ./libhellolib1.so LD_LIBRARY_PATH=$PWD ./tt 头文件,避免公用代码的重复,预处理时展开头文件,需要使用#pragma once避免重复引用,头文件只是简单的文件替换,理论上的可以替换任何文本。 cmake * 子模块,使用add_subdirectory引入 * 第三方库 * 只是头文件,直接指定头文件目录编译即可 * 使用子模块 * 使用为连接库 * 使用git模块 STL 重点为容器和算法 lambda表达式,实质上是仿函数,是一个结构体实现()运算的重载,捕获的时候按照声明的新式捕获参数,建议使用的时候明确使用的参数,使用哪个就捕获哪一个,否则他实际上会占据一定的大小的,配合std::function使用 CTAD — complie-time argument deduction,编译器参数推断,C++17引入的,可以在编译器按照上下文推断类型,具体表现在lambda参数可以使用auto,容器可以不适用<> ranges https://zhuanlan.zhihu.com/p/350068132 module raii 获取资源即初始化,释放资源即销毁,具体的实现是使用构造函数和析构函数,当前的实现为智能指针,其他用户自己管理的资源最好也使用raii,遮这样在函数有多个出口的时候,就不会有意外的情况,本质上还是自己管理资源,不想其他的语言有GC 异常安全,C++中异常机制在回溯栈的时候会析构对象,所以如果没有实现RAII,则自己管理的内存则无法释放,C++的异常可以发生在任何地方,如果发生在析构函数中,则需要自己处理,不要在析构函数中抛出异常的,在构造函数中的时候,也需要捕获异常然后释放已经申请的资源,构造函数异常的时候,是不会调用析构函数的, 构造函数 构造函数有时候会隐士的生成对象,即使没有显示声明,使用explicit避免这种情况,单参数的时候会,多参数使用{},调用的时候也会 直接使用多参数的时候,()和{}是有区别的,()除了正常的使用外,其他情况不具备特殊含义 int a = (10, 11); int a = {10, 11}; tt t(1, 2); tt q{1, 3}; tt w = {1, 4}; tests({1,5}); ``` 上面的语句1正确,a的值为11,2错误,{}这种用法的意义是参数列表,是会构造对象的。ps,调用构造函数的时候,有具体的对象的时候两种括号无差别,但是无对象的时候有区别,如上,细品 默认构造函数 拷贝构造( A(A const & a) ) A a = aa; 移动构造( A(A && a) ) 赋值构造( A&operator=(A const& a) ) A a; a = aa; 移动赋值( A&operator=(A && a) ) =delte和=default 类内部变量可以赋初值 三五法则 拷贝构造或者赋值构造需要区分深拷贝和浅拷贝,这也是构造函数肯可能引入的问题,例如浅拷贝导致内存的重复释放, 各种构造函数更多的是需要考虑当前对象的来源,如果是直接从零开始的,则是普通的构造函数,如果是从别的对象来的,则需要考虑深浅拷贝的问题,以及构造之后别的对象是否还需要的问题,简而言之,就是资源细节上的考虑,只要内涉及到资源的操作,则需要多话费一些心思区考虑, 函数返回多值
Read more →

issues # 1490 # 1921 # 1699 # http://10.20.16.216:9090/ADB/AntDB/-/issues/1490 http://10.20.16.216:9090/ADB/AntDB/-/issues/1921 http://10.20.16.216:9090/ADB/AntDB/-/issues/1699 问题 # 使用到reduce的地方(包括查询)偶现以下错误,再次执行sql就正常; ERROR: remote node 16389 closed socket CONTEXT: dynamic reduce 复现方法 # 使用修改分布方式的方式去复现问题,过程如下: 创建100张表,然后并发100,不停执行下面的语句,5分钟之内会出现报错: alter table xxx distribute by replication; alter table xxx distribute by random; 无法直接复现 1779 # http://10.20.16.216:9090/ADB/AntDB/-/issues/1779 问题 # 执行计划不正确导致dyreduce执行出错 复现方法 # create table tttb1( c1 int,c2 varchar(100),c3 varchar(100)); create table tttb2(c1 int,sheet_num varchar(100)); create table tttb3(c1 int,order_no varchar(100)); explain select count(distinct c2) from tttb1 where c2 in (select distinct sheet_num from tttb2,tttb3 where sheet_num=order_no and c3='1'); create table tb1(c1 int,c2 varchar(100),c3 varchar(100)); create table tb2(c1 int,sheet_num varchar(100)); create table tb3(c1 int,order_no varchar(100)); explain select count(distinct c2) from tb1 where c2 in (select distinct sheet_num from tb2,tb3 where sheet_num=order_no and c3='1'); insert into tb1 select (random()*10000000)::int, (random()*10000000)::int, (random()*10000000)::int from generate_series(1,100000); insert into tb2 select (random()*10000000)::int, (random()*10000000)::int from generate_series(1,100000); insert into tb3 select (random()*10000000)::character varying, (random()*10000000)::int from generate_series(1,100000); create table tb1int(c1 int, c2 int,c3 int); create table tb2int(c1 int, sheet_num int); create table tb3int(c1 int, order_no int); explain select count(distinct c2) from tb1int where c2 in (select distinct sheet_num from tb2int,tb3int where sheet_num=order_no and c3=1); insert into tb1int select (random()*10000000)::int, (random()*10000000)::int, (random()*10000000)::int from generate_series(1,100000); insert into tb2int select (random()*10000000)::int, (random()*10000000)::int from generate_series(1,100000); insert into tb3int select (random()*10000000)::int, (random()*10000000)::int from generate_series(1,100000); 1875 # http://10.
Read more →

语句 prepare s3(int, int) as select no_o_id from bmsql_new_order where no_w_id = $1 and no_d_id = $2 order by no_o_id asc; QUERY PLAN --------------------------------------------------------------------------------------------------- Cluster Gather (cost=291.52..430.37 rows=459 width=4) Remote node: 16386 -> Sort (cost=291.52..292.67 rows=459 width=4) Output: no_o_id Sort Key: bmsql_new_order.no_o_id -> Bitmap Heap Scan on public.bmsql_new_order (cost=13.46..271.23 rows=459 width=4) Output: no_o_id Recheck Cond: ((bmsql_new_order.no_w_id = 1) AND (bmsql_new_order.no_d_id = 1)) -> Bitmap Index Scan on bmsql_new_order_pkey (cost=0.00..13.34 rows=918 width=0) Index Cond: ((bmsql_new_order.no_w_id = 1) AND (bmsql_new_order.no_d_id = 1)) Remote node: 16386 (11 rows) QUERY PLAN -------------------------------------------------------------------------------------------------------------------- Data Node Scan on "__REMOTE_SORT_QUERY__" (cost=0.00..0.00 rows=1000 width=4) Output: bmsql_new_order.no_o_id Node/s: data_1 Remote query: SELECT no_o_id FROM ONLY public.
Read more →

predicate_refuted_by 和 make_new_qual_list的运行逻辑以及PARAM 无法选出一个节点的原因 make_new_qual_list需要使用表达式和分区信息构造新的表达式,但是PARAM不是常量,所以无法构造, 所以predicate_refuted_by判定变大时和约束的时候无法正确的选择节点,动态语句只要使用到分区键都不行 node_count = 2 Table "public.bmsql_new_order" Column | Type | Nullable | Storage | ---------+---------+----------+---------+ no_w_id | integer | not null | plain | no_d_id | integer | not null | plain | no_o_id | integer | not null | plain | Indexes: "bmsql_new_order_pkey" PRIMARY KEY, btree (no_w_id, no_d_id, no_o_id) Foreign-key constraints: "no_order_fkey" FOREIGN KEY (no_w_id, no_d_id, no_o_id) REFERENCES bmsql_oorder(o_w_id, o_d_id, o_id) DISTRIBUTE BY HASH(no_w_id) TO NODE(dn1, dn2) Access method: heap 数据分布 benchmarksql=# execute direct on (dn1) 'select distinct no_w_id from public.bmsql_new_order'; no_w_id --------- 1 5 2 (3 rows) benchmarksql=# execute direct on (dn2) 'select distinct no_w_id from public.
Read more →

Read more →

remote Query # 精确选择数据源,需要从语句的约束条件中计算出具体的执行数据源节点,然后把语句下发的对应的 DN 操作尽可能下推,下推一些操作到对应的DN上执行 remote query当前使用两阶段优化 第一阶段是FQS,对语句进行简单的判断,如果语句可以完全在DN上执行,则直接在这里创建remote plan,然后直接返回,如下例子 benchmarksql=# explain select * from t1; QUERY PLAN ---------------------------------------------------------------------------- Data Node Scan on "__REMOTE_FQS_QUERY__" (cost=0.00..0.00 rows=0 width=0) Primary node/s: dn1 Node/s: dn1, dn2 (3 rows) 第二阶段,FQS判断失败的语句,此时需要进行常规优化,一般是语句需要DN之间的数据发生交换的时候,例如join使用多表, 但是关联条件不是分区键,此时需要把DN的数据读取到 CN 上,然后进行关联, postgres=# explain select * from t1 join t2 on t1.c1 = t2.c1; QUERY PLAN --------------------------------------------------------------------------------------------------- Hash Join (cost=2752.50..5509.65 rows=3000 width=16) Hash Cond: (t2.c1 = t1.c1) -> Data Node Scan on t2 "_REMOTE_TABLE_QUERY_" (cost=0.00..2715.90 rows=3001 width=8) Primary node/s: dn1 Node/s: dn1, dn2, dn3 -> Hash (cost=2715.00..2715.00 rows=3000 width=8) -> Data Node Scan on t1 "_REMOTE_TABLE_QUERY__1" (cost=0.00..2715.00 rows=3000 width=8) Primary node/s: dn1 Node/s: dn1, dn2, dn3 (9 rows) 1.
Read more →

typedef struct SubPlan { pg_node_attr(no_query_jumble) Expr xpr; /* Fields copied from original SubLink: */ SubLinkType subLinkType; /* see above */ /* The combining operators, transformed to an executable expression: */ Node *testexpr; /* OpExpr or RowCompareExpr expression tree */ List *paramIds; /* IDs of Params embedded in the above */ /* Identification of the Plan tree to use: */ int plan_id; /* Index (from 1) in PlannedStmt.subplans */ /* Identification of the SubPlan for EXPLAIN and debugging purposes: */ char *plan_name; /* A name assigned during planning */ /* Extra data useful for determining subplan's output type: */ Oid firstColType; /* Type of first column of subplan result */ int32 firstColTypmod; /* Typmod of first column of subplan result */ Oid firstColCollation; /* Collation of first column of subplan result */ /* Information about execution strategy: */ bool useHashTable; /* true to store subselect output in a hash table (implies we are doing "IN") */ bool unknownEqFalse; /* true if it's okay to return FALSE when the * spec result is UNKNOWN; this allows much * simpler handling of null values */ bool parallel_safe; /* is the subplan parallel-safe?
Read more →

配置文件guc.c http://www.postgres.cn/docs/12/view-pg-settings.html Column | Type | Collation | Nullable | Default | Storage | Description —————–+———+———–+———-+———+———-+————- name | text | | | | extended | 名称 setting | text | | | | extended | 配置 unit | text | | | | extended | 单位 category | text | | | | extended | 分类 short_desc | text | | | | extended | 描述 extra_desc | text | | | | extended | 附加描述 context | text | | | | extended | 上下文 vartype | text | | | | extended | 参数类型 source | text | | | | extended | 来源 min_val | text | | | | extended | 最小值 max_val | text | | | | extended | 最大值 enumvals | text[] | | | | extended | 枚举的允许值 boot_val | text | | | | extended | 默认值 reset_val | text | | | | extended | 当前session中reset 之后会设置的值 sourcefile | text | | | | extended | 设置文件 sourceline | integer | | | | plain | 文件行号 pending_restart | boolean | | | | plain | 修改文件是否需要重启生效 select name, setting, boot_val, reset_val, sourcefile, sourceline, pending_restart from pg_settings ; View definition: SELECT a.
Read more →

Read more →