Electronics
Btrieve
Motorcycling
Software

New Lock Mechanism for NetWare Btrieve v6.10b

Btrieve is Novell's complete key-indexed record management system designed for high-performance data handling and improved programming productivity. Btrieve allows your application to retrieve, insert, update, or delete records either by key value or by sequential or random access methods.

NetWare Btrieve is the server-based implementation of Novell's tried-and-tested record manager. It is implemented as an NLM for NetWare 3.x and 4.x. This article discusses a new design feature of NetWare Btrieve v6.10b, specifically: concurrency inside concurrent transactions and lock sharing with multiple cursors.

Novell has added two significant enhancements to NetWare Btrieve (NLM) v6.10b:

In the earlier releases of NetWare Btrieve, record locking inside a concurrent transaction was converted to page-level locking. In the new release a true record-level lock is used. Also, with previous releases, multiple cursors in the same file within the same application could block one another.

In NetWare Btrieve v6.10b, the same record can be locked by different cursors on behalf of the same client within a single application. In this article, multiple cursors in an application refers to cursors belonging to a single client within that application. (A "single-client" application is one that uses the BTRV function call and all Btrieve requests are only executed on behalf of that client. A "multiple- client" application is an application that uses the BTRVID function call and Btrieve calls are executed on behalf of the individual client whose ID is specified in the BTRVID function call.)

For simplicity, this article refers to new and old implementations to distinguish between different revisions. The "old implementation" refers to NetWare Btrieve v6.0, v6.0a-d, v6.10 and v6.10a; and the "new implementation" refers to NetWare Btrieve v6.10b and above.

Characteristics Common to All Versions

In all versions of NetWare Btrieve, any Insert, Update, or Delete operation within a concurrent transaction locks the data pages and any index pages modified for the duration of that concurrent transaction. So, if a record is updated within a concurrent transaction, the second user is unable to update or delete other records that either reside on that data page or use the same index page.

In addition, "simple reads," or reads operations without any lock bias, within a concurrent transaction will not lock the corresponding data and index pages.

Finally, record locks are owned (controlled) by the cursor, or positioning within a file. If a file is opened multiple times by a single client within an application using different position blocks, each position block contains independent positioning information within that file. Individual position blocks are referred to as cursors. If a NetWare Btrieve client has multiple cursors for a particular file, specific record locks obtained by one cursor cannot be released by another cursor.

New Characteristics: Record Locking inside Concurrent Transactions

The first difference between the old and new implementations is record locking within concurrent transactions. In the old implementation, the locking inside a transaction took place at the page level. The new implementation provides more concurrency by allowing true record-level locking. An explicit record lock (set by adding a bias to the Get and Step operations or Begin Transaction) does not lock the corresponding data page; it only locks that particular record. To demonstrate this, examine the examples at left. In each of the examples, Record 1 and Record 2 reside on the same data page.

In Figure 1, User B receives status 84 (Record In Use) on the Read operation using old revisions because User A's Read+Lock has locked the data page. In the new implementation, since the page is not locked by User A, User B successfully reads Record 2; both users are able to read and lock their respective records. Later, after User updates record 1, the page is implicitly locked with either implementation. User B must wait until User A aborts or ends that transaction before continuing with the update.

FIGURE 1: Explicit record lock within concurrent transaction 

 USER A                       | USER B
==============================|=============================
Begin Concurrent Transaction  |
------------------------------|-----------------------------
                              | Begin Concurrent Transaction
------------------------------|-----------------------------
Read+Lock Record 1            |
(page locked with old         |
implementation,               |
not locked w/ new)            |
------------------------------|-----------------------------
                              | Read+Lock Record 2
                              | (status with old imple-
                              | mentation status 0 w/new)
------------------------------|-----------------------------
Update Record 1               |
(page locked implicitly       |
w/ either implementation)     |
------------------------------|-----------------------------
                              | Update Record 2
                              | (USER B w/ either
                              | implementation)
==============================|=============================

END of FIGURE 1

Successful locking of a record (inside or outside of a transaction) guarantees that no other client (not to be confused with "no other cursor") may update or delete that record. In other words, when a user performs an update or delete operation on a record which he has previously locked, he will eventually succeed unless a deadlock situation is detected. A deadlock occurs if two clients are waiting for each other to release a resource which is locked by the other. If a user obtains a lock on a record and the corresponding data page or index page is locked implicitly by another client in a concurrent transaction, waiting for the data page to be released will produce a deadlock situation. Then, Btrieve will return status 78 (Deadlock Detected).

In the example in Figure 1, User B waits until User A aborts or ends the transaction. However, in the example in Figure 2, Btrieve detects a deadlock; User B is waiting for User A to release Record 1 while User A is waiting for the data page to be released in order to execute the update.

FIGURE 2: Record locking in deadlock situation 

 USER A                 | USER B                   | STATUS
