Table of Contents
Transactions allow you to treat one or more operations on one or more containers as a single unit of work. The BDB XML transactional subsystem is simply a wrapper around Berkeley DB's transactional subsystem. This means that you BDB XML offers the same, full, ACID protection as does Berkeley DB. That is, BDB XML transactions offer you:
Atomicity.
Multiple container operations (most importantly, write operations) are treated as a single unit of work. In the event that you abort a transaction, all write operations performed during the transaction are discarded. In this event, your container is left in the state it was in before the transaction began, regardless of the number or type of write operations that you may have performed during the course of the transaction.
Note that BDB XML transactions can span one or more Container handles. Also, transactions can span both containers and Berkeley DB databases, provided they exist within the same environment.
Consistency.
Your BDB XML containers will never see a partially completed transactions, no matter what happens to your application. This is true even if your application crashes while there are in-progress transactions. If the application or system fails, then either all of the container changes appear when the application next runs, or none of them appear.
Isolation.
While a transaction is in progress, your containers will appear to the transaction as if there are no other operations are occurring outside of the transaction. That is, operations wrapped inside a transaction will always have a clean and consistent view of your databases. They never have to contend with partially updated records (unless you want them to).
Durability.
Once committed to your containers, your modifications will persist even in the event of an application or system failure. Note that durability is available only if your application performs a sync when it commits a transaction.
Transactionally processing is covered in great detail in the Berkeley DB Programmer's Reference Guide. All of the concepts and topics described there are relevant to transactionally protecting an BDB XML application.
The next few sections describe topics that are specific to transactionally protecting a BDB XML application.
In order to use transactions, you must turn on the transactional subsystem. You do this when you open your XmlManager by setting the appropriate flags for the manager. You must also turn on transactions for your container when you open it, again through the use of the appropriate flags.
Note that if you do not enable transactions when you first create your environment, then you cannot subsequently use transactions. Also, if your environment is not opened to support transactions, then your containers cannot be opened to support transactions. Finally, you cannot transactionally protect your container operations unless your environment and containers are configured to support transactions.
One final point: the default XmlManager constructor does not enable the transactional subsystem for its underlying environment, and there is no way to pass the appropriate flags to that environment using the default constructor. Instead, you must construct your own DbEnv object, passing it the flags required to enable transactions, and then hand that DbEnv object to the XmlManager constructor.
In order to enable transactions, you must enable the memory pool (the cache), the logging subsystem, the locking subsystem, and the transactional subsystem. For example:
#include "DbXml.hpp" ... using namespace DbXml; int main(void) { u_int32_t env_flags = DB_CREATE | // If the environment does not // exist, create it. DB_INIT_LOCK | // Initialize locking DB_INIT_LOG | // Initialize logging DB_INIT_MPOOL | // Initialize the cache DB_INIT_TXN; // Initialize transactions std::string envHome("/export1/testEnv"); DbEnv myEnv(0); XmlManager *myManager = NULL; try { myEnv.open(envHome.c_str(), env_flags, 0); myManager = new XmlManager(myEnv, 0); } catch(DbException &e) { std::cerr << "Error opening database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } catch(XmlException &e) { std::cerr << "Error opening database environment: " << envHome << " or opening XmlManager." << std::endl; std::cerr << e.what() << std::endl; } try { if (myManager != NULL) { delete myManager; } myEnv.close(0); } catch(DbException &e) { std::cerr << "Error closing database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } catch(XmlException &e) { std::cerr << "Error closing database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } }
Once you have enabled transactions for your environment and your manager, you must enable transactions for the containers that you open. You do this by providing the DBXML_TRANSACTIONAL flag when you create or open the container.
The following code updates the previous example to also open a container. The new code is shown in bold.
#include "DbXml.hpp" ... using namespace DbXml; int main(void) { u_int32_t env_flags = DB_CREATE | // If the environment does not // exist, create it. DB_INIT_LOCK | // Initialize locking DB_INIT_LOG | // Initialize logging DB_INIT_MPOOL | // Initialize the cache DB_INIT_TXN; // Initialize transactions std::string envHome("/export1/testEnv"); DbEnv myEnv(0); XmlManager *myManager = NULL; try { myEnv.open(envHome.c_str(), env_flags, 0); myManager = new XmlManager(myEnv); u_int32_t containerFlags = DB_CREATE | // If the container does not exist, // create it. DB_TRANSACTIONAL; // Enable transactions. std::string containerName = "myContainer.dbxml"; XmlContainer myContainer = myManager.openContainer(containerName, containerFlags); } catch(DbException &e) { std::cerr << "Error opening database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } catch(XmlException &e) { std::cerr << "Error opening database environment: " << envHome << " or opening XmlManager." << std::endl; std::cerr << e.what() << std::endl; } try { if (myManager != NULL) { delete myManager; } myEnv.close(0); } catch(DbException &e) { std::cerr << "Error closing database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } catch(XmlException &e) { std::cerr << "Error closing database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; } }