Table of Contents
The previous chapters in this Reference Guide have described applications that use the Berkeley DB access methods for fast data storage and retrieval. The applications described in the following chapters are similar in nature to the access method applications, but they are also threaded and/or recoverable in the face of application or system failure.
Application code that uses only the Berkeley DB access methods might appear as follows:
switch (ret = dbp->/put(dbp, NULL, &key, &data, 0)) { case 0: printf("db: %s: key stored.\n", (char *)key.data); break; default: dbp->/err(dbp, ret, "dbp->/put"); exit (1); }
The underlying Berkeley DB architecture that supports this is
As you can see from this diagram, the application makes calls into the access methods, and the access methods use the underlying shared memory buffer cache to hold recently used file pages in main memory.
When applications require recoverability, their calls to the Access Methods must be wrapped in calls to the transaction subsystem. The application must inform Berkeley DB where to begin and end transactions, and must be prepared for the possibility that an operation may fail at any particular time, causing the transaction to abort.
An example of transaction-protected code might appear as follows:
for (fail = 0;;) { /* Begin the transaction. */ if ((ret = dbenv->/txn_begin(dbenv, NULL, &tid, 0)) != 0) { dbenv->/err(dbenv, ret, "dbenv->/txn_begin"); exit (1); } /* Store the key. */ switch (ret = dbp->/put(dbp, tid, &key, &data, 0)) { case 0: /* Success: commit the change. */ printf("db: %s: key stored.\n", (char *)key.data); if ((ret = tid->/commit(tid, 0)) != 0) { dbenv->/err(dbenv, ret, "DB_TXN->/commit"); exit (1); } return (0); case DB_LOCK_DEADLOCK: default: /* Failure: retry the operation. */ if ((t_ret = tid->/abort(tid)) != 0) { dbenv->/err(dbenv, t_ret, "DB_TXN->/abort"); exit (1); } if (fail++ == MAXIMUM_RETRY) return (ret); continue; } }
In this example, the same operation is being done as before; however, it is wrapped in transaction calls. The transaction is started with DB_ENV->txn_begin() and finished with DB_TXN->commit(). If the operation fails due to a deadlock, the transaction is aborted using DB_TXN->abort(), after which the operation may be retried.
There are actually five major subsystems in Berkeley DB, as follows:
Here is a more complete picture of the Berkeley DB library:
In this model, the application makes calls to the access methods and to the Transaction subsystem. The access methods and Transaction subsystems in turn make calls into the Memory Pool, Locking and Logging subsystems on behalf of the application.
The underlying subsystems can be used independently by applications. For example, the Memory Pool subsystem can be used apart from the rest of Berkeley DB by applications simply wanting a shared memory buffer pool, or the Locking subsystem may be called directly by applications that are doing their own locking outside of Berkeley DB. However, this usage is not common, and most applications will either use only the access methods subsystem, or the access methods subsystem wrapped in calls to the Berkeley DB transaction interfaces.