|
The lock subsystem provides interprocess and intraprocess concurrency control mechanisms. While the locking system is used extensively by the Berkeley DB access methods and transaction system, it may also be used as a stand-alone subsystem to provide concurrency control to any set of designated resources.
The lock subsystem is created, initialized, and opened by calls to DBENV->open with the DB_INIT_LOCK or DB_INIT_CDB flags specified.
The lock_detect function provides the programmatic interface to the Berkeley DB deadlock detector. Whenever two threads of control issue lock requests that are not carefully ordered or that require upgrading locks (obtaining write locks on objects that are already read-locked), the possibility for deadlock arises. A deadlock occurs when two or more threads of control are blocked, waiting for actions that another one of these blocked threads must take. For example, assume that threads one and two have each obtained read locks on object A. Now suppose that both threads wish to obtain write locks on object A. Neither thread can be granted its writelock (because of the other thread's readlock). Both threads block and will never unblock because the event for which they are waiting can never happen.
The deadlock detector examines all the locks held in the environment and identifies situations where no thread can make forward progress. It then selects one of the participants in the deadlock (according to the argument that was specified to DBENV->set_lk_detect) and forces it to return the value DB_LOCK_DEADLOCK, which indicates that a deadlock occurred. The thread receiving such an error should abort its current transaction, or simply release all its locks if it is not running in a transaction, and retry the operation.
The lock_vec interface is used to acquire and release locks.
Two additional interfaces, lock_get and lock_put, are provided. These interfaces are simpler front-ends to the lock_vec functionality, where lock_get acquires a lock, and lock_put releases a lock that was acquired using lock_get or lock_vec.
It is up to the application to specify lockers and objects appropriately. When used with the Berkeley DB access methods, these lockers and objects are handled completely internally, but an application using the lock manager directly must either use the same conventions as the access methods or define its own convention to which it adheres. If the application is using the access methods with locking at the same time that it is calling the lock manager directly, the application must follow a convention that is compatible with the access methods' use of the locking subsystem. See Access method locking conventions for more information.
The lock_id function returns a unique ID which may safely be used as the locker parameter to the lock_vec interface. The access methods use lock_id to generate unique lockers for the cursors associated with a database.
The lock_vec function performs any number of lock operations atomically. It also provides the ability to release all locks held by a particular locker and release all the locks on a particular object. Performing multiple lock operations atomically is useful in performing Btree traversals where you want to acquire a lock on a child page and once acquired, immediately release the lock on its parent (this is traditionally referred to as "lock-coupling"). Using lock_vec instead of separate calls to lock_put and lock_get reduces the synchronization overhead between multiple threads or processes.
The three interfaces, lock_get, lock_put and lock_vec, are fully compatible, and may be used interchangeably.
All locks explicitly requested by an application should be released via calls to lock_put or lock_vec.
The lock_stat function returns information about the status of the lock subsystem. It is the programmatic interface used by the db_stat utility.
The locking subsystem is closed by the call to DBENV->close.
Finally, the entire locking subsystem may be discarded using the DBENV->remove interface.