KTB分析(常見的change11.x系列的第一部分)
op=0x01
KTB Redo
op: 0x01 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0002.01c.00000254 uba: 0x00c080f1.0060.0e
對應的結構:
typedef struct KTB{
uint8_t op; //0x01
uint24_t unknown0;
unit32_t unknown1;
unit16_t xid0;
uint16_t xid1;
uint32_t xid2;
uint32_t uba0;
uint16_t uba1;
uint8_t uba2;
uint8_t unknown2;
}KTB;
複製程式碼
op=0x02
KTB Redo
op: 0x02 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: C uba: 0x00c0d5b7.0082.1d
對應的結構:
typedef struct KTB{
uint8_t op;
uint24_t unknown0;
uint32_t unknown1;
uint32_t uba0;
uint16_t uba1;
uint8_t uba2;
uint8_t unknown2;
}KTB;
複製程式碼
op=0x03 & op=0x04
KTB Redo
op: 0x03 ver: 0x01
compat bit: 4 (post-11) padding: 1
op:Z
複製程式碼
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0007.00b.0000057d uba: 0x00c004b7.007b.0b
flg: C--- lkc: 0 scn: 0x0000.001868a7
複製程式碼
op=0x03和op=0x04常出現在回滾事務中。
複製程式碼
op=0x05
KTB Redo
op: 0x05 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: R itc: 1
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0005.001.00000291 0x00c118ad.0066.01 -B-- 1 fsc 0x0000.00000000
複製程式碼
op=0x11
KTB Redo
op: 0x11 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0003.00e.00000245 uba: 0x00c0d5b7.0082.1c
Block cleanout record, scn: 0x0000.000a813e ver: 0x01 opt: 0x02, entries follow...
itli: 1 flg: 2 scn: 0x0000.000a80e5
itli: 2 flg: 2 scn: 0x0000.000a8059
對應的結構:
Block cleanout record開始是塊清除資訊,之前的資訊跟op=0x01時相同,塊清除資訊個人覺得用不上。
複製程式碼
op=0x12
KTB Redo
op: 0x12 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: C uba: 0x00c0f5f8.0060.32
Block cleanout record, scn: 0x0000.000ad642 ver: 0x01 opt: 0x02, entries follow...
itli: 1 flg: 2 scn: 0x0000.000ad642
對應的結構:
Block cleanout record之前的結構跟op=0x02的相同。
複製程式碼
常見change分析
opcode=11.2,insert操作
SQL> insert into t1 values (2, 'wsdecx');
CHANGE #1 TYP:2 CLS:1 AFN:1 DBA:0x00414f01 OBJ:73439 SCN:0x0000.000f5aba SEQ:5 OP:11.2 ENC:0 RBL:0
KTB Redo
op: 0x01 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0003.01b.00000330 uba: 0x00c02886.00ac.36
KDO Op code: IRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00414f01 hdba: 0x00414f00
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 1(0x1) size/delt: 13
fb: --H-FL-- lb: 0x2 cc: 2
null: --
col 0: [ 2] c1 03
col 1: [ 6] 77 73 64 65 63 78
insert操作產生的change可以分成3部分,KTB-KDO-實際資料,其中KTB記錄了事務ID和UBA等資訊,KDO記錄了表號,行號slot,資料塊地址bdba,資料段地址hdba等,第三部分的col 0,col 1即本次insert操作的資料。
其中KTB的結構根據op引數的值不同,有不同的結構。
KTB:請看KTB 分析。
KDO結構:
typedef struct KDO{
uint32_t bdba;
uint32_t hdba;
uint16_t maxfr;
uint16_t unknown0;
uint8_t itli;
uint24_t unknown1;
uint8_t fb; //標誌
uint8_t lb;
uint8_t cc;
uint8_t unknown2;
uint32_t unknown3[5];
uint16_t size/delt;
uint16_t slot; //行號
uint8_t tabn; //表編號,簇表中使用
uint24_t unknown4;
uint32_t unknown5;
}KDO;
第三部分,是本次insert實際影響了的資料,從表的第一個欄位開始。其中c1 03是2(型別轉換後續會講解),77 73 64 65 63 78是ASCII碼儲存,轉換後是'wsdecx'。
複製程式碼
opcode=11.3,delete操作
SQL> delete from t1 where id=2;
1 row deleted.
CHANGE #1 TYP:2 CLS:1 AFN:1 DBA:0x00414f01 OBJ:73439 SCN:0x0000.000f6468 SEQ:2 OP:11.3 ENC:0 RBL:0
KTB Redo
op: 0x01 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0006.001.0000033e uba: 0x00c001ad.00d1.33
KDO Op code: DRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00414f01 hdba: 0x00414f00
itli: 2 ispac: 0 maxfr: 4863
tabn: 0 slot: 1(0x1)
delete操作產生的change分成2部分,KTB-KDO,因為根據rowid(後續會講)可以唯一確定一行,所以不需要再記錄其他資訊了。
KTB:請看KTB 分析。
KDO:
typedef struct KDO{
uint32_t bdba;
uint32_t hdba;
uint16_t maxfr;
uint16_t unknown0;
uint8_t itli;
uint24_t unknown1;
uint16_t slot;
uint16_t unknown2
}KDO;
複製程式碼
opcode=11.5,update操作
SQL> update t2 set id=34,name='wertyu' where id1=22;
CHANGE #1 TYP:2 CLS:1 AFN:1 DBA:0x00414f09 OBJ:73444 SCN:0x0000.000f6832 SEQ:2 OP:11.5 ENC:0 RBL:0
KTB Redo
op: 0x11 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0006.00f.00000347 uba: 0x00c001da.00d1.31
Block cleanout record, scn: 0x0000.000fd835 ver: 0x01 opt: 0x02, entries follow...
itli: 2 flg: 2 scn: 0x0000.000f6832
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00414f09 hdba: 0x00414f08
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 1 ckix: 0
ncol: 3 nnew: 2 size: -1
col 0: [ 2] c1 23
col 2: [ 6] 77 65 72 74 79 75
對於一個update操作,分成四個部分:KTB、KDO、update更新的欄位編號、update更新的欄位值。
KTB:請看KTB 分析。
KDO:
typedef struct KDO{
uint32_t bdba;
uint32_t hdba;
uint16_t maxfr;
uint16_t unknown0;
uint8_t itli; //位數不確定
uint24_t unknown1;
uint8_t flag;
uint8_t lock;
uint8_t ckix;
uint8_t tabn;
uint16_t slot;
uint8_t ncol;
uint8_t nnew;
uint...[不知道是什麼]
}KDO;
第三部分:
update操作的欄位編號,總長度由向量表中計算,其中2個位元組表示一個欄位編號。
第四部分:
update操作的欄位內容,總長度由向量表中決定。
假設本次update更新了三個欄位的值,則在向量表中欄位編號後還有3個2位元組,表示三個欄位的值的長度。(不理解的可以跳到本文末尾看計算例子)。
複製程式碼
opcode=5.2, 操作回滾段頭
CHANGE #2 TYP:0 CLS:21 AFN:3 DBA:0x00c000a0 OBJ:4294967295 SCN:0x0000.000fc606 SEQ:2 OP:5.2 ENC:0 RBL:0
ktudh redo: slt: 0x0001 sqn: 0x00000338 flg: 0x000a siz: 136 fbi: 0
uba: 0x00c028b0.00ac.01 pxid: 0x0000.000.00000000
對於一個5.2操作,表示一個事務的開始,分成一個部分,記錄本次事務分配的第一個undo塊的地址,以及事務id(即xid)。
ktudh:
typedef struct KTUDH{
uint16_t slt; //xid1
uint16_t unknown0;
uint32_t sqn; //xid2
uint32_t uba0;
uint16_t uba1;
uint8_t uba2;
uint8_t unknown1;
uint16_t flg;
uint16_t siz;
uint16_t pxid0;
uint16_t pxid1;
uint32_t pxid2;
}KTUDH;
複製程式碼
opcode=5.1, 記錄前映象資料
CHANGE #4 TYP:1 CLS:22 AFN:3 DBA:0x00c028b0 OBJ:4294967295 SCN:0x0000.000fc634 SEQ:1 OP:5.1 ENC:0 RBL:0
ktudb redo: siz: 136 spc: 0 flg: 0x000a seq: 0x00ac rec: 0x01
xid: 0x0003.001.00000338
ktubl redo: slt: 1 rci: 0 opc: 11.1 [objn: 73439 objd: 73439 tsn: 0]
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
0x00000000 prev ctl uba: 0x00c028af.00ac.31
prev ctl max cmt scn: 0x0000.000fc23e prev tx cmt scn: 0x0000.000fc24d
txn start scn: 0x0000.000fc500 logon user: 0 prev brb: 12593322 prev bcl: 0 BuExt idx: 0 flg2: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0001.006.00000267 uba: 0x00c00133.0074.2f
flg: C--- lkc: 0 scn: 0x0000.000f65c2
KDO Op code: DRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00414f01 hdba: 0x00414f00
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 1(0x1)
對於一個5.1操作,隨著其他操作而變化,舉例:執行一個11.2時,產生的5.1是分成4個部分的(ktudb、ktubl/ktubu、KTB、KDO), 執行一個11.3時,產生的5.1是分成5個部分的(ktudb、ktubl/ktubu、KTB、KDO、實際資料),具體情況具體分析。
ktudb:
typedef struct ktudb{
uint16_t siz;
uint16_t spc;
uint16_t flg;
uint16_t unknown0;
uint16_t xid0;
uint16_t xid1;
uint32_t xid2;
uint16_t seg; //uba1
uint8_t rec; //uba2
uint8_t unknown1;
}ktudb;
ktubl(是事務的第一個5.1時):
typedef struct ktubl{
uint32_t objn;
uint32_t objd;
uint32_t tsb; //表空間編號,猜測是4位元組
uint32_t unknown1;
uint8_t opc0;
uint8_t upc1;
uint8_t slt;
uint8_t rci;
uint32_t unknown2[2];
uint32_t prev ctl uba0;
uint16_t prev ctl uba1;
uint8_t prev ctl uba2;
uint8_t unknown3;
uint32_t prev ctl max cmt scn_base;
uint16_t prev ctl max cmt scn_wrapper;
uint16_t unknown4;
uint32_t prev tx cmt scn_base;
uint16_t prev tx cmt scn_wrapper;
uint16_t unknown4;
uint32_t unknown5;
uint32_t txn start scn_base;
uint16_t txn start scn_wrapper;
uint16_t unknown6;
uint32_t prev brb;
uint32_t unknown7;
uint16_t logon user; //位數不確定,執行這個事務的使用者
uint16_t unknown8;
}ktubl;
ktubu(不是事務的第一個5.1時):
ktubu redo: slt: 25 rci: 5 opc: 11.1 objn: 66450 objd: 66450 tsn: 6
Undo type: Regular undo Undo type: Last buffer split: No
Tablespace Undo: No
0x00000000
typedef struct ktubu{
uint32_t objn;
uint32_t objd;
uint32_t tsn; //表空間編號,位數不確定
uint32_t unknown0;
uint8_t opc0;
uint8_t opc1;
uint8_t slt;
uint8_t rci;
uint32_t unknown1;
}ktubu;
KTB,KDO等這些都是對應11.x操作的相反操作,例如:11.2對應11.3,11.3對應11.2,11.5對應11.5,這裡不再贅述,想不通的話,可以聯絡我。
複製程式碼
opcode=5.4,commit操作,表示一個事務的結束
CHANGE #3 TYP:0 CLS:21 AFN:3 DBA:0x00c000a0 OBJ:4294967295 SCN:0x0000.000fc635 SEQ:1 OP:5.4 ENC:0 RBL:0
ktucm redo: slt: 0x0001 sqn: 0x00000338 srt: 0 sta: 9 flg: 0x2
ktucf redo: uba: 0x00c028b0.00ac.01 ext: 26 spc: 8012 fbi: 0
對於一個5.4操作,結構視情況而定。
ktucm:
typedef struct ktucm{
uint16_t slt;
uint16_t unknown0;
uint32_t sqn; //xid2
uint32_t unknown1;
uint8_t sta;
uint24_t unknown2;
uint8_t flg;
uint24_t unknown3;
}
情況一:
事務commit後,最後使用的undo塊中還有空間可以提交給別的事務使用時,5.4中會記錄將undo塊提交到空閒池列表中。此時ktucm的flg會等於0x02或0x12。
此時5.4結構為ktucm-ktucf-未知4位元組
typedef struct ktucf{
uint32_t uba0;
uint16_t uba1;
uint8_t uba2;
uint8_t unknown0;
uint16_t ext;
uint16_t spc;
uint32_t unknown1;
}ktucf;
第三部分是固定的4位元組,作用未知。
情況二:
事務commit後,最後使用的undo塊中沒有空間給別的事務時,此時5.4的結構為ktucm-未知4位元組。此時ktucm的flg引數為0x00或0x10。
情況三:
事務回滾時,5.4的結構為ktucm-未知4位元組,此時ktucm的flg引數為0x04或0x14。
複製程式碼
最後
常用的change還有11.11(批量更新),11.12(批量刪除),11.19(陣列更新),可以先對11.2,11.3,11.5做大量練習後再看這幾個opcode,先佔坑,遲點更新。
複製程式碼
計算
舉例11.5的例子,11.5理解之後,11.2和11.3也容易理解了。
CHANGE #1 TYP:2 CLS:1 AFN:1 DBA:0x00414f09 OBJ:73444 SCN:0x0000.000f6832 SEQ:2 OP:11.5 ENC:0 RBL:0
KTB Redo
op: 0x11 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: F xid: 0x0006.00f.00000347 uba: 0x00c001da.00d1.31
Block cleanout record, scn: 0x0000.000fd835 ver: 0x01 opt: 0x02, entries follow...
itli: 2 flg: 2 scn: 0x0000.000f6832
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x00414f09 hdba: 0x00414f08
itli: 1 ispac: 0 maxfr: 4863
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 1 ckix: 0
ncol: 3 nnew: 2 size: -1
col 0: [ 2] c1 23
col 2: [ 6] 77 65 72 74 79 75
二進位制:
[change header]
0b050100 01000100 094f4100 32680f00 00004000 0202e41e
[change length list]
0c004000 1d000400 02000600
[第一部分]
110d0000 00000000 06000f00 47030000 da01c000 d1003100 00000000 00000000
00000000 00000000 00000000 02010100 35d80f00 00000000 02020000 32680f00
[第二部分]
094f4100 084f4100 ff120501 01000000 2c010000 00000302 ffff0000 00000000
[第三部分]
00000200
[欄位值]
c1237704
77657274 79754007
[注意]這裡我已經區分了,只取11.5這部分的二進位制,如果對結構計算海不熟練的話,需要回去重看redo_struct.md檔案。
從change length list中可以得知,欄位編號部分長度為4,值是00000200,計算得到:0, 2,
redo中計算欄位編號從0開始,而資料庫中從1開始。根據欄位編號查詢COL$表可以得到欄位名稱。
從change length list中可以得知,第一個欄位值的長度為2,取值:c1 23,第二個欄位值的長度為6,取值:77 65 72 74 79 75。
複製程式碼