Bug #9595
Records accessed from dynamic buffers remain LOCKed until the user context is destroyed
0%
Related issues
History
#1 Updated by Ovidiu Maxiniuc over 1 year ago
I am facing some issues related to (un-)locking of records from (dynamic) buffers. Consider the following 2 procedures:
p01:
DEFINE VARIABLE bh AS HANDLE.
CREATE BUFFER bh FOR TABLE "_tenant".
bh = BUFFER fwd._tenant:handle.
DO TANSACTION:
MESSAGE
"Find:"
bh:FIND-FIRST("WHERE _tenant-name EQ 'default'" /*, EXCLUSIVE-LOCK*/)
bh:rowid
bh::_tenantId
bh::_tenant-name
bh::_Tenant-Description.
bh::_tenant-Description = "New Default Tenant".
MESSAGE
"Altered:"
bh:rowid
bh::_tenantId
bh::_tenant-name
bh::_Tenant-Description
bh:buffer-release().
PAUSE MESSAGE "1".
END.
PAUSE MESSAGE "2".
DELETE OBJECT bh.
PAUSE MESSAGE "3".
p002:
FOR EACH _tenant:
MESSSAGE ROWID_tenant) "*" _tenantId "*" _tenant-name "*" _Tenant-Description.
END.
The idea is to start p01 which will create a transaction in order to change the tenant description. There are 3 pauses, where the lock could be released for 'default' tenant. So, while p01 is pausing in 1 the p02 should be run to see if the record is still locked.
- in 4GL, the default tenant is locked and not displayed until 2nd pause. It makes sense, since that's the moment when the transaction is completed, even if the buffer released the record before moment 1.
- in FWD, converted the code as is above,
p02will NOT show the tenant untilp01is completely closed. Once a record was locked (using dynamic API) it is not released neither on buffer release, buffer delete nor transaction end.
I have not tested with static code (yet - I was only interested in dynamic one), but I have reasons to think it behaves the same.
I looked at the moment when the record is released (in RB.setCurrentRecord(), around line 12330). Because there is an on-going transaction, the lock is not released from context, instead the following code is executed:
// Downgrade pinned lock type. This won't actually downgrade the lock, it
// just lets the lock context know that this buffer is done with its
// exclusive lock on this record.
setPinnedLockType(id, LockType.SHARE);Actually, this does nothing, the internal state of pinnedLocks.inTrans remains unchanged.
I would have expected to get the following code executed:
// try to release the lock
RecordIdentifier<String> ident = this.currentRecord.getRecordLockIdentifier();
persistenceContext.getRecordLockContext().lock(ident, LockType.NONE, 0L, this);But that happens only outside transactions.
Also, I could not find a place where these pinned locks are released at the end of transaction. At that moment, the pinnedLocks.inTrans is simply cleared. I think before clearing this map, it should be iterated and the records unlocked using a code similar to that above.
The above comments are not related to tenants at all, usage of _Tenant table is just for my convenience. The issue was discovered when implementing the REST API for tenant administration. When it attempts to access a record, it will automatically remain locked for the lifetime of the FWD server, since the context in which the requests are processed is not cleared as with normal clients when they disconnect.
#2 Updated by Ovidiu Maxiniuc over 1 year ago
- Blocks Feature #8976: Admin REST API for interacting with tenant authentication tables added
#3 Updated by Greg Shah over 1 year ago
- Project changed from Core Development to Database
#4 Updated by Greg Shah over 1 year ago
+Eric