Product Documentation

FairCom ISAM for C

Previous Topic

Next Topic

Begin

Mark beginning of transaction.

Short Name

TRANBEG()

Type

Low-Level data file function

Declaration

LONG Begin(COUNT trnmod)

Description

Begin() marks the beginning of a transaction. All files opened by this user, that have been created with a file mode of either ctPREIMG or ctTRNLOG, will have file updates held until they are committed with a matching call to Commit(). For a full description of transaction processing, see the chapter on Data Integrity.

trnmod values presently supported are summarized in the following table:

trmmod value

Operation

ctTRNLOG

Full transaction processing functionality, including auto-recovery. Mutually exclusive to ctPREIMG.

ctPREIMG

Transaction atomicity only, auto-recovery is not available. Mutually exclusive to ctTRNLOG.

ctENABLE

Automatically implements LockISAM(ctENABLE) when applicable. Mutually exclusive with ctREADREC.

ctREADREC

Automatically implements LockISAM(ctREADREC) when applicable. Mutually exclusive with ctENABLE.

ctLK_BLOCK

Automatically implements blocking locks when OR-ed with ctREADREC or ctENABLE.

ctLK_RECR

Enables recursive locking.

ctSAVENV

Saves current ISAM position after each successful ISAM file update operation (i.e., ReWriteRecord(), DeleteRecord(), etc. ).

ctAUTOSAVE

Automatically invokes savepoints after each successful ISAM or resource update. Disables ctSAVENV.

ctTWOFASE

Enables two-phase transaction support.

ctDEFERBEG

Enables a deferred transaction begin state. The TRANBEG log entry is delayed until an update is made within the transaction. This can benefit performance when no updates are made as the transaction flush can ultimately be skipped.

Either ctPREIMG or ctTRNLOG must be used to specify the transaction logging mode.

Note: Using ctPREIMG with a file created with ctTRNLOG results in a TTYP_ERR (99).

Either ctENABLE or ctREADREC may also be OR-ed in to automatically invoke LockISAM(). If either is used, ctLK_BLOCK can be OR-ed in to convert the locks to blocking locks. This sleeps the process until the lock is available instead of returning DLOK_ERR (42).

If ctSAVENV is used, or if the user profile in InitCTreeXtd() or InitISAMXtd() includes USERPRF_SAVENV, then the current ISAM position of the files updated during the transaction is saved. This allows a subsequent Abort() or RestoreSavePoint() to reset the current ISAM position of the files.

Automatic Savepoints

ctAUTOSAVE automatically follows each successful ISAM update or resource update with a special savepoint. The savepoint permits an update error to be rolled-back so that a compound transaction can continue its updates and subsequently Commit() the transaction. This automatic savepoint does NOT support the ctSAVENV profile setting. ctSAVENV is disabled if ctAUTOSAVE is on.

This approach is faster than explicit savepoints after each update since no network traffic is required between updates, and the auto savepoint is more efficient than an explicit savepoint.

If an error occurs in the middle of a set of updates within a single transaction, and if ctAUTOSAVE was in trnmod, the application simply calls RestoreSavePoint(-1) to roll-back the error, and continues update processing.

Explicit calls to SetSavePoint() should not be made when ctAUTOSAVE is effective. Error ASAV_ERR (532) will be returned by SetSavePoint() if called after updates have occurred. A typical usage pattern in pseudo-code would be:

Begin(ctTRNLOG | ctAUTOSAVE | ctENABLE)

loop: update operation

if error

RestoreSavePoint(-1)

if not done

goto loop

Commit(...)

Deferred Begin

It is not uncommon for a higher-level API to start transactions without knowledge of whether or not any updates will occur. To reduce the overhead of unnecessary log flushes, a deferred mode is available. ctDEFERBEG results in the actual TRANBEG entry in the log to be delayed until an attempt is made to update a transaction controlled file, and if a TRANEND() or TRANABT() is called without any updates, then the transaction begin and end log entries are not flushed to disk. ctDEFERBEG has no affect for ctPREIMG transactions.

Note: When using a transaction mode of deferred begin, Begin(ctTRNLOG | ctDEFERBEG) returns a value of 1 as the actual transaction number assignment is delayed until the log write of the first file update takes place.

Two-Phase Transactions

Two-Phase transaction support allows, for example, a transaction to span multiple servers. This is useful for updating information from a master database to remote databases in an all-or-nothing approach.

To start a transaction that supports a two-phase commit, you would include the ctTWOFASE attribute in the transaction mode passed to the Begin() function. Call the TRANRDY() function to execute the first commit phase, and finally Commit() to execute the second commit phase.

Note: You may need additional caution with regard to locking and unlocking of records as your transactions become more complex in a multi-server environment to avoid performance problems.

Example

(Note that this example could also use individual threads of operation for the different c-tree Server connections, avoiding the c-tree instance calls.)

COUNT rc1,rc2,filno1,filno2,rcc1,rcc2;

TEXT databuf1[128],databuf2[128];

/* Create the connections and c-tree instances */

...

if (!RegisterCtree("server_1")) {

SwitchCtree("server_1");

InitISAMXtd(10, 10, 64, 10, 0, "ADMIN", "ADMIN", "FAIRCOMS1");

filno1 = OPNRFIL(0, "mydata.dat", ctSHARED);

FirstRecord(filno1, databuf1);

memcpy (databuf1, "new data", 8);


/* Prepare transaction on c-tree server 1 */

Begin(ctTRNLOG | ctTWOFASE | ctENABLE);

ReWriteRecord(filno1, databuf2);

rc1 = TRANRDY();

}

if (!RegisterCtree("server_2")) {

SwitchCtree("server_2");

InitISAMXtd(10, 10, 64, 10, 0, "ADMIN", "ADMIN", "FAIRCOMS2");

filno2 = OPNRFIL(0, "mydata.dat", ctSHARED);

FirstRecord(filno2, databuf2);

memcpy (databuf2, "new data", 8);


/* Prepare transaction on c-tree server 2 */

Begin(ctTRNLOG | ctTWOFASE | ctENABLE);

ReWriteRecord(filno2, databuf2);

rc2 = TRANRDY();

}

/* Commit the transactions */

if (!rc1 && !rc2) {

SwitchCtree("server_1");

rcc1 = Commit(ctFREE);

SwitchCtree("server_2");

rcc2 = Commit(ctFREE);

if (!rcc1 && !rcc2) {

printf("Transaction successfully committed across both servers.\n");

} else {

printf("One or more units of the second commit phase of the transaction failed: rcc1=%d rcc2=%d\n", rcc1, rcc2);

}
} else {

printf("One or more of the transactions failed to be prepared: rc1=%d rc2=%d\n", rc1, rc2);


printf("Pending transactions will be aborted.\n");

SwitchCtree("server_1");

Abort();

SwitchCtree("server_2");

Abort();

}

/* Done */

SwitchCtree("server_1");

CloseISAM();

SwitchCtree("server_2");

CloseISAM();

Note: Two-Phase transactions can become extremely difficult to debug should there be communications problems between servers at any time during the second commit phase. This can result in out of sync data between the servers as one server may have committed while another server failed. It is always appropriate to check the return codes of the individual Commit() functions to ensure a complete successful transaction commit across multiple servers.

Return

Begin() returns a transaction number (low word for six-byte transaction numbers) if successful, or zero on error. With six-byte transaction number support, call ctGETHGH() for the high word of the transaction number.

It an error occurs Begin() returns 0 and uerr_cod will return the appropriate c-tree error code.

Value

Symbolic Constant

Explanation

70

TEXS_ERR

Transaction already pending - you cannot start one until the prior one is committed or aborted.

99

TTYP_ERR

Transaction type / trnmod conflict.

150

SHUT_ERR

Server is shutting down.

See FairCom DB Error Codes for a complete listing of valid FairCom DB error values.

Example

COUNT savepoint;


void domaster() {

Begin(ctENABLE|ctTRNLOG); /* start transaction with locks */

while(another()); { /* get next record to add */

savepoint = SetSavePoint(); /* get save point at

beginning of each master record */

if (add_master() < 0)

Abort(); /* Begin if can't add master rec */

dodetail(); /* process detail records */

}

if (Commit(ctFREE) != 0)

printf("\nError %d in transaction",uerr_cod);

return;

}


void dodetail() {

while(moredetail()); { /*get next detail record to add */

if (add_detail()<0) { /* add details, if possible */

RestoreSavePoint(savepoint) /* with error, return

to savept */

return;

}

}

}

See also

Abort, AbortXtd, Commit, ClearSavePoint, ctGETHGH, ctSETHGH, DeleteRecord, InitCTreeXtd, InitISAMXtd, LockISAM, RestoreSavePoint, ReWriteRecord, SetSavePoint, SetOperationState, TRANRDY

TOCIndex