public abstract class RecordLockContext
extends java.lang.Object
LockManager
handles the actual synchronization and acquisition
of record locks across all sessions for a given database, an instance of
RecordLockContext
is responsible for ensuring that all record
buffers which access a given record lock within a session cooperate
properly in their interactions with the lock manager.
When a record lock is required, it generally is associated with one or more record buffers in a session. There are several housekeeping processes in the persistence framework which may temporarily require a lock, but generally, record locks are associated with record buffers as the result of some converted Progress language statement option which (possibly implicitly) determines a record lock (i.e., NO-LOCK, SHARE-LOCK, EXCLUSIVE-LOCK on FIND, GET, FOR, OPEN QUERY, CREATE, etc.).
In P2J, this association is made by RecordBuffer
at the time it
creates a new record, or when a record found by a database query is stored
in the buffer via the setRecord method
.
A record lock is associated with a single record; there can be only one type of lock granted for a particular combination of database, table, and primary key identifier at a time across all sessions. However, multiple record buffers which contain the same record at the same time within a session all share access to the lock, such that each of them are granted the set of rights (or lack thereof) associated with the lock. Since each session is essentially single threaded, this is safe.
Record locking across buffers within a session is asymmetric: any buffer
can acquire and upgrade the communal lock, but all buffers must agree
before the communal lock can be downgraded or released. More specifically,
each buffer maintains its own state about its particular requirement for
the state of the lock (its "pinned" lock type -- the lock type which will
potentially "pin" the state of the communal lock at a certain, minimum
level until released by that buffer). If a buffer's pinned lock type is
LockType.NONE
, then that buffer effectively does not pin the
communal lock at all, and the lock may be released if no other buffers are
pinning it to a higher level. However, if a buffer's pinned lock type is
LockType.EXCLUSIVE
or LockType.SHARE
, the
communal lock may not be downgraded or released, respectively, until that
buffer changes its pinned type to a lower level.
In addition to this requirement for buffers to cooperate for lock downgrade and release, a SHARE lock may not be released, nor an EXCLUSIVE lock downgraded, while an application level transaction is active. The presence of a transaction trumps the pinning rules noted above. Once the transaction ends, via commit or rollback, those rules apply again.
This class is abstract, and two different subclasses, both defined here,
are used to support permanent database tables and temporary tables. The
factory method get(Persistence, BufferManager)
is used to acquire an
instance of the appropriate type. It should only be invoked once per database,
per session and is only intended for use by the Persistence
class.
Modifier and Type | Class and Description |
---|---|
private static class |
RecordLockContext.Perm
Concrete implementation of
RecordLockContext which enables
intra-session record lock sharing across record buffers for permanent
database tables. |
Modifier | Constructor and Description |
---|---|
private |
RecordLockContext()
Default constructor accessible only from within this class.
|
Modifier and Type | Method and Description |
---|---|
void |
forceRelease(RecordIdentifier ident,
RecordBuffer buffer)
Force the unconditional release of a lock.
|
static RecordLockContext |
get(Persistence persistence,
BufferManager bufferManager)
Factory method used to retrieve an instance of a
RecordLockContext implementation which is appropriate for
the database whose records are being managed. |
LockType |
lock(RecordIdentifier ident,
LockType requestedType)
Request that the communal lock on a record be acquired or otherwise
modified to match the requested type.
|
LockType |
lock(RecordIdentifier ident,
LockType requestedType,
long timeout,
RecordBuffer buffer)
Request that the communal lock on a record be acquired or otherwise
modified to match the requested type.
|
void |
registerBuffer(RecordIdentifier ident,
RecordBuffer buffer)
Register a record buffer to a particular record lock, which must
have been created previously.
|
java.util.Set<java.io.Serializable> |
relinquishBufferLocks(RecordBuffer buffer)
Attempt to release all locks associated with the given buffer.
|
java.util.Set<java.io.Serializable> |
transactionEnded()
Process any pending lock changes which have been deferred during the most recent
application level transaction.
|
private RecordLockContext()
public static RecordLockContext get(Persistence persistence, BufferManager bufferManager)
RecordLockContext
implementation which is appropriate for
the database whose records are being managed. Should only be called by
the Persistence
class.
The implementation returned for use with temporary tables essentially is a do-nothing implementation, since record locking is a no-op for temp tables.
The implementation returned for permanent tables adheres to the rules noted in the class description above.
This dual architecture is used so that other classes which use the services of this class do not have to differentiate their behavior for temporary vs. permanent tables. This permits client classes to remain unaware of the implementation differences for permanent and temporary tables.
persistence
- Persistence service object which will be used for access to
the global lock manager.bufferManager
- Buffer manager which tracks buffer scopes.public void registerBuffer(RecordIdentifier ident, RecordBuffer buffer)
Explicit deregistration of this association is unnecessary. It occurs implicitly when the lock is released and/or the buffer goes out of scope.
This implementation does nothing. It should be overridden for a meaningful implementation.
ident
- Unique identifier for a particular database record.buffer
- Record buffer to be associated with the specified record
lock.public java.util.Set<java.io.Serializable> relinquishBufferLocks(RecordBuffer buffer)
This implementation does nothing. It should be overridden for a meaningful implementation.
buffer
- Record buffer whose locks are being relinquished.null
if no locks were released. Does not
include locks which were downgraded to SHARE locks. This implementation always
returns null
.public void forceRelease(RecordIdentifier ident, RecordBuffer buffer)
ident
- Record identifier.buffer
- Optional buffer whose pinned state should be updated in accordance with the
lock release.public java.util.Set<java.io.Serializable> transactionEnded()
This implementation does nothing. It should be overridden for a meaningful implementation.
null
if no locks were released. Does not
include locks which were downgraded to SHARE locks. This implementation always
returns null
.public LockType lock(RecordIdentifier ident, LockType requestedType, long timeout, RecordBuffer buffer) throws LockUnavailableException, LockTimeoutException
This implementation does nothing. It should be overridden for a meaningful implementation.
ident
- Unique identifier for a particular database record.requestedType
- The lock type being requested.timeout
- Positive number of milliseconds to wait to acquire lock before
raising an exception; specify 0 to wait indefinitely. Ignored if
a no-wait lock variant is requested.buffer
- Record buffer on whose behalf the request is being made.
May be null
in cases where the association
will be made later or if the lock is being managed for
framework housekeeping purposes.LockTimeoutException
- never.LockUnavailableException
- never.public LockType lock(RecordIdentifier ident, LockType requestedType) throws LockUnavailableException
The communal lock may or may not be modified immediately, according to the rules described in this class' description. Generally, a request to upgrade or acquire the lock for the first time is honored immediately. However, a request to downgrade or release the lock may be deferred.
ident
- Unique identifier for a particular database record.requestedType
- The lock type being requested.LockUnavailableException
- if a no-wait lock variant is requested, and another session
currently holds the lock. This will never be thrown in
cases where a downgrade or release is being requested.