콘텐츠로 이동

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.