It is often desirable to have concurrent access to a database where there is no need for full recoverability or transaction semantics. For this class of applications, Berkeley DB provides an interface supporting multiple-reader/single writer semantics on the database. This means that, at any instant in time, there may be either multiple readers accessing data or a single writer modifying data. The application is entirely unaware of which is happening, and Berkeley DB implements the necessary locking and blocking to ensure these semantics.
This chapter describes how to create concurrent access applications using Berkeley DB.
In order to create concurrent applications, you must first initialize an environment by calling db_appinit. You must specify the DB_INIT_CDB flag to that interface, and you may optionally also specify the DB_INIT_MPOOL flag. (If your application is doing concurrent access via a single multi-threaded process, DB_INIT_MPOOL will not be necessary, however, in the case of multiple processes sharing a database, it is.) As concurrent applications are not recoverable, you should not specify any of the other db_appinit subsystem configuration flags, e.g., you should not DB_INIT_LOCK, DB_INIT_LOG, DB_INIT_TXN, DB_RECOVER or DB_RECOVER_FATAL.
The DB_ENV structure returned by db_appinit must then be passed to all of the db_open calls made by your application.
The Berkeley DB access method calls used to support concurrent access are unchanged from the normal access method calls, with one exception, the DB->cursor interface. In the Berkeley DB Concurrent Access Methods product, each cursor must encapsulate the idea of being used for read-only access or for read-write access. There may only be one read-write cursor active at any one time. When your application creates a cursor, if that cursor will ever be used for writing, the DB_RMW flag must be specified when the cursor is created.
Because only a single thread of control may write the database at a time, care must be taken to ensure that applications do not inadvertently block themselves. Some common mistakes are:
Note that it is correct operation for two different threads of control (actual threads or processes) have multiple read-write cursors open, or for one thread to issue a DB->put call while another thread has a read-write cursor open, and it is only a problem if these things are done in a single thread of control.