# WalMiner **Repository Path**: harrik/XLogMiner ## Basic Information - **Project Name**: WalMiner - **Description**: WalMiner是从PostgreSQL的WAL(write ahead logs)日志中解析出执行的SQL语句的工具,并能生成对应的undo SQL语句。与传统的logical decode插件相比,walminer不要求logical日志级别且解析方式较为灵活。开发组QQ群:811105058欢迎任何使用者加入。 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 59 - **Created**: 2020-06-10 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README WalMiner2.0 Beta(2020-6-7更新) ===== ## 什么是WalMiner WalMiner是从PostgreSQL的WAL(write ahead logs)日志中解析出执行的SQL语句的工具,并能生成对应的undo SQL语句。与传统的logical decode插件相比,walminer不要求logical日志级别且解析方式较为灵活。 **walminer2.0更新内容** - 代码重构,对PG各个版本的支持都合成为一份代码,master分支为主要开发库,WalMiner_10_0_1和WalMiner_11_0_1不再维护 - 增加对PG13的支持 - 精简输出结果表 - 修改xid解析模式 - 修改解析执行语句 - 增加精确解析支持 - 增加回归测试 ## PG版本支持 - 支持PostgreSQL 9.5及其以上版本 ## 编译安装 1. 将walminer目录放置到编译通过的PG工程的"../contrib/"目录下 2. 进入walminer目录 3. 执行命令 ```shell make && make install ``` ## 使用方法 ### 场景一:从WAL日志产生的数据库中直接执行解析 #### 1. 创建walminer的extension create extension walminer; #### 2. 添加要解析的wal日志文件 ```sql -- 添加wal文件: select walminer_wal_add('/opt/test/wal'); -- 注:参数可以为目录或者文件 ``` #### 3. Remove wal日志文件 ```sql -- 移除wal文件: select walminer_wal_remove('/opt/test/wal'); -- 注:参数可以为目录或者文件 ``` #### 4. List wal日志文件 ```sql -- 列出wal文件: select walminer_wal_list(); ``` #### 5. 执行解析 ​ 5.1 普通解析 ```sql --解析add的全部wal日志 select walminer_all(); 或 select wal2sql(); --在add的wal日志中查找对应时间范围的wal记录 --可以参照walminer_time.sql回归测试中的使用用例 select walminer_by_time(starttime, endtime); 或 select wal2sql(starttime, endtime); --在add的wal日志中查找对应lsn范围的wal记录 --可以参照walminer_lsn.sql回归测试中的使用用例 select walminer_by_lsn(startlsn, endlsn); 或 select wal2sql(startlsn, endlsn); --在add的wal日志中查找对应xid的wal记录 --可以参照walminer_xid.sql回归测试中的使用用例 --前一个walminer版本对xid的支持是范围解析,但是xid的提交是不连续的 --会导致各种问题,所以这个版本只支持单xid解析 select walminer_by_xid(xid); 或 select wal2sql(xid); ``` ​ 5.2 精确解析 ```sql --在add的wal日志中查找对应时间范围的wal记录 select walminer_by_time(starttime, endtime,'true'); 或 select wal2sql(starttime, endtime,'true'); --在add的wal日志中查找对应lsn范围的wal记录 select walminer_by_lsn(startlsn, endlsn,'true'); 或 select wal2sql(startlsn, endlsn,'true'); --在add的wal日志中查找对应xid的wal记录 select walminer_by_xid(xid,'true'); 或 select wal2sql(xid,'true'); ``` walminer的构建基础是,checkpoint之后对每一个page的更改会产生全页写(FPW),因此一个checkpoint之后的所有wal日志可以完美解析。*注意checkpoint是指checkpoint开始的点,而不是checkpoint的wal记录的点,[参照说明](https://my.oschina.net/lcc1990/blog/3027718)* 普通解析会直接解析给定范围内的wal日志,因为可能没有找到之前的checkpoint点,所以会出现有些记录解析不全导致出现空的解析结果。 精确解析是指walminer程序会界定需要解析的wal范围,并在给定的wal范围之前探索一个checkpoint开始点c1,从c1点开始记录FPI,然后就可以完美解析指定的wal范围。如果在给定的wal段内没有找到c1点,那么此次解析会报错停止。 ​ 5.3 单表解析 ```sql --在add的wal日志中查找对应时间范围的wal记录 select walminer_by_time(starttime, endtime,'false',reloid); 或 select wal2sql(starttime, endtime,'true',reloid); --在add的wal日志中查找对应lsn范围的wal记录 select walminer_by_lsn(startlsn, endlsn,'true',reloid); 或 select wal2sql(startlsn, endlsn,'false',reloid); --在add的wal日志中查找对应xid的wal记录 select walminer_by_xid(xid,'true',reloid); 或 select wal2sql(xid,'true',reloid); ``` ​ 'true'和‘false’代表是否为精确解析模式,reloid为目标表的oid(注意**不是**relfilenode) #### 6. 解析结果查看 ```sql select * from walminer_contents; ``` ```sql -- 表walminer_contents ( sqlno int, --本条sql在其事务内的序号 xid bigint, --事务ID topxid bigint, --如果为子事务,这是是其父事务;否则为0 sqlkind int, --sql类型1->insert;2->update;3->delete(待优化项目) minerd bool, --解析结果是否完整(缺失checkpoint情况下可能无法解析出正确结果) timestamp timestampTz, --这个SQL所在事务提交的时间 op_text text, --sql undo_text text, --undo sql complete bool --如果为false,说明有可能这个sql所在的事务是不完整解析的 ) ``` #### 7. 结束walminer操作 该函数作用为释放内存,结束日志分析,该函数没有参数。 ```sql select walminer_stop(); ``` ### 场景二:从非WAL产生的数据库中执行WAL日志解析 :warning: 要求执行解析的PostgreSQL数据库和被解析的为同一版本 #### 于生产数据库 ##### 1.创建walminer的extension ```sql create extension walminer; ``` ##### 2.生成数据字典 ```sql select walminer_build_dictionary('/opt/proc/store_dictionary'); -- 注:参数可以为目录或者文件 ``` #### 于测试数据库 ##### 1. 创建5walminer的extension ```sql create extension walminer; ``` ##### 2. load数据字典 ```sql select walminer_load_dictionary('/opt/test/store_dictionary'); -- 注:参数可以为目录或者文件 ``` ##### 3. add wal日志文件 ```sql -- 增加wal文件: select walminer_wal_add('/opt/test/wal'); -- 注:参数可以为目录或者文件 ``` ##### 4. remove wal日志文件 ```sql -- 移除wal文件: select walminer_wal_remove('/opt/test/wal'); -- 注:参数可以为目录或者文件 ``` ##### 5. list wal日志文件 ```sql -- 列出wal文件: select walminer_wal_list(); -- 注:参数可以为目录或者文件 ``` ##### 6. 执行解析 同上 ##### 7. 解析结果查看 ```sql select * from walminer_contents; ``` ##### 8.结束walminer操作,该函数作用为释放内存,结束日志分析,该函数没有参数。 ```sql select walminer_stop(); ``` :warning: **注意**:walminer_contents是walminer自动生成的临时表,因此当session断开再重新进入或其他session中解析数据不可见。这么做主要是基于安全考虑。 如果希望保留解析结果,可利用create xxx as select * from walminer_contents;写入普通表中。 ## 使用限制 1. 本版本只解析DML语句,不处理DDL语句 2. 执行了删除表、truncate表、更改表的表空间、更改表字段的类型、vacuum full,这样的DDL语句后,发生DDL语句之前的此表相关的DML语句不会再被解析。 7. 只能解析与数据字典时间线一致的wal文件 ## 联系我 发现bug或者有好的建议可以通过邮箱(lchch1990@sina.cn)联系我。