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.