3. XLog 분석#
이 장은 XLog를 분석하기 위해 필요한 XLog, Meta 정보, Altibase Internal Data Type 등에 대해 설명한다.
XLog와 Meta 정보는 Log Analysis API로 얻을 수 있다.
XLog#
XLog의 종류와 구성 요소를 설명한다.
사용자는 XLog를 얻기 위해 ALA_GetXLog()를 호출해야 한다.
XLog의 종류#
typedef enum
{
XLOG_TYPE_COMMIT = 2, /* Transaction Commit */
XLOG_TYPE_ABORT = 3, /* Transaction Rollback */
XLOG_TYPE_INSERT = 4, /* DML: Insert */
XLOG_TYPE_UPDATE = 5, /* DML: Update */
XLOG_TYPE_DELETE = 6, /* DML: Delete */
XLOG_TYPE_SP_SET = 8, /* Savepoint Set */
XLOG_TYPE_SP_ABORT = 9, /* Abort to savepoint */
XLOG_TYPE_LOB_CURSOR_OPEN = 14, /* LOB Cursor open */
XLOG_TYPE_LOB_CURSOR_CLOSE = 15, /* LOB Cursor close */
XLOG_TYPE_LOB_PREPARE4WRITE = 16, /* LOB Prepare for write */
XLOG_TYPE_LOB_PARTIAL_WRITE = 17, /* LOB Partial write */
XLOG_TYPE_LOB_FINISH2WRITE = 18, /* LOB Finish to write */
XLOG_TYPE_KEEP_ALIVE = 19, /* Keep Alive */
XLOG_TYPE_REPL_STOP = 21, /* Replication Stop */
XLOG_TYPE_LOB_TRIM = 35, /* LOB Trim */
XLOG_TYPE_CHANGE_META = 25 /* Meta change by DDL */
} ALA_XLogType;
XLog에는 13 가지의 트랜잭션 관련 XLog, 2 가지의 Control 관련 XLog가 있다.
트랜잭션 관련 XLog는 XLOG_TYPE_COMMIT이나 XLOG_TYPE_ABORT로 끝난다.
LOB은 큰 데이터이므로, LOB에 대한 갱신 작업은 다수의 XLog로 구성될 수 있다. 이 경우에는 LOB 관련 XLog가 아래와 같은 구조로 수신된다.
XLOG_TYPE_LOB_CURSOR_OPEN
{
XLOG_TYPE_LOB_PREPARE4WRITE
{
XLOG_TYPE_LOB_PARTIAL_WRITE
...
}
XLOG_TYPE_LOB_FINISH2WRITE
...
또는
XLOG_TYPE_LOB_TRIM
…
}
XLOG_TYPE_LOB_CURSOR_CLOSE
Control 관련 XLog는 KEEP_ALIVE와 REPL_STOP이다.
KEEP_ALIVE는 XLog Sender에서 전송할 XLog가 없을 때, 네트워크 연결이 유지됨을 확인하기 위해 전송하는 XLog이다.
REPL_STOP은 XLog Sender가 정상 종료하는 것을 나타낸다. ALA_SendACK()를 호출한 다음에 네트워크 연결이 끊어진다.
CHANGE_META는 XLog Sender에서 DDL발생으로 인한 meta 정보 변경을 보여준다. XLog Sender는 CHANGE_META를 전송한 후에 새로운 meta정보로써 XLog를 전송하게 되므로 ALA 응용프로그램에 meta정보를 재전송 해주어야 한다. 따라서 ALA응용프로그램이 이를 처리할 수 있도록 XLog Sender는 CHANGE_META에 이어서 REPL_STOP을 보내고 재 접속을 시도한다.
XLog 구조체#
typedef UInt ALA_TID; /* Transaction ID */
typedef ULong ALA_SN; /* Log Record SN */
typedef struct ALA_Value /* Altibase Internal Data */
{
UInt length; /* Length of value */
const void * value;
} ALA_Value;
구조체 멤버 | 설 명 |
---|---|
길이 (length) | Altibase 내부 데이터 값의 길이 |
값 (value) | Altibase 내부 데이터 값 |
typedef struct ALA_XLogHeader /* XLog Header */
{
ALA_XLogType mType; /* XLog Type */
ALA_TID mTID; /* Transaction ID */
ALA_SN mSN; /* SN */
ALA_SN mSyncSN; /* Reserved */
ALA_SN mRestartSN; /* Used internally */
ULong mTableOID; /* Table OID */
} ALA_XLogHeader;
typedef struct ALA_XLogPrimaryKey /* Primary Key */
{
UInt mPKColCnt; /* Primary Key Column Count */
ALA_Value *mPKColArray; /* Primary Key Column Value Array */
} ALA_XLogPrimaryKey;
typedef struct ALA_XLogColumn /* Column */
{
UInt mColCnt; /* Column Count */
UInt *mCIDArray; /* Column ID Array */
ALA_Value *mBColArray; /* Before Image Column Value Array */
ALA_Value *mAColArray; /* After Image Column Value Array */
} ALA_XLogColumn;
typedef struct ALA_XLogSavepoint /* Savepoint */
{
UInt mSPNameLen; /* Savepoint Name Length */
SChar *mSPName; /* Savepoint Name */
} ALA_XLogSavepoint;
typedef struct ALA_XLogLOB /* LOB */
{
ULong mLobLocator; /* LOB Locator of Altibase */
UInt mLobColumnID;
UInt mLobOffset;
UInt mLobOldSize;
UInt mLobNewSize;
UInt mLobPieceLen;
UChar *mLobPiece;
} ALA_XLogLOB;
typedef struct ALA_XLog /* XLog */
{
ALA_XLogHeader mHeader;
ALA_XLogPrimaryKey mPrimaryKey;
ALA_XLogColumn mColumn;
ALA_XLogSavepoint mSavepoint;
ALA_XLogLOB mLOB;
/* Used internally */
struct ALA_XLog *mPrev;
struct ALA_XLog *mNext;
} ALA_XLog;
XLog구조체는 Header, Primary Key, Column, Savepoint, LOB관련 구조체로 구성된다.
각 부분은 ALA_XLog구조체에서 직접 얻거나 XLog 관련 Log Analysis API를 사용하여 얻을수 있다.
ALA_XLogPrimaryKey구조체에는 Primary Key Column ID Array가 없다. 이것은 테이블의 메타 정보를 가지고 있는 ALA_Table구조체의 mPKColumnArray[sIndex]->mColumnID 로 얻을 수 있다. 테이블의 메타 정보는 ALA_GetTableInfo()이나 ALA_GetTableInfoByName()으로 얻을 수 있다.
XLog의 종류에 따른 구성#
XLog의 종류는 ALA_XLogHeader의 mType 멤버로 알 수 있다.
COMMIT XLog#
Header (mType, mTID, mSN, mSyncSN)
ABORT XLog#
Header (mType, mTID, mSN, mSyncSN)
INSERT XLog#
Header (mType, mTID, mSN, mSyncSN, mTableOID)
Column (mColCnt, mCIDArray, mAColArray)
UPDATE XLog#
Header (mType, mTID, mSN, mSyncSN, mTableOID)
Primary Key (mPKColCnt, mPKColArray)
Column (mColCnt, mCIDArray, mBColArray, mAColArray)
DELETE XLog#
Header (mType, mTID, mSN, mSyncSN, mTableOID)
Primary Key (mPKColCnt, mPKColArray)
SP_SET XLog#
Header (mType, mTID, mSN, mSyncSN)
Savepoint (mSPNameLen, mSPName)
-
mSPName이 "$$IMPLICIT"로 시작하면, Implict Savepoint 이다.
-
mSPName이 "$$PSM_SVP"이면, PSM Savepoint이다.
SP_ABORT XLog#
Header (mType, mTID, mSN, mSyncSN)
Savepoint (mSPNameLen, mSPName)
-
mSPName이 "$$IMPLICIT"로 시작하면, Implict Savepoint이다.
-
mSPName이 "$$PSM_SVP"이면, PSM Savepoint이다.
LOB_CURSOR_OPEN XLog#
Header (mType, mTID, mSN, mSyncSN, mTableOID)
Primary Key (mPKColCnt, mPKColArray)
LOB (mLobLocator, mLobColumnID)
LOB_CURSOR_CLOSE XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB (mLobLocator)
LOB_PREPARE4WRITE XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB (mLobLocator, mLobOffset, mLobOldSize, mLobNewSize)
LOB_PARTIAL_WRITE XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB (mLobLocator, mLobOffset, mLobPieceLen, mLobPiece)
- mLobOffset는 LOB_PREPARE4WRITE XLog의 mLobOffset을 기준으로 상대적인 위치이다.
LOB_FINISH2WRITE XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB (mLobLocator)
KEEP_ALIVE XLog#
Header (mType, mTID, mSN, mSyncSN)
REPL_STOP XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB_TRIM XLog#
Header (mType, mTID, mSN, mSyncSN)
LOB (mLobLocator, mLobOffset)
- mLobOffset은 삭제(trim)된 LOB 데이터 바이트 단위의 시작 위치이다.
CHANGE_META#
Header (mType, mTID, mSN, mSyncSN)
- mSN은 현재까지 처리한 변경 로그의 마지막 순서번호이며, mTID, mSyncSN은 사용자에게 의미 없는 값이다.
메타 정보#
XLog를 해석할 수 있는 메타 정보를 얻는 방법을 설명한다.
사용자는 메타 정보를 얻기 전에 ALA_Handshake()를 호출해야 한다.
Meta 정보 구조체#
typedef struct ALA_ProtocolVersion
{
UShort mMajor; /* Major Version */
UShort mMinor; /* Minor Version */
UShort mFix; /* Fix Version */
} ALA_ProtocolVersion;
typedef struct ALA_Replication
{
SChar mXLogSenderName[ALA_NAME_LEN]; /* XLog Sender Name */
UInt mTableCount; /* Table Count */
ALA_Table *mTableArray; /* Table Array */
SChar mDBCharSet[ULA_NAME_LEN]; /* DB Charter Set */
SChar mDBNCharSet[ULA_NAME_LEN]; /* DB National Charter Set */
ULong mSenderVersion; /* Sender Version */
} ALA_Replication;
typedef struct ALA_Table
{
ULong mTableOID; /* Table OID */
SChar mFromUserName[ALA_NAME_LEN]; /* (From) User Name */
SChar mFromTableName[ALA_NAME_LEN]; /* (From) Table Name */
SChar mToUserName[ALA_NAME_LEN]; /* (To) User Name */
SChar mToTableName[ALA_NAME_LEN]; /* (To) Table Name */
UInt mPKIndexID; /* Index ID of Primary Key */
UInt mPKColumnCount; /* Primary Key Column Count */
ALA_Column **mPKColumnArray; /* Primary Key Column Array */
UInt mColumnCount; /* Column Count */
ALA_Column *mColumnArray; /* Column Array */
UInt mIndexCount; /* Index Count */
ALA_Index *mIndexArray; /* Index Array */
} ALA_Table;
typedef struct ALA_Column
{
UInt mColumnID; /* Column ID */
SChar mColumnName[ALA_NAME_LEN]; /* Column Name */
UInt mDataType; /* Column Data Type */
UInt mLanguageID; /* Column Language ID */
UInt mSize; /* Column Size */
SInt mPrecision; /* Column Precision */
SInt mScale; /* Column Scale */
ALA_BOOL mNotNull; /* Column Not Null? */
} ALA_Column;
typedef struct ALA_Index
{
UInt mIndexID; /* Index ID */
SChar mIndexName[ALA_NAME_LEN]; /* Index Name */
ALA_BOOL mUnique; /* Index Unique? */
UInt mColumnCount; /* Index Column Count */
UInt *mColumnIDArray; /* Index Column ID Array */
} ALA_Index;
Meta 정보에는 Protocol Version, Replication, Table, Column, Index가 있다.
ALA_Table 구조체의 mPKColumnArray 멤버는 ALA_Column 포인터의 배열이다.
Altibase 데이터 타입과 저장 구조체#
이 절에서는 내부에서 데이터가 저장되는 구조를 Altibase 데이터 타입별로 설명한다.
칼럼정보(ALA_Column)는 ALA_GetColumnInfo()를 호출해서 얻고, 컬럼의 데이터(ALA_Value)는 XLog 관련 Log Analysis API를 사용해서 얻는다.
컬럼의 데이터 값은 ALA_Value 구조체의 value 멤버이고, 컬럼의 데이터 값의 길이는 ALA_Value 구조체의 length 멤버이다.
내부 데이터 타입의 종류는 ALA_Column의 mDataType 값으로 알 수 있다.
카테고리 | 내부 데이터의 종류 | 상수 |
---|---|---|
숫자 |
FLOAT |
6 |
NUMERIC |
2 |
|
DOUBLE |
8 |
|
REAL |
7 |
|
BIGINT |
(UInt)-5 |
|
INTEGER |
4 |
|
SMALLINT |
5 |
|
날짜/시간 |
DATE |
9 |
문자/이진 |
CHAR |
1 |
VARCHAR |
12 |
|
NCHAR |
(UInt)-8 |
|
NVARCHAR |
(UInt)-9 |
|
BYTE |
20001 |
|
NIBBLE |
20002 |
|
BIT |
(UInt)-7 |
|
VARBIT |
(UInt)-100 |
|
BLOB |
30 |
|
CLOB |
40 |
|
공간 |
GEOMETRY |
10003 |
[표 3‑1] Altibase 내부 데이터 종류
FLOAT, NUMERIC#
내부 구조#
FLOAT와 NUMERIC의 내부 데이터 구조는 같다.
typedef struct mtdNumericType
{
UChar length; /* Length of (signExponent + mantissa) */
UChar signExponent; /* Sign and Exponent */
UChar mantissa[1]; /* UChar Array (Base 100) */
} mtdNumericType;
부호와 지수값은 ALA_GetInternalNumericInfo()를 호출하거나, 아래와 같이 mtdNumericType 구조체의 요소 값을 통해서 구할 수 있다.
mtdNumericType에서 Sign 얻기#
if(signExponent is 128 ~ 255)
{
Sign = '+';
}
else /* if(signExponent is 0 ~ 127) */
{
Sign = '-';
}
mtdNumericType에서 Exponent 얻기#
10진수에 대한 Exponent이다.
if(signExponent is 128 ~ 255)
{
Exponent = ((SInt)(signExponent & 0x7F) - 64) * 2
+ ((mantissa[0] < 10) ? -1 : 0);
}
else /* if(signExponent is 0 ~ 127) */
{
Exponent = (64 - (SInt)(signExponent & 0x7F)) * 2
+ ((mantissa[0] >= 90) ? -1 : 0);
}
mtdNumericType에서 Mantissa 문자열 얻기#
각 UChar는 0 ~ 99의 값을 가진다. (각 UChar 의 값은 100진수)
결과는 0과 1 사이의 수이다.
if(Sign is '+')
{
/* Example : 01 23 45 67 89 -> 0.123456789
/* 12 34 56 78 99 -> 0.1234567899
*/
/* mantissa[0] */
if(mantissa[0] < 10)
{
MantissaStr = mantissa[0];
}
else
{
MantissaStr = mantissa[0] / 10;
MantissaStr = MantissaStr + mantissa[0] % 10;
}
/* mantissa[1] ~ mantissa[mLength - 1] */
for(Index = 1; Index < mLength - 1; Index++)
{
MantissaStr = MantissaStr + mantissa[Index] / 10;
MantissaStr = MantissaStr + mantissa[Index] % 10;
}
}
else /* if(Sign is '-') */
{
/* Example : 98 76 54 32 10 -> 0.123456789
/* 09 87 65 43 21 -> 0.9012345678
*/
/* mantissa[0] */
if(mantissa[0] >= 90)
{
MantissaStr = MantissaStr + (99 - mantissa[0]);
}
else
{
MantissaStr = MantissaStr + (99 - mantissa[0]) / 10;
MantissaStr = MantissaStr + (99 - mantissa[0]) % 10;
}
/* mantissa[1] ~ mantissa[mLength - 1] */
for(Index = 1; Index < mLength - 1; Index++)
{
MantissaStr = MantissaStr + (99 - mantissa[Index]) / 10;
MantissaStr = MantissaStr + (99 - mantissa[Index]) % 10;
}
}
DOUBLE, REAL, BIGINT, INTEGER, SMALLINT#
내부 구조#
각 타입은 Primitive Data Type과 매핑된다.
typedef SDouble mtdDoubleType; /* DOUBLE */
typedef SFloat mtdRealType; /* REAL */
typedef SLong mtdBigintType; /* BIGINT */
typedef SInt mtdIntegerType; /* INTEGER */
typedef SShort mtdSmallintType; /* SMALLINT */
DATE#
내부 구조#
시간과 날짜에 관련된 내부 데이터 타입은 하나만 존재한다.
typedef struct mtdDateType
{
SShort year; /* Year(16bit) */
UShort mon_day_hour; /* Not Used(2bit), Month(4bit), */
/* Day(5bit), Hour(5bit) */
UInt min_sec_mic; /* Minute(6bit), Second(6bit), */
/* MicroSec(20bit) */
} mtdDateType;
CHAR, VARCHAR, NCHAR, NVARCHAR, BYTE, NIBBLE, BIT, VARBIT, BLOB, CLOB#
내부 구조#
각 데이터 타입은 비슷한 구조를 가진다.
typedef struct mtdCharType /* CHAR, VARCHAR */
{
UShort length; /* Length of value */
UChar value[1]; /* UChar Array */
} mtdCharType;
typedef struct mtdNcharType
{ /*NCHAR, NVARCHAR */
UShort length; /* Length of value */
UChar value[1]; /* UChar Array */
} mtdNcharType;
typedef struct mtdByteType /* BYTE */
{
UShort length; /* Length of value */
UChar value[1]; /* UChar Array */
} mtdByteType;
typedef struct mtdNibbleType /* NIBBLE */
{
UChar length; /* Length of Nibbles */
UChar value[1]; /* UChar Array */
} mtdNibbleType;
typedef struct mtdBitType /* BIT, VARBIT */
{
UInt length; /* Length of Bits */
UChar value[1]; /* UChar Array */
} mtdBitType;
typedef struct mtdLobType
{
UInt length; /* Length of value */
UChar value[1]; /* UChar Array */
} mtdLobType;
typedef mtdLobType mtdBlobType; /* BLOB */
typedef mtdLobType mtdClobType; /* CLOB */
BLOB, CLOB타입의 데이터는 ALA_GetAltibaseText(), ALA_GetAltibaseSQL(), ALA_GetODBCCValue()함수의 인자로 사용할 수 없다.
NIBBLE타입 구조체의 length요소의 유효값은 0 ~ 254 이다. length 가 255이면 NULL값을 가리킨다.
GEOMETRY#
내부 구조#
Geometry 데이터의 구조 및 처리 방법은 Spatial SQL Reference을 참고한다.
GEOMETRY데이터는 ALA_GetAltibaseText(), ALA_GetAltibaseSQL(), ALA_GetODBCCValue() 함수의 인자로 사용할 수 없다.
SAVEPOINT#
SAVEPOINT를 지정하면 트랜잭션 처리 과정에서 지금까지 실행된 트랜잭션이 임시로 저장된다.
Altibase에서 사용할 수 있는 SAVEPOINT는 다음과 같이 구분된다.
-
Implicit Savepoint
-
Explicit Savepoint
-
PSM Savepoint
Implicit Savepoint는 트랜잭션 관련 문장(Statement)을 실행하면 내부적으로 Savepoint가 사용되고 이는 트랜잭션별로 하나의 리스트로 관리된다. 문장을 실패할 경우 해당 문장만 자동으로 부분 롤백(Partial Rollback)을 하기 위해 사용된다.
Explicit Savepoint는 사용자가 명시적으로 지정하는 것으로 트랜잭션별로 하나의 리스트로 관리된다. Explicit Savepoint에 대한 자세한 설명은 SQL Reference을 참조한다.
PSM Savepoint는 저장 프로시저(PSM)를 실행할 때 내부적으로 사용되는 Savepoint이다. PSM을 실행 할 때에만 Savepoint가 관리된다. 저장 프로시저에 대한 자세한 설명은 Stored Procedures Manual을 참조한다.
SAVEPOINT는 종류별로 관리되며, savepoint xlog는 애플리케이션 내에서 상황에 따라 처리하면 된다.
예제
iSQL> CREATE TABLE T1 (I1 INTEGER PRIMARY KEY);
Create success.
iSQL> INSERT INTO T1 VALUES (2);
1 row inserted.
iSQL> CREATE OR REPLACE PROCEDURE PROC1
2 AS
3 BEGIN
4 INSERT INTO T1 VALUES(1);
5 SAVEPOINT EXPLICIT_SP;
6 INSERT INTO T1 VALUES(2);
7 INSERT INTO T1 VALUES(3);
8 END;
9 /
Create success.
iSQL> AUTOCOMMIT OFF;
Set autocommit off success.
iSQL> EXEC PROC1;
[ERR-11058 : The row already exists in a unique index.
0006 : INSERT INTO T1 VALUES(2);
^ ^
]
iSQL> ROLLBACK TO SAVEPOINT EXPLICIT_SP;
Rollback success.