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;
複製代碼
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;
複製代碼
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常出如今回滾事務中。
複製代碼
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
複製代碼
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時相同,塊清除信息我的以爲用不上。
複製代碼
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的相同。
複製代碼
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'。
複製代碼
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;
複製代碼
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字節,表示三個字段的值的長度。(不理解的能夠跳到本文末尾看計算例子)。
複製代碼
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;
複製代碼
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,這裏再也不贅述,想不通的話,能夠聯繫我。
複製代碼
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。
複製代碼