HP 3000 Manuals

Using the Locking Facility [ TurboIMAGE/XL Database Management System Reference Manual ] MPE/iX 5.0 Documentation


TurboIMAGE/XL Database Management System Reference Manual

Using the Locking Facility 

The DBLOCK procedure applies a logical lock to a database or one or more
data sets or data entries.  The DBUNLOCK procedure releases these locks.

Locking can be viewed as a means of communication and control to be used
by mutually cooperating users.  The locking facility provides a method
for protecting the logical integrity of the data shared in a database.
With the DBLOCK procedure, application programs can isolate temporarily a
subsection of the database in order to perform a transaction against the
isolated data.  Locking is not required to protect the structure of the
database.  TurboIMAGE/XL has internal mechanisms that do this.

If a program opens the database in access mode 1 and locks a part of the
database, it can perform the transaction with the certain knowledge that
no other user will modify the data until the application program issues a
DBUNLOCK call.  This is because TurboIMAGE/XL does not allow changes in
access mode 1 unless a lock covers the data to be changed.  If one
process has the database opened in access mode 1, TurboIMAGE/XL requires
that all other processes that modify the database must also operate in
access mode 1.

The DBLOCK procedure operates in one of six modes.  Modes 1 and 2 can be
used for locking the database and modes 3 and 4 for locking a data set.
In modes 5 and 6, you describe the database entity or entities to be
locked using lock descriptors.

At the data entry level, locking is performed on the basis of data item
values.  For example, suppose a customer requests a change in an order
the customer has placed.  The data entries for the customer's account
that are in the SALES data set could be locked while the order is changed
and other database activity can continue concurrently.

Lock Descriptors 

A lock descriptor is used to specify a group of data entries that are to
be locked.  It consists of a data set name or number, a relational
operator, and an associated value.  For purposes of this discussion, the
notation dset :  ditem relop value is used.  For example, the lock
descriptor SALES:ACCOUNT = 89393899 requests locking of all the data
entries in the SALES data set with an ACCOUNT data item equal to
89393899.  Note that the result of specifying a single lock descriptor
can be that none, one, or many entries are locked depending on how many
entries qualify.

The following relational operators can be used:

   *   less than or equal (<=)

   *   greater than or equal (>=)

   *   equal (= _ or _ =), where _ indicates a space character

The value must be specified exactly as it is stored in the database.  A
lock will succeed even if no data item with the specified value exists in
the data set; no check is made to determine the existence of a particular
data item value.  This allows you to use techniques such as issuing a
lock to cover a data entry before you actually add it to a data set.

With the exception of compound items, any data item can be used in a lock
descriptor; that is, the lock item need not be a search item.

TurboIMAGE/XL does not require that you have read or write access to a
data set or data item in order to specify it in a lock request.

A process can specify any number of lock descriptors with a single DBLOCK
call.  For example, the following lock descriptors can be specified in
one DBLOCK call:

     CUSTOMER: ACCOUNT = 89393899
     SALES: ACCOUNT = 89393899
     SUP-MASTER: STATE = AZ
     INVENTORY: ONHANDQTY <= 100
     INVENTORY: ONHANDQTY >= 1500


NOTE Multiple calls to DBLOCK without intervening calls to DBUNLOCK are not allowed unless the program has Multiple RIN (MR) capability. Refer to "Issuing Multiple Calls to DBLOCK" later in this chapter.
How Locking Works The internal implementation of locking does not involve reading or writing to the database element to be locked. TurboIMAGE/XL keeps a table of everything that is locked by all processes that have the database opened. One table is associated with each database. This table serves as a global list of lock descriptors. In locking mode 5 or 6, a database lock is specified with the descriptor @:@ and a data set lock with dset:@. If you call DBLOCK in locking mode 1, 2, 3, or 4, TurboIMAGE/XL sets up the appropriate lock descriptor and puts it in the lock descriptor table. Figure 4-3 illustrates the contents of this list in a situation where one process has locked all SALES data entries with ACCOUNT equal to 12121212 or equal to 33334444. Another process has locked all INVENTORY data entries with STOCK# equal to 6650D22S. A third process has locked the whole SUP-MASTER data set. The figure illustrates what the table represents, not the actual internal format. When a lock request is made, TurboIMAGE/XL compares the newly specified lock descriptors with those that are currently in the list. If a conflict exists, TurboIMAGE/XL notifies the calling process that the entity cannot be locked or, if the process has requested unconditional locking, it is placed in a waiting state until the entity can be locked. If there are no conflicts, TurboIMAGE/XL adds the new lock descriptors to the list.
[]
Figure 4-3. Lock Descriptor List Conditional and Unconditional Locking You can request conditional or unconditional locking. If you request unconditional locking, TurboIMAGE/XL returns control to your calling program only after the specified entity has been locked. If you request conditional locking, TurboIMAGE/XL returns immediately. In this case, the condition code must be examined to determine whether or not the requested locks have been applied. If multiple lock descriptors are specified, the status area indicates the numbers that have been applied. The calling program should call DBUNLOCK if only a subset of the requested locks succeeded. Access Modes and Locking It is anticipated that access mode 1 will typically be used by applications implementing a locking scheme. In this mode, TurboIMAGE/XL enforces the following rules: * To modify (DBPUT, DBDELETE, or DBUPDATE) a data entry, you must first issue a successful lock covering the affected data entry. It can be a data entry, data set, or database lock. * To add to or delete from (DBPUT or DBDELETE) a manual master data set, you must first successfully lock the data set or database. To update (DBUPDATE) a master data set, data entry level locks are sufficient. If your application opens the database in access mode 2, it is recommended that you use locking to coordinate updates with other users. TurboIMAGE/XL does not prevent any process from reading data even though another process holds a lock on it. If you want to ensure that no modifications are in progress while you are reading from the database, you should place an appropriate lock on the data before starting. Therefore, you may want to use locking in access modes 2, 4, 5, and 6 to coordinate the reading and modifying sequences and ensure that they do not occur concurrently. Because access mode 3 and 7 users have exclusive control of the database and access mode 8 users allow concurrent reading only, locking need not be used in these modes. Automatic Masters When adding or deleting entries from a detail data set, you need not have locks covering the implicit additions or deletions that occur in any associated automatic masters. Locking Levels Locking can be viewed as operating on three levels: the whole database, whole data sets, or data entries. TurboIMAGE/XL allows mixed levels of locking. For example, one user could be locking data entries and another locking the data set. In this situation, a request to lock the data set cannot succeed until all the currently locked data entries have been released. Subsequent requests to lock data entries, those that are made while the data set lock is pending, are placed in a queue behind the data set lock. This principle is followed for database locks also. If data set or data entry locks are in effect at the time a database lock is requested, the database lock must wait until they are released and all subsequent locking requests must wait behind the pending database lock. In either case, if the request is for a conditional lock, an exceptional condition is generated. (Refer to the "Locking Mode Options" table in chapter 5.) Deciding on a Locking Strategy It is important, especially for on-line interactive applications, to establish a locking strategy at application design time. In general, locking is related to the transaction, the basic unit of work performed against a database. TurboIMAGE/XL transactions are either single or logical, and logical transactions can be static, multiple database, or dynamic. Refer to "User Logging and Logical Transactions" later in this chapter for more details and to chapter 5 for additional information. Typically a transaction consists of several calls to TurboIMAGE/XL intrinsics to locate and modify data. For example, a transaction to add a new order with three line items could require several reads to locate customer information and several DBPUT calls to add the order detail records. One characteristic of a transaction is that the data in the database is consistent both before and after the transaction, but not while it is in progress. For example, a user reading the detail data set being modified by the above order transaction may only see some of the line items and may get no indication that the transaction is incomplete. This type of problem is referred to as logical inconsistency of data and can be prevented by using the locking facilities. The general principle that should be applied for any transaction in a shared-access environment is: At the start of any transaction, establish locks that cover all data entries that you intend to modify (with DBPUT, DBDELETE, or DBUPDATE) and/or all data entries which must not be changed by other processes during the transaction. Choosing a Locking Level Because TurboIMAGE/XL needs more information to lock data entries than to lock the whole database, program complexity tends to increase as locks are employed at lower and lower levels. Locking the whole database or a single data set is the simplest operation, followed in increasing order of complexity by locking multiple data sets and locking data entries. At system design time, a compromise must be made between the benefits of low-level locking and the extra programming effort required. Data entry locking should give the best concurrency; however, there are situations in which the extra programming effort for data entry locking is not worthwhile. Concurrency is least optimum at the higher level of the lock. Concurrency and programming effort should be considered; some other considerations that could affect your choice of locking level are discussed below. Locking at the Same Level. All programs concurrently accessing a database should lock at the same level most of the time. For example, one process locking a data set will hold up all other processes that are attempting to lock entries in that set. Therefore, the attempt by the process locking at the data entry level to allow other processes to share the database is nullified by the process locking at the data set level and the effect is as if all processes were locking at the data set level. The rule of locking at the same level can be violated for infrequent operations such as exception handling or rare transactions. Length of Transactions. Generally, the longer the lock is to be held, the lower the level it should be. In other words, if you are performing lengthy transactions, you should probably lock at the entry level. For shorter transactions, you can use locks at either the database or data set level with satisfactory results. An extreme case of a long transaction is one in which user dialog takes place while a lock is held. For example, a program can read some data entries, interact with a terminal operator, and modify some or all of the entries. A lock to cover this transaction can last several minutes which is an unacceptable amount of time to stop all database or data set activity. In this situation, data entry level locking should be used. Because the length of different transactions varies, the longest transaction (that is also frequently used) should guide the choice of locking level. Locking During User Dialog. In the situation described above, where a lock is held during interactive dialog with a terminal operator, the terminal time-out feature of MPE/iX can be used to avoid having the locked entity inaccessible when the terminal operator is interrupted in the middle of the dialog. The time-out feature can be used to cause the terminal read to terminate automatically if no response is received within a certain time period. Refer to the discussion of "FCONTROL" in the MPE/iX Intrinsics Manual. Strong Locking and Dynamic Transactions. Dynamic transactions, which are described later in this chapter, are only allowed with a database access mode that enforces locking, because strong locking is required for this type of transaction. TurboIMAGE/XL requires that dynamic transactions be independent of all other types of transactions. This is guaranteed when the database access mode is 3 or 4, because the mode guarantees exclusive modify access. When a database is opened in access mode 1, the programmer must ensure that strong locks are in place. In other words, any call to DBUNLOCK must occur after the call to DBXEND, or the dynamic transaction is aborted.
NOTE A call to DBXUNDO must be processed if an error occurs or if the transaction needs to be rolled back for any other reason, because TurboIMAGE/XL will not go on to the next transaction in the event of a transaction abort unless an intervening call to DBXUNDO occurs. Furthermore, if DBXUNDO was used to roll back a transaction, the program logic should ensure that the subsequent call to DBXEND is not processed.
Choosing an Item for Locking An important convention to follow in designing a locking scheme is that all programs sharing the database concurrently use the same data item to lock data entries in a particular data set. At any one time, TurboIMAGE/XL allows no more than one data item per data set to be used for locking purposes. However, several values of the data item can be locked at the same time. For example, if one process has successfully locked SALES:ACCOUNT = 54321000, another process could lock SALES:ACCOUNT = 11111111. If a request is made to unconditionally lock SALES:STOCK# = 8888X22R, the requesting process will be made to wait until all entries locked by ACCOUNT number are unlocked. Furthermore, any new requests for locking other SALES:ACCOUNT values will wait until SALES:STOCK# = 8888X22R is successfully locked and unlocked again. With this in mind, it is apparent that it is more efficient if all processes locking data entries in the SALES data set use the same data item because it is much less likely that one process will have to wait until another process finishes using the data. Therefore, at system design time, decide which item will be used in each data set for lock specification purposes. It can be useful to add comments in the schema indicating which item is the locking item for each set. If a chain is used heavily for chained reads, its search item is a prime candidate for a lock item. Examples of Locking The examples in this section show the order in which TurboIMAGE/XL intrinsics can be called when locking is used. The ORDERS database is used in the examples. (Refer to the ORDERS database schema in chapter 3.) For descriptions of the procedures used in these examples, refer to chapter 5. Table 4-3 contains guidelines that can be helpful in designing locking schemes for shared-access environments which include users who might modify the database. Although data entry level locks are recommended in this table and illustrated in the following examples, data set or database locks could be more appropriate for similar tasks depending upon other application requirements. Table 4-3. Locking in Shared-Access Environments -------------------------------------------------------------------------------------------- | | | | Action | Recommended Locks | | | | -------------------------------------------------------------------------------------------- | | | | Chained DBGET calls | Lock all data entries in the chain. This usually | | | requires one lock descriptor. | | | | | Serial DBGET calls | Lock the data set. | | | | | Update a data entry (DBUPDATE) | Lock the data entry before calling DBGET to read | | | the data entry. Unlock after the update. | | | | | Directed reads (DBGET calls) | These are not recommended in a shared environment. | | | Lock the data set before determining which data | | | entry is needed. | | | | | Add a data entry to a detail data | Any lock which covers this data entry, but | | set (DBPUT) | preferably uses the data item that was decided on | | | as the "lock item" for the data set. | | | | | Add to or delete from a master | Lock the data set or database. This is mandatory | | data set (DBPUT and DBDELETE) | if the database is open in access mode 1. | | | | -------------------------------------------------------------------------------------------- Add a New Customer. 1. DBLOCK the CUSTOMER data set or the whole database. 2. DBPUT new data entry in CUSTOMER data set. 3. DBUNLOCK. Note that TurboIMAGE/XL requires a data set or database lock to cover the addition of an entry to a master data set. Update Inventory Information. 1. DBLOCK INVENTORY: STOCK# = 6650D22S. (Alternatively, the INVENTORY set or the whole database can be locked.) 2. DBFIND and DBGET the data entry that is locked in step 1. 3. Compute new UNIT-COST = UNIT-COST + .12 * UNIT-COST. 4. DBUPDATE the data entry that is locked. 5. DBUNLOCK. Insert a New Product with a New Supplier. 1. DBLOCK the PRODUCT master data set, the SUP-MASTER data set, and the data item STOCK# = 4444A33B in the INVENTORY detail data set. (This can be done in one DBLOCK mode 5 call.) 2. DBBEGIN. 3. DBPUT a new data entry in PRODUCT master data set. (For example: 4444A33B CALIPER). 4. DBPUT a new data entry in SUP-MASTER data set. 5. DBPUT a new data entry in INVENTORY data set for STOCK# = 4444A33B. 6. DBEND. 7. DBUNLOCK. The locking in the above example was done around the entire transaction to maintain data consistency during the multistep transaction. Interactively Modify a Customer Account Order. 1. DBLOCK SALES: ACCOUNT = 89393899. 2. DBFIND the CUSTOMER master data set entry with ACCOUNT = 89393899 in order to prepare to read the chain of SALES data entries with the same ACCOUNT value. 3. DBGET each entry in the chain and display it to the user until the correct order is located. 4. DBUPDATE the contents of the data entry according to the user's request. 5. DBUNLOCK. In the last example, all data entries for ACCOUNT 89393899 in the SALES data set are locked. Note that these locks are held while a dialog takes place with the terminal operator; therefore, the lock could be held for several minutes. For this type of transaction, it may be best to first perform a conditional lock to determine if the records are accessible. For example, when a mode 6 DBLOCK is called with lock descriptor SALES: ACCOUNT = 89393899 and the lock does not succeed, the following message is displayed: RECORDS BEING MODIFIED. WANT TO WAIT? If the response is NO, then proceed with other processing. If the answer is YES, call DBLOCK again with mode 5. Issuing Multiple Calls to DBLOCK In order to guarantee that two processes cannot deadlock, TurboIMAGE/XL does not allow two DBLOCK calls to be made without a DBUNLOCK between the DBLOCK calls. Two exceptions to this rule are stated here: * A redundant call can be made to lock the whole database with DBLOCK mode 1 or 2 provided the call relates to the same access path. The redundant call will have no effect. (This is allowed in order to maintain compatibility with earlier versions of IMAGE.) * More than one DBLOCK call can be made if the program from which multiple DBLOCK calls are issued has the MPE/iX Multiple RIN (MR) capability. The DBLOCK procedure is similar to the MPE/iX FLOCK procedure in that DBLOCK can put a process into a waiting state and thus can cause a deadlock to occur. For example, a deadlock can occur if process A is waiting for an MPE/iX file to be freed by process B, and process B is waiting for a database entity to be unlocked by process A. Therefore, issuing a DBLOCK in conjunction with a lock applied by an MPE/iX intrinsic, such as FLOCK, or by the COBOLLOCK procedure requires MR capability. The use of MR capability is not recommended unless absolutely necessary. Users whose programs have MR capability and issue multiple DBLOCK calls are responsible for deadlock prevention. This type of locking must be done very carefully. Recovery from a deadlock requires a restart of the operating system. No matter how many descriptors are listed in a single DBLOCK call, TurboIMAGE/XL guarantees that deadlocks will never occur provided that no executing program that accesses the database has MR capability. Programs that execute successfully using TurboIMAGE/XL locks in a single process environment will not execute in a process-handling environment without MR (Multiple RIN) capability. (Refer to appendix D for more information on the MR capability.) Releasing Locks The locks held by a process for a particular access path of a database are relinquished when the process calls DBUNLOCK; they are automatically relinquished when the process closes the database, terminates, aborts, or is aborted by an operator. Failure of a program to release locks will result in other programs waiting indefinitely for any conflicting locks. These programs, while in a waiting state, cannot be aborted by the operating system. An attempt to abort such a waiting process will result in the abort taking effect as soon as the process obtains the lock for which it was waiting.
NOTE Any program that executes a DBGET in mode 5 or 6 should lock the chain in the detail data set. This prevents the execution of any DBPUTs or DBDELETEs to the detail data set from modifying the current chain, thereby preventing a status 18 (broken chain) error.


MPE/iX 5.0 Documentation