注册
dmlcvt工具解析归档文件
专栏/技术分享/ 文章详情 /

dmlcvt工具解析归档文件

PYZ 2024/09/06 834 0 0
摘要

一、功能简介

dmlcvt 是 DM 提供的用于解析日志文件的工具,包括联机日志文件和归档日志文件。
当意外情况导致系统故障或者介质故障时,并且没有提前开启逻辑附加日志和SQL日志的情况下,需要通过日志文件进行分析、恢复。此时可以使用日志解析工具dmlcvt,通过指定日志文件类型和路径从日志文件中获取详细的日志信息,分析系统故障原因。
获取到如下日志信息:
1、日志文件信息
2、物理事务(ptx)信息
3、事务对应的记录信息
4、页信息
5、警告信息和错误信息
通常 dmlcvt 解析日志需要指定读入的日志文件类型、具体路径以及结果输出路径等。
指定日志文件路径有三种方式:
1、指定控制文件,程序会解析控制文件找出所有日志文件
2、指定归档目录,程序会解析目录下所有归档文件
3、指定单个日志文件,程序只解析指定的日志文件
最终结果会生成四个报告,存放在输出路径下。
报告分别为 file_info.txt、page_info000.txt、rec_info000.txt 和 warn_info.txt。

二、dmlcvt参数详解

[dmdba@test ~]$ dmlcvt help version: 03134284058-20231013-204750-20046 Pack19 格式: ./dmlcvt KEYWORD=value 例程: ./dmlcvt F_TYPE=4 F_PATH=/opt/dmdbms/data/DAMENG/dm.ini OUT_PATH=/opt/temp 关键字 说明(默认值) -------------------------------------------------------------------------------- F_TYPE 必选,表示读入的日志文件类型,与F_PATH配合使用 1 F_PATH必须指向归档目录 2 F_PATH必须指向某个归档文件 3 F_PATH必须指向单个联机日志文件 4 F_PATH必须指向文件dm.ini 5 F_PATH必须指向ptx->log组成的二进制文件 6 F_PATH必须指向从内存中dump出来的rpkg->data文件 7 F_PATH必须指向从内存中dump出来的buf_ctl->page文件 f_type=7 f_path=/xxx/24272.dat out_path=/xxx/24272 rec_data=1 desc_file=/xxx/desc.txt n_napp_flds=6 rowid_off=12 F_PATH 必选,对应F_TYPE的路径 当F_TYPE = 6: 1.gdb dump memory /tmp/x.log begin_addr end_addr 2.dmlcvt f_type=6 f_path='/tmp/x.log' out_path='/tmp/log_analyse' rec_data=1 OP_TYPE 可选,操作类型,对应不同的F_TYPE. 当F_TYPE = 1: 1 打印日志内容,默认值 当F_TYPE = 2: 1 打印日志内容,默认值 2 截断归档日志文件到指定LSN(LSN_START) 3 截断归档日志文件到SEQ(ARCH_SEQ) 4 拷贝从指定LSN(LSN_START)开始的归档文件内容到指定的输出目录(OUT_PATH)中自动新建的归档文件 5 调整归档文件元信息 6 通过归档日志构造数据页 f_type=2 f_path=/xxx/arch/x.log out_path=/xxx/arch/36121 op_type=6 ts_id=4 file_id=0 page_no=36121 rec_data=1 [page_path=xxx.txt] 当F_TYPE = 3: 1 打印联机日志内容,默认值 当F_TYPE = 4: 1 打印日志内容,默认值 2 调整当前CKPT到最近的一个合法位置 3 调整当前CKPT到最老的一个合法位置 4 找出指定LSN(LSN_START)开始的REDO日志中涉及的数据页号 5 截断REDO日志到指定LSN(LSN_START) REC_LEVEL 可选,打印日志内容级别,可选值为1,2,3,默认为3 1 仅打印ptx信息 2 仅打印rec信息 3 打印ptx和rec信息 REC_DATA 可选,打印rec数据类型,可选值为0,1,2,默认为0 0 不打印rec数据 1 打印所有类型的rec数据 2 仅打印数据类型的rec数据 PAGE_INFO 可选,是否打印页信息,bool型,可选值 1/0,默认为1 OUT_PATH 可选,输出文件路径,默认为当前路径,并包含以下文件: rec_infoxxx.txt, page_infoxxx.txt, file_infoxxx.txt, warn_infoxxx.txt F_TYPE=4并且OP_TYPE=4,则包含ref_pagesxxx.txt OUT_SIZE 可选,输出文件最大大小,单位(M),最小32,最大1024,默认为128 LSN_START 可选,从该lsn开始打印 LSN_END 可选,直到该lsn结束打印 ARCH_SEQ 可选,截断到的归档日志页序号 PTX_COUNT 可选,总共打印多少ptx F_OFFSET 可选,文件偏移,仅对单个日志文件有效,即当F_TYPE=3或者F_TYPE=2且OP_TYPE=1时有效 PMNT_MAGIC 可选,库的perment magic值,仅对归档目录有效,即当F_TYPE=1时有效 DB_MAGIC 可选,库的db magic值,仅对归档目录有效,即当F_TYPE=1时有效 TS_ID 可选,指定表空间id FILE_ID 可选,指定文件id PAGE_NO 可选,指定页号 REC_TYPE 可选,指定记录类型 DCR_INI 可选,dmdcr.ini的路径 DM_INI 可选,dm.ini的路径 DSC_SEQNO 可选,DSC环境中节点号 HELP 查看帮助信息

三、示例

1、编辑dml.java,通过java程序对test1和test2表进行一些批量的DML操作,用来产生一些归档

import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; public class dml { public static void main(String[] args) { String jdbcUrl = "jdbc:dm://192.168.100.12:5236?SCHEMA=HR"; String username = "HR"; String password = "hr"; Statement updateStmt = null, copyStmt = null, deleteStmt = null; try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) { connection.setAutoCommit(false); // 清空test1 String trunctest1SQL = "TRUNCATE TABLE test1"; try (PreparedStatement truncateStatement = connection.prepareStatement(trunctest1SQL)) { truncateStatement.executeUpdate(); System.out.println("test1 table has been truncated."); } // 清空test2 String trunctest2SQL = "TRUNCATE TABLE test2"; try (PreparedStatement truncateStatement = connection.prepareStatement(trunctest2SQL)) { truncateStatement.executeUpdate(); System.out.println("test2 table has been truncated."); } // 插入test1 10w条行记录,每1000条commit String insertSQL = "INSERT INTO test1 (id, name) VALUES (?, ?)"; try (PreparedStatement insertStatement = connection.prepareStatement(insertSQL)) { for (int i = 1; i <= 100000; i++) { insertStatement.setInt(1, i); insertStatement.setString(2, "Value_ " + i); insertStatement.addBatch(); if (i % 1000 == 0) { insertStatement.executeBatch(); connection.commit(); System.out.println("Inserted and committed batch of 1000 records."); } } insertStatement.executeBatch(); // 提交剩余的记录 connection.commit(); } // update test1 id <= 50000 String updateSQL = "UPDATE test1 SET name = dbms_random.string('U',4) WHERE id <= 50000"; updateStmt = connection.createStatement(); updateStmt.executeUpdate(updateSQL); connection.commit(); System.out.println("Update completed."); // 数据copy到test2 String copySQL = "INSERT INTO test2 SELECT * FROM test1"; copyStmt = connection.createStatement(); copyStmt.executeUpdate(copySQL); connection.commit(); System.out.println("Insert test2 completed."); // test2删除name like 'Value_%' String deleteSQL = "DELETE FROM test2 WHERE name like 'Value_%'"; deleteStmt = connection.createStatement(); deleteStmt.executeUpdate(deleteSQL); System.out.println("Delete completed."); connection.commit(); System.out.println("Commit completed."); } catch (SQLException e) { e.printStackTrace(); } } }

2、编译并执行java程序,此操作会发生2次truncate、10w次insert、5w次update、5w次delete

--编译 javac dml.java --执行程序 java -cp .:/dm8/drivers/jdbc/DmJdbcDriver18.jar dml

3、SYSDBA登录数据库切换当前归档文件(PS:dmlcvt需要解析完整的归档文件,否则解析会出错)

[dmdba@test dmarch]$ ls -ltr 总用量 131072 -rw-r--r-- 1 dmdba dinstall 134217728 9月 4 14:41 ARCHIVE_LOCAL_0x695BD122_EP0_2024-09-04_14-40-40.log [dmdba@test dmarch]$ disql sysdba/SYSDBA Server[LOCALHOST:5236]:mode is primary, state is open login used time : 2.514(ms) disql V8 SQL> alter system archive log current; executed successfully used time: 4.822(ms). Execute id is 0. SQL> exit [dmdba@test dmarch]$ ls -ltr 总用量 30496 -rw-r--r-- 1 dmdba dinstall 31227904 9月 4 14:42 ARCHIVE_LOCAL_0x695BD122_EP0_2024-09-04_14-40-40.log

4、dmlcvt解析归档文件(PS:存放解析结果的目录需要提前创建)

[dmdba@test rec]$ dmlcvt F_TYPE=1 F_PATH=/dmarch OP_TYPE=1 REC_DATA=1 OUT_PATH=/dmdata/rec DMLCVT V8 Total arch file counts:1 file name:/dmarch/ARCHIVE_LOCAL_0x695BD122_EP0_2024-09-04_14-40-40.log version=0x7007, arch_lsn=6083824, clsn=6285765, arch_seq=98371, next_seq=98515, g_next_seq=98515, src_db_magic=1767624994, pmnt_magic=819081852, db_magic=1767624994, dsc_seqno=0, dsc_node=1, crt_time=2024-09-04 14:40:40.937919, lclose_time=2024-09-04 14:42:55.826005 Arch file /dmarch/ARCHIVE_LOCAL_0x695BD122_EP0_2024-09-04_14-40-40.log finished. analyze start time: 2024-09-04 14:43:14.547333 +08:00 analyze end time: 2024-09-04 14:43:16.200525 +08:00

5、查看结果,解析后会在OUT_PATH=/dmdata/rec目录下生成结果文件,主要分析rec_info*.txt,检索关键字"UREC"可以查看到归档中记录的数据库操作

[dmdba@test rec]$ ls file_info000.txt page_info000.txt rec_info000.txt warn_info000.txt

这里直接通过awk脚本对结果进行统计

[dmdba@test rec]$ awk '{ match($0, /UREC_[A-Z]+:/);Operation = substr($0, RSTART, RLENGTH); match($0, /tabid:[0-9a-fA-Fx]+\(\)/);tabid = substr($0, RSTART, RLENGTH); if (Operation != "" && tabid != "") { print Operation, tabid; } }' rec_info*.txt |sort |uniq -c 50000 UREC_DEL: tabid:0x402() 100000 UREC_INS: tabid:0x401() 1 UREC_TRUNC: tabid:0x401() 1 UREC_TRUNC: tabid:0x402() 50000 UREC_UPD: tabid:0x401()

结果中的tabid是以十六进制的方式显示的,可以在数据库中通过utl_raw.cast_to_int方法将其转换成数字格式,即可找到DML操作的表名

SQL> select owner,object_name,object_id,object_type,last_ddl_time from dba_objects where object_id = utl_raw.cast_to_int('0x401'); LINEID OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE LAST_DDL_TIME ---------- ----- ----------- --------- ----------- -------------------------- 1 HR TEST1 1025 TABLE 2024-09-04 14:42:28.000000 SQL> select owner,object_name,object_id,object_type,last_ddl_time from dba_objects where object_id = utl_raw.cast_to_int('0x402'); LINEID OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE LAST_DDL_TIME ---------- ----- ----------- --------- ----------- -------------------------- 1 HR TEST2 1026 TABLE 2024-09-04 14:42:28.000000

四、总结

1、当没有开启逻辑附件日志无法进行日志挖掘,并且sql日志也没有相关记录的情况下,dmlcvt工具可以针对某个时间段的归档文件进行批量解析,即可统计出这个时间段内数据库都对什么表做了哪些操作,便于排查分析;
2、dmlcvt工具需要解析完整归档文件;
3、dmlcvt的解析可以不在原库执行,也可以将归档文件拷贝到其他环境进行分析;

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服