Oracle redo解析之-3、常見change分析

門牙發表於2019-04-16

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。
複製程式碼

相關文章