Skip to main content

Details of Lock Requests and Deadlocks

This topic provides more detailed information on how lock requests are handled in InterSystems IRIS® data platform, as well as a detailed look at deadlock scenarios.

Waiting Lock Requests

When a process holds an exclusive lock, it causes a wait condition for any other process that attempts to acquire the same lock, or a lock on a higher level node or lower level node of the held lock. When locking subscripted globals (array nodes) it is important to make the distinction between what you lock, and what other processes can lock:

  • What you lock: you only have an explicit lock on the node you specify, not its higher or lower level nodes. For example, if you lock ^student(1,2) you only have an explicit lock on ^student(1,2). You cannot release this node by releasing a higher level node (such as ^student(1)) because you don’t have an explicit lock on that node. You can, of course, explicitly lock higher or lower nodes in any sequence.

  • What they can lock: the node that you lock bars other processes from locking that exact node or a higher or lower level node (a parent or child of that node). They cannot lock the parent ^student(1) because to do so would also implicitly lock the child ^student(1,2), which your process has already explicitly locked. They cannot lock the child ^student(1,2,3) because your process has locked the parent ^student(1,2). These other processes wait on the lock queue in the order specified. They are listed in the lock table as waiting on the highest level node specified ahead of them in the queue. This may be a locked node, or a node waiting to be locked.

For example:

  1. Process A locks ^student(1,2).

  2. Process B attempts to lock ^student(1), but is barred. This is because if Process B locked ^student(1), it would also (implicitly) lock ^student(1,2). But Process A holds a lock on ^student(1,2). The lock Table lists it as WaitExclusiveParent ^student(1,2).

  3. Process C attempts to lock ^student(1,2,3), but is barred. The lock Table lists it as WaitExclusiveParent ^student(1,2). Process A holds a lock on ^student(1,2) and thus an implicit lock on ^student(1,2,3). However, because Process C is lower in the queue than Process B, Process C must wait for Process B to lock and then release ^student(1).

  4. Process A locks ^student(1,2,3). The waiting locks remain unchanged.

  5. Process A locks ^student(1). The waiting locks change:

    • Process B is listed as WaitExclusiveExact ^student(1). Process B is waiting to lock the exact lock (^student(1)) that Process A holds.

    • Process C is listed as WaitExclusiveChild ^student(1). Process C is lower in the queue than Process B, so it is waiting for Process B to lock and release its requested lock. Then Process C will be able to lock the child of the Process B lock. Process B, in turn, is waiting for Process A to release ^student(1).

  6. Process A unlocks ^student(1). The waiting locks change back to WaitExclusiveParent ^student(1,2). (Same conditions as steps 2 and 3.)

  7. Process A unlocks ^student(1,2). The waiting locks change to WaitExclusiveParent ^student(1,2,3). Process B is waiting to lock ^student(1), the parent of the current Process A lock ^student(1,2,3). Process C is waiting for Process B to lock then unlock ^student(1), the parent of the ^student(1,2,3) lock requested by Process C.

  8. Process A unlocks ^student(1,2,3). Process B locks ^student(1). Process C is now barred by Process B. Process C is listed as WaitExclusiveChild ^student(1). Process C is waiting to lock ^student(1,2,3), the child of the current Process B lock.

Queuing of Array Node Lock Requests

The basic queuing algorithm for array locks is to queue lock requests for the same resource strictly in the order received, even when there is no direct resource contention. This is illustrated in the following example, in which three locks on the same global array are requested by three different processes in the sequence shown:

Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)

The status of these requests is as follows:

  • Process A holds a lock on ^x(1,1).

  • Process B cannot lock ^x(1) until Process A to releases its lock on ^x(1,1).

  • Process C is also blocked, but not by Process A’s lock; rather, it is the fact that Process B is waiting to explicitly lock ^x(1), and thus implicitly lock ^x(1,2), that blocks Process C.

This approach is designed to speed the next job in the sequence after the one holding the lock. Allowing Process C to jump Process B in the queue would speed Process C, but could unacceptably delay Process B, especially if there are many jobs like Process C.

The exception to the general rule that requests are processed in the order received is that a process holding a lock on a parent node is immediately granted any requested lock on a child of that node. For example, consider the following extension of the previous example:

Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)
Process A: LOCK ^x(1,2)

In this case, Process A is immediately granted the requested lock on ^x(1,2), ahead of both Process B and Process C, because it already holds a lock on ^x(1,1).

Note:

This process queuing algorithm applies to all subscripted lock requests. However, the release of a nonsubscripted lock, such as LOCK ^x, when there are both nonsubscripted (LOCK +^x) and subscripted (LOCK +^x(1,1)) requests waiting is a special case, in which the lock request granted is unpredictable and may not follow process queuing.

ECP Local and Remote Lock Requests

When releasing a lock, an ECP client may donate the lock to a local waiter in preference to waiters on other systems in order to improve performance. The number of times this is allowed to happen is limited in order to prevent unacceptable delays for remote lock waiters.

Avoiding Deadlock

Requesting a (+) exclusive lock when you hold an existing shared lock is potentially dangerous because it can lead to a situation known as "deadlock". This situation occurs when two processes each request an exclusive lock on a lock name already locked as a shared lock by the other process. As a result, each process hangs while waiting for the other process to release the existing shared lock.

The following example shows how this can occur (numbers indicate the sequence of operations):

Process A Process B

1. LOCK ^a(1)#"S"

Process A acquires shared lock.

 
 

2. LOCK ^a(1)#"S"

Process B acquires shared lock.

3. LOCK +^a(1)

Process A requests exclusive lock and waits for Process B to release its shared lock.

 
 

4. LOCK +^a(1)

Process B requests exclusive lock and waits for Process A to release its shared lock. Deadlock occurs.

This is the simplest form of deadlock. Deadlock can also occur when a process is requesting a lock on the parent node or child node of a held lock.

To prevent deadlocks, request the exclusive lock without the plus sign, which unlocks your shared lock. In the following example, both processes release their prior locks when requesting an exclusive lock to avoid deadlock (numbers indicate the sequence of operations). Note which process acquires the exclusive lock:

Process A Process B

1. LOCK ^a(1)#"S"

Process A acquires shared lock.

 
 

2. LOCK ^a(1)#"S"

Process B acquires shared lock.

3. LOCK ^a(1)

Process A releases shared lock, requests exclusive lock, and waits for Process B to release its shared lock.

 
 

4. LOCK ^a(1)

Process B releases shared lock and requests exclusive lock. Process A immediately acquires its requested shared lock. Process B waits for Process A to release its shared lock.

Another way to avoid deadlocks is to follow a strict protocol for the order in which you issue LOCK + and LOCK - commands. Deadlocks cannot occur as long as all processes follow the same order. A simple protocol is for all processes to apply and release locks in collating sequence order.

To minimize the impact of a deadlock situation, include the timeout argument when using plus sign locks. For example, the LOCK +^a(1):10 operation times out after 10 seconds.

If a deadlock occurs, you can resolve it by using the Management Portal or the ^LOCKTAB utility to remove one of the locks in question. From the Management Portal, open the Manage Locks window, and then select the Remove option for the deadlocked process.

See Also

FeedbackOpens in a new tab