###

Berkeley DB Reference Guide:
  Programmer Notes

# Building multi-threaded applications

The Berkeley DB library is not itself multi-threaded. The library was deliberately architected to not use threads internally because of the portability problems that using threads within the library would introduce.

Berkeley DB supports multi-threaded applications with the caveat that it loads and calls functions that are commonly available in C language environments. Other than this usage, Berkeley DB has no static data and maintains no local context between calls to Berkeley DB functions.

Environment and database object handles returned from Berkeley DB library functions are free-threaded. No other object handles returned from the Berkeley DB library are free-threaded.

The following rules should be observed when using threads to access the Berkeley DB library:

1. The DB_THREAD flag must be specified to the DBENV->open and DB->open functions if the Berkeley DB handles returned by those interfaces will be used in the context of more than one thread. Setting the DB_THREAD flag inconsistently may result in database corruption.

   Threading is assumed in the Java API, so no special flags are required, and Berkeley DB functions will always behave as if the DB_THREAD flag was specified.

   Only a single thread may call the DBENV->close or DB->close functions for a returned environment or database handle.

   No other Berkeley DB handles are free-threaded, for example, cursors and transactions may not span threads as their returned handles are not free-threaded.

2. When using the non-cursor Berkeley DB calls to retrieve key/data items (e.g., DB->get), the memory referenced by the pointer stored into the Dbt is only valid until the next call to Berkeley DB using the DB handle returned by DB->open. This includes any use of the returned DB handle, including by another thread of control within the process.

   For this reason, if the DB_THREAD handle was specified to the DB->open function, either DB_DBT_MALLOC, DB_DBT_REALLOC or DB_DBT_USERMEM must be specified in the DBT when performing any non-cursor key or data retrieval.

3. The DB_CURRENT, DB_NEXT and DB_PREV flags to the log_get function may not be used by a free-threaded handle. If such calls are necessary, a thread should explicitly create a unique environment handle by separately calling DBENV->open without specifying DB_THREAD.

4. Each database operation (i.e., any call to a function underlying the handles returned by DB->open and DB->cursor) is normally performed on behalf of a unique locker. If, within a single thread of control, multiple calls on behalf of the same locker are desired, then transactions must be used. For example, consider the case where a cursor scan locates a record, and then based on that record, accesses some other item in the database. If these operations are done using the default lockers for the handle, they may conflict. If the application wishes to guarantee that the operations do not conflict, locks must be obtained on behalf of a transaction, instead of the default locker ID, and a transaction must be specified to the cursor creation and the subsequent Berkeley DB calls.

5. Transactions may not span threads. Each transaction must begin and end in the same thread, and each transaction may only be used by a single thread.

   Cursors may not span transactions or threads. Each cursor must be allocated and de-allocated within the same transaction and within the same thread.

6. User-level synchronization mutexes must have been implemented for the compiler/architecture combination. Attempting to specify the DB_THREAD flag will fail if fast mutexes are not available.

   If blocking mutexes are available, for example POSIX pthreads, they will be used. Otherwise, the Berkeley DB library will make a system call to pause for some amount of time when it is necessary to wait on a lock. This may not be optimal, especially in a thread-only environment where it will be more efficient to explicitly yield the processor to another thread.

   It is possible to specify a yield function on an per-application basis. See db_env_set_func_yield for more information.

   It is possible to specify the number of attempts that will be made to acquire the mutex before waiting. Se db_env_set_tas_spins for more information.

Copyright Sleepycat Software