An explicit transaction has its own "server cache" in memory on the server. This cache is only visible to that transaction. All updated records are written to the server cache. Pages of the cache which have been changed are flagged "dirty" and when the transaction is committed will be written to the tables on disk. If the power fails when some, but not all, of the dirty pages have been written to disk the database will be left in an inconsistent state.
To prevent this possibility set the Failsafe property of your TnxDatabase component to true. As the transaction proceeds clean "before images" of the cache pages which are about to be updated are written to a Transaction Journal File (TJF). When a transaction is committed all the dirty pages are written as "after images" to the TJF and the completed file is closed and flushed to disk. The dirty pages are then written to the database tables on disk and when complete the TJF is deleted. If the power is lost the TJF can be used later to automatically complete the transaction.
For a Rollback the dirty cache pages are discarded and the TJF is deleted.
There are 3 settings available with Failsafe transactions:
• | Mode 1 ("Dialog") – before and after images are stored. If a reboot finds these images then a dialog is displayed and the operator asked whether to commit or rollback the changes found. |
• | Mode 2 ("Always Rollback") – stores before images only. If a reboot finds these images an automatic rollback is performed. This can be thought of as a conservative, or cautious, mode of operation. |
• | Mode 3 ("Always Commit") – stores after images only. If a reboot finds these types of images an automatic commit is performed. |
Mode 2 and 3 require no user interaction. This makes them perfect if the NexusDB Server is running as a service.
The use of the journal file in this manner implements a two-phase commit transaction protocol. The two-phase commit protocol is an industry standard way of ensuring the highest level of data integrity. Many transaction theory references discuss this protocol in depth, for more information on the two-phase commit protocol it is recommended you consult those external references.
How is a commit performed?
Committing a failsafe transaction roughly means:
• | write journal header marked as incomplete |
• | write all before and/or after pages to the journal (depending on the journal engine used) |
• | flag the journal header as completed |
• | write the changes to the real table files |
• | delete the journal |
Using the rollback journal engine gives a consistent experience for the client: if the commit call returned with DBIERR_NONE all changes have been committed to disk, otherwise not.
Using e.g. the commit journal engine that the transaction will be committed if a journal file that already reached stage c) is found on start of the server. If the journal file is still marked as incomplete it is simply deleted. For the next release of NexusDB I've removed the dialog that was shown if an incomplete journal file was found as it is meaningless. As long as the journal is still marked as incomplete no action needs to be taken beyond deleting the journal to recover the database to a consistent state. The dialog maybe made some people believe there was an error that resulted in data corruption when in reality everything worked correctly.
There are 3 points to activate failsafe transactions: per Server, per Database or per explicit transaction. Turning it on at one level forces it on for all higher levels. There is currently no way to force it off from a higher level if it is on at a lower level.