========================|==========================|========
Begin Concurrent Trans. |                          |   0
------------------------|--------------------------|--------
Read+Lock Record 1      |                          |   0
------------------------|--------------------------|--------
                        | Begin Concurrent Trans.  |   0
------------------------|--------------------------|--------
                        | Read+Lock Record 2       |   0
------------------------|--------------------------|--------
                        | Update Record 2          |   0
------------------------|--------------------------|--------
                        | Read+Wait Lock Record 1  | USER B
                        |                          | waits
------------------------|--------------------------|--------
Update Record 1         |                          |  78
========================|==========================|========

END of FIGURE 2

Lock Sharing with Multiple Cursors

In the new implementation, if a client of an application opens the same file multiple times, the locks issued by different cursors within the same application do not block each other. In the previous implementation, cursors were treated as completely independent clients. Thus, if a record was locked by one cursor, the second cursor of the same client would not be able to obtain a lock on the same record. As mentioned previously, cursors in the new implementation do not block each other from locking the same record, but they are still independent in the sense that they cannot explicitly unlock (using the Unlock operation) the records that were locked by the other cursors. In Figure 3, with the new implementation, Cursor 1 and Cursor 2 can lock the same record, but the update by Cursor 1 fails with status 80 (Conflict Error).

FIGURE 3: Lock-sharing with multiple cursors (Case 1)

USER A/             | USER A/             | STATUS  | STATUS
CURSOR 1            | CURSOR 2            | (New)   | (Old)
====================|=====================|=========|========
Read+Lock Record 1  |                     |    0    |   0
--------------------|---------------------|---------|--------
                    | Read+Lock Record 1  |    0    |  84
--------------------|---------------------|---------|--------
                    | Update Record 1     |    0    |  N/A
--------------------|---------------------|---------|--------
Update Record 1     |                     |   80    |   0
====================|=====================|=========|========

END of FIGURE 3

This status is returned because Cursor 2 has already updated the record and Cursor 1 must re-read the record before updating it. In the old implementation, the application will never reach this point and will receive status 84 on the read by the second cursor.

Thus, in the new implementation, after Cursor 1 has read a record with a lock, Cursor 2 can update or delete the record regardless of whether Cursor 2 has locked the record (see Figure 4). Cursor 1 will not receive an status 80 until it tries to delete or update that record. In the old implementation, Cursor 2 would receive a status 84 on a read if a lock bias is used or a status 84 on an Update operation if regular read without any lock bias is used.

FIGURE 4: Lock sharing with multiple cursors (Case 2) 

USER A/             | USER A/             | STATUS  | STATUS
CURSOR 1            | CURSOR 2            | (New)   | (Old)
====================|=====================|=========|========
Read+Lock Record 1  |                     |    0    |   0
--------------------|---------------------|---------|--------
                    | Read Record 1       |    0    |   0
--------------------|---------------------|---------|--------
                    | Update Record 1     |    0    |  84
--------------------|---------------------|---------|--------
Update Record 1     |                     |   80    |   0
====================|=====================|=========|========

END of FIGURE 4

With multiple cursors inside a concurrent transaction, locks obtained on a cursor before the application starts a concurrent transaction are automatically released when the cursor becomes an active participant of that transaction. A cursor becomes an active participant of a concurrent transaction if a lock is requested or if an insert, delete, or update operation is executed with that cursor. This situation is shown in Figure 5.

FIGURE 5: Multiple cursors within a concurrent transaction 

USER A/          |USER A/           |USER B           | STATUS
CURSOR 1         | CURSOR 2         |                 |
=================|==================|=================|=======
Read+Lock Rec.1  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 | Read+Lock Rec.1  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
Begin Concurrent |                  |                 |   0
Transaction.     |                  |                 |
-----------------|------------------|-----------------|-------
Read+Lock Rec.1  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
End Transaction  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
                 | Update Record 1  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |   0
=================|==================|=================|=======

END of FIGURE 5

Notice that all locks in Figure 5 are single, no-wait locks. The transaction does not have any affect on the inactive cursors. In other words, locks obtained before the transaction are still maintained after ending or aborting the transaction for inactive cursors.

This article has discussed two major issues with the new Btrieve locking mechanism. First, more concurrency is achieved by allowing record-level locking inside concurrent transactions. Second, the ability to share locks between multiple cursors held by one client on the same file in an application has been added.

NetWare Btrieve v6.10b is now available on NetWire at no charge to U.S. and international customers. The following files are located in Library 7 and have been compressed using PKZIP:

At 9600 baud, downloading the files takes about 30 minutes. If you wish to receive the product on diskette, call 1-800-UPDATE1 (domestic customers) or 317-364-7276 (international customers) and order the product for US$49.95 plus shipping and handling. You may also place orders by fax by calling 317-364-0787.

The NetWare Btrieve v6.1x Developer's Kit Supplement is available to registered members of the Novell Professional Developers' Program.

Copyright © Madis Kaal 2000-