E: Escalating lock
Allows you to apply a large number of concurrent locks without overflowing the lock table. By default, locks are non-escalating. When applying a lock, you can use locktype “E” to designate that lock as escalating. When releasing an escalating lock, you must specify locktype “E” in the unlock statement. You can designate both exclusive locks and shared (“S”) locks as escalating.
Commonly, you would use escalating locks when applying a large number of concurrent locks at the same subscript level. For example LOCK +^mylock(1,1)#"E",+^mylock(1,2)#"E",+^mylock(1,3)#"E"....
The same lock can be concurrently applied as a non-escalating lock and as an escalating lock. For example, ^mylock(1,1) and ^mylock(1,1)#"E". InterSystems IRIS counts locks issued with locktype “E” separately in the lock table. For information on how escalating and non-escalating locks are represented in the lock table, refer to the “Lock Management” chapter of Using ObjectScript.
When the number of “E” locks at a subscript level reaches a threshold number, the next “E” lock requested for that subscript level automatically attempts to lock the parent node (the next higher subscript level). If it cannot, no escalation occurs. If it successfully locks the parent node, it establishes one parent node lock with a lock count corresponding to the number of locks at the lower subscript level, plus 1. The locks at the lower subscript level are released. Subsequent “E” lock requests to the lower subscript level further increment the lock count of this parent node lock. You must unlock all “E” locks that you have applied to decrement the parent node lock count to 0 and de-escalate to the lower subscript level. The default lock threshold is 1000 locks; lock escalation occurs when the 1001st lock is requested.
Note that once locking is escalated, lock operations preserve only the number of locks applied, not what specific resources were locked. Therefore, failing to unlock the same resources that you locked can cause “E” lock counts to get out of sync.
In the following example, lock escalation occurs when the program applies the lock threshold + 1 “E” lock. This example shows that lock escalation both applies a lock on the next-higher subscript level and releases the locks on the lower subscript level:
Main
TSTART
SET thold=$SYSTEM.SQL.Util.GetOption("LockThreshold")
WRITE "lock escalation threshold is ",thold,!
SET almost=thold-5
FOR i=1:1:thold+5 { LOCK +dummy(1,i)#"E"
IF i>almost {
IF ^$LOCK("dummy(1,"_i_")","OWNER") '= "" {WRITE "lower level lock applied at ",i,"th lock ",! }
ELSEIF ^$LOCK("dummy(1)","OWNER") '= "" {WRITE "lock escalation",!
WRITE "higher level lock applied at ",i,"th lock ",!
QUIT }
ELSE {WRITE "No locks applied",! }
}
}
TCOMMIT
Note that only “E” locks are counted towards lock escalation. The following example applies both default (non-“E”) locks and “E” locks on the same variable. Lock escalation only occurs when the total number of “E” locks on the variable reaches the lock threshold:
Main
TSTART
SET thold=$SYSTEM.SQL.Util.GetOption("LockThreshold")
WRITE "lock escalation threshold is ",thold,!
SET noE=17
WRITE "setting ",noE," non-escalating locks",!
FOR i=1:1:thold+noE { IF i < noE {LOCK +a(6,i)}
ELSE {LOCK +a(6,i)#"E"}
IF ^$LOCK("a(6)","OWNER") '= "" {
WRITE "lock escalation on lock a(6,",i,")",!
QUIT }
}
TCOMMIT
Unlocking “E” locks is the reverse of the above. When locking is escalated, unlocks at the child level decrement the lock count of the parent node lock until it reaches zero (and is unlocked); these unlocks decrementing a count, they are not matched to specific locks. When the parent node lock count reaches 0, the parent node lock is removed and “E” locking de-escalates to the lower subscript level. Any subsequent locks at the lower subscript level create specific locks at that level.
The “E” locktype can be combined with any other locktype. For example, “SE”, “ED”, “EI”, “SED”, “SEI”. When combined with the “I” locktype it permits unlocks of “E” locks to occur immediately when invoked, rather than at the end of the current transaction. This “EI” locktype can minimize situations where locking is escalated.
Commonly, “E” locks are automatically applied for SQL INSERT, UPDATE, and DELETE operations within a transaction. However, there are specific limitations on SQL data definition structures that support “E” locking. Refer to the specific SQL commands for details.
I: Immediate unlock
Immediately releases a lock, rather than waiting until the end of a transaction:
-
Specifying “I” when unlocking a non-incremented (lock count 1) lock immediately releases the lock. By default, an unlock does not immediately release a non-incremented lock. Instead, when you unlock a non-incremented lock InterSystems IRIS maintains that lock in a delock state until the end of the transaction. Specifying “I” overrides this default behavior.
-
Specifying “I” when unlocking an incremented lock (lock count > 1) immediately releases the incremental lock, decrementing the lock count by 1. This is the same behavior as a default unlock of an incremented lock.
The “I” locktype is used when performing an unlock during a transaction. It has the same effect on InterSystems IRIS unlock behavior whether the lock was applied within the transaction or outside of the transaction. The “I” locktype performs no operation if the unlock occurs outside of a transaction. Outside of a transaction, an unlock always immediately releases a specified lock.
“I” can only be specified for an unlock operation; it cannot be specified for a lock operation. “I” can be specified for an unlock of a shared lock (#"SI") or an exclusive lock (#"I"). Locktypes “I” and “D” are mutually exclusive. “IE” can be used to immediately unlock an escalating lock.
This immediate unlock is shown in the following example:
TSTART
LOCK +^a(1) // apply lock ^a(1)
LOCK -^a(1) // remove (unlock) ^a(1)
// An unlock without a locktype defers the unlock
// of a non-incremented lock to the end of the transaction.
WRITE "Default unlock within a transaction.",!,"Go look at the Lock Table",!
HANG 10 // This HANG allows you to view the current Lock Table
LOCK +^a(1) // reapply lock ^a(1)
LOCK -^a(1)#"I" // remove (unlock) lock ^a(1) immediately
// this removes ^a(1) from the lock table immediately
// without waiting for the end of the transaction
WRITE "Immediate unlock within a transaction.",!,"Go look at the Lock Table",!
HANG 10 // This HANG allows you to view the current Lock Table
// while still in the transaction
TCOMMIT
D: Deferred unlock
Controls when an unlocked lock is released during a transaction. The unlock state is deferred to the state of the previous unlock of that lock. Therefore, specifying locktype “D” when unlocking a lock may result in either an immediate unlock or a lock placed in delock state until the end of the transaction, depending on the history of the lock during that transaction. The behavior of a lock that has been locked/unlocked more than once differs from the behavior of a lock that has only been locked once during the current transaction.
The “D” unlock is only meaningful for an unlock that releases a lock (lock count 1), not an unlock that decrements a lock (lock count > 1). An unlock that decrements a lock is always immediately released.
“D” can only be specified for an unlock operation. “D” can be specified for a shared lock (#"SD") or an exclusive lock (#"D"). “D” can be specified for a escalating (“E”) lock, but, of course, the unlock must also be specified as escalating (“ED”). Lock types “D” and “I” are mutually exclusive.
This use of “D” unlock within a transaction is shown in the following examples. The HANG commands give you time to check the lock’s ModeCount in the Lock Table.
If the lock was only applied once during the current transaction, a “D” unlock immediately releases the lock. This is the same as “I” behavior. This is shown in the following example:
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
HANG 10
TCOMMIT
If the lock was applied more than once during the current transaction, a “D” unlock reverts to the prior unlock state.
-
If the last unlock was a standard unlock, the “D” unlock reverts unlock behavior to that prior unlock’s behavior — to defer unlock until the end of the transaction. This is shown in the following examples:
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive->Delock
WRITE "1st unlock",! HANG 5
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1) // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "3rd unlock",! HANG 5
TCOMMIT
-
If the last unlock was an “I” unlock, the “D” unlock reverts unlock behavior to that prior unlock’s behavior — to immediately unlock the lock. This is shown in the following examples:
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: null (immediate unlock)
WRITE "1st unlock",! HANG 5
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
-
If the last unlock was a “D” unlock, the “D” unlock follows the behavior of the last prior non-“D” lock:
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "2nd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1) // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive->Delock
WRITE "3rd unlock",! HANG 5
TCOMMIT
TSTART
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK +^a(1) // Lock Table ModeCount: Exclusive
LOCK -^a(1)#"I" // Lock Table ModeCount: Exclusive/2
WRITE "1st unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: Exclusive
WRITE "2nd unlock",! HANG 5
LOCK -^a(1)#"D" // Lock Table ModeCount: null (immediate unlock)
WRITE "3rd unlock",! HANG 5
TCOMMIT