Using ObjectScript
Lock Management
|
|
A process can apply (lock) and release (unlock) locks using the
LOCK command. A lock controls access to a data resource, such as a global variable. This access control is by convention; a lock and its corresponding variable may (and commonly do) have the same name, but are independent of each other. Changing a lock does not affect the variable with the same name; changing a variable does not affect the lock with the same name.
By itself a lock does not prevent another process from modifying the associated data because InterSystems IRIS Data Platform™ does not enforce unilateral locking. Locking works only by convention: it requires that mutually competing processes all implement locking on the same variables.
A lock can be a local (accessible only by the current process) or a global (accessible by all processes). Lock naming conventions are the same as local variable and global variable naming conventions.
A lock remains in effect until it is unlocked by the process that locked it, is unlocked by a system administrator, or is automatically unlocked when the process terminates.
This chapter describes the following topics:
-
Management Portal Lock Table, which displays all held locks system-wide, and all lock requests waiting for the release of a held lock. The lock table can also be used to release held locks.
-
-
Waiting lock requests. How InterSystems IRIS queues lock requests waiting for the release of a held lock.
-
InterSystems IRIS maintains a system-wide lock table that records all locks that are in effect and the processes that have locked them, and all waiting lock requests. The system manager can display the existing locks in the Lock Table or remove selected locks using the
Management Portal interface or the
^LOCKTAB utility. You can also use the
%SYS.LockQuery class to read lock table information. From the %SYS namespace you can use the
SYS.Lock class to manage the lock table.
A held lock
ModeCount can, of course, represent any combination of shared or exclusive, escalating or non-escalating locks with or without increments. An Exclusive lock or a Shared lock (escalating or non-escalating ) can be in a Delock state.
ModeCount indicates the lock (or lock request) that is blocking this lock request. This is not necessarily the same as
Reference, which specifies the currently held lock that is at the head of the lock queue on which this lock request is waiting.
Reference does not necessarily indicate the requested lock that is immediately blocking this lock request.
The
Routine column provides the current line number and routine that the owner process is executing.
The
window cannot be used to remove locks.
To remove (delete) locks currently held on the system, go to the
Management Portal, select
System Operation, select
, then select
. For the desired process (
Owner) click either Remove or Remove All Locks for Process.
Removing a lock releases all forms of that lock: all increment levels of the lock, all exclusive, exclusive escalating, and shared versions of the lock. Removing a lock immediately causes the next lock waiting in that lock queue to be applied.
Removing a lock requires WRITE permission. Lock removal is logged in the audit database (if enabled); it is not logged in messages.log.
You can also view and delete (remove) locks using the InterSystems IRIS
^LOCKTAB utility from the
%SYS namespace. You can execute
^LOCKTAB in either of the following forms:
-
DO ^LOCKTAB: allows you to view and delete locks. It provides letter code commands for deleting an individual lock, deleting all locks owned by a specified process, or deleting all locks on the system.
-
DO View^LOCKTAB: allows you to view locks. It does not provide options for deleting locks.
Note that these utility names are case-sensitive.
The following Terminal session example shows how
^LOCKTAB displays the current locks:
%SYS>DO ^LOCKTAB
Node Name: MYCOMPUTER
LOCK table entries at 07:22AM 01/13/2018
16767056 bytes usable, 16774512 bytes available.
Entry Process X# S# Flg W# Item Locked
1) 4900 1 ^["^^c:\intersystems\iris\mgr\"]%SYS("CSP","Daemon")
2) 4856 1 ^["^^c:\intersystems\iris\mgr\"]ISC.LMFMON("License Monitor")
3) 5016 1 ^["^^c:\intersystems\iris\mgr\"]ISC.Monitor.System
4) 5024 1 ^["^^c:\intersystems\iris\mgr\"]TASKMGR
5) 6796 1 ^["^^c:\intersystems\iris\mgr\user\"]a(1)
6) 6796 1e ^["^^c:\intersystems\iris\mgr\user\"]a(1,1)
7) 6796 2 1 ^["^^c:\intersystems\iris\mgr\user\"]b(1)Waiters: 3120(XC)
8) 3120 2 ^["^^c:\intersystems\iris\mgr\user\"]c(1)
9) 2024 1 1 ^["^^c:\intersystems\iris\mgr\user\"]d(1)
Command=>
In the
^LOCKTAB display, the X# column lists exclusive locks held, the S# column lists shared locks held. The X# or S# number indicates the lock increment count. An e suffix indicates that the lock is defined as
escalating. A D suffix indicates that the lock is in a
delock state; the lock has been unlocked, but is not available to another process until the end of the current transaction. The W# column lists number of waiting lock requests. As shown in the above display, process 6796 holds an incremented shared lock ^b(1). Process 3120 has one lock request waiting this lock. The lock request is for an exclusive (X) lock on a child (C) of ^b(1).
Enter a question mark (?) at the
Command=> prompt to display the help for this utility. This includes further description of how to read this display and letter code commands to delete locks (if available).
Note:
You cannot delete a lock that is in a lock pending state, as indicated by the Flg column value.
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.
-
-
-
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).
-
-
-
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).
-
Process A unlocks
^student(1). The waiting locks change back to WaitExclusiveParent
^student(1,2). (Same conditions as steps 2 and 3.)
-
-
The InterSystems IRIS 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. As this may differ from expectations, or from implementations of lock queuing on other databases, some clarification is provided here.
Consider the case where three locks on the same global array are requested by three different processes:
Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)
In this case, Process A gets a lock on
^x(1,1). Process B must wait for Process A to release
^x(1,1) before locking
^x(1). But what about Process C? The lock granted to Process A blocks Process B, but no held lock blocks the Process C lock request. It is the fact that Process B is waiting to explicitly lock
^x(1) and thus implicitly lock
^x(1,2) which is the node that Process C wants to lock that blocks Process C. In InterSystems IRIS, Process C must wait for Process B to lock and unlock.
The InterSystems IRIS lock queuing algorithm is fairest for Process B. Other database implementations that allowed Process C to jump the queue can speed Process C, but could (especially if there are many jobs such as Process C) result in an unacceptable delay for Process B.
Note:
This strict process queuing algorithm applies to all subscripted lock requests. However, a process releasing a non-subscripted lock (such as
LOCK -^abc) when there are both non-subscripted (
LOCK +^abc) and subscripted (
LOCK +^abc(1,1)) waiting lock requests is a special case. In this case, which lock request is serviced is unpredictable and may not follow strict process queuing.
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.
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):
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, you should either request the exclusive lock without the plus sign (thus unlocking 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:
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, you should always include the
timeout argument when using plus sign locks. For example,
LOCK +^a(1):10.
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
window, then select the Remove option for the deadlocked process.
Content Date/Time: 2019-02-22 00:52:40