5.5 Using Transaction Logging



Transaction logging is a superset of basic logging. Like basic logging, you must define a database log file, turn logging on for the database's logical RMSfiles, and ensure the existence of the log file. This starts the basic logging.

To activate transaction logging, extra function calls must be added to your C programs. These functions record the start and ending points of transactions. Any changes made by your process are considered part of the current transaction.

Each transaction is assigned a sequence number by the begin transaction function, dlbegin(C-3). The numbers start at 1 and go up with each begin transaction call. Each process has its own sequence of transaction ID's starting at 1. The combination of process ID and transaction ID is always unique. The transaction ID returned by dlbegin must be used in later transaction function calls. An example should help illustrate how to handle transaction IDs.

You have a user_edit routine for entering invoices. The code that handles the U_ADD of the header should look something like the following:

static DLID trid;

...

if (edit\(rutype == U\(ruADD) {

/* record beginning of transaction */

trid = dlbegin ("Add a new invoice");

... other code ...

}

...

The comment enclosed in quotes is optional and can be passed as NULL. It is important to place the call to dlbegin before any of the file changes for the transaction. You must also remember that the transaction ID value must retain its value from one user_edit call to the next. This determines how you declare trid.

When the last part of the invoice is stored (the trailer), the transaction is marked in the log file as completed with the end transaction function, dlend(C-3). Your user_edit routine should do something like the following:

static DLID trid; /* same value as above */

...

if (edit\(rutype == U\(ruSTORED

&& strcmp (sformname(), "trailer") == 0) {

... finish all changes ...

/* record end of transaction */

dlend (trid);

}

...

When a transaction is canceled by the user, it is the program's responsibility to undo any file changes that have been made, and then record that the transaction has been canceled with the canceled transaction function, dlcancel(C-3). For example, your user_edit routine should do something like the following:

static DLID trid; /* same value as above */

...

if (edit\(rutype == U\(ruCANCEL) {

... undo all file changes ...

/* record transaction cancellation */

dlcancel (trid);

}

...

For the purpose of transaction logging, canceling a transaction and ending a transaction are equivalent. They both declare that the database is in a consistent state. Canceling a transaction is recorded in the log file for documentation purposes only.

No special action is taken by the database restore command when a transaction is canceled. When a transaction is canceled, all the file operations performed by the program to restore the original file contents are logged just like any other file operation. By the time of the dlcancel function call, all database RMSfiles are once again consistent, so the database restore program can perform all the logical RMSfile changes involved in a cancellation.

Be very careful that a transaction you begin is either ended or canceled. If a transaction is not marked as completed, all of the records it changes are considered invalid and all future transactions modifying those records are invalidated. This can also extend backwards. One rule to follow in transaction logging is:

Any transaction begun MUST be ended

Should you forget this rule, the system silently ignores the problem until you do your restore. Obviously, at this point it is too late to correct the problem. (There is one feature that allows for restoration of incomplete transactions: see the section on Restoring from a Log File).