Bug #5743
finally block: finalizable processing
0%
Related issues
History
#2 Updated by Constantin Asofiei over 2 years ago
- Start date deleted (
10/19/2021)
- first program:
repeat transaction: find first book exclusive-lock. book.book-id = 12345678. leave. finally: message "transaction" transaction. // this shows 'no' pause. // start the second program end. end.
- second program:
find first book exclusive-lock where book.book-id = 12345678. // this blocks for the lock to be released message book.book-id.
The above test shows also the 'index leak dirty share' which requires the dirty database in FWD (just make sure to change the '12345678' to something else each time you run the program).
In #5700, we've changed certain finalizables (like parameter processing) to execute 'on top-level block return'. But there is a change in RecordBuffer.openScope:7757
which is incorrect:
// Register this buffer as a Finalizable with the TM, so that its // finished method is called when this buffer scope is about to close. ProcedureManager.executeOnReturn(this::finished, this.weight());
as it forces to execute on return, regardless of the buffer's scope block.
But what's interesting is that a FINALLY does have a transaction if it e.g. sets EXCLUSIVE-LOCK:
repeat: leave. finally: find first book exclusive-lock. message "transaction" transaction. end. end.
#3 Updated by Constantin Asofiei over 2 years ago
I've tried changing that code to this:
if (isTopLevelBlock()) { ProcedureManager.executeOnReturn(this::finished, this.weight()); } else { txHelper.registerFinalizable(this, false); }
but it is not enough. I think some other
registerFinalizable
calls need to be moved to 'executeOnReturn'.
Or do more investigations and find which (if any) of the FWD finalizables need to be processed before the FINALLY block.
#4 Updated by Ovidiu Maxiniuc over 2 years ago
Actually, I think it depends on the location of the 'finalizable' is configured. If it is configured for a do block, it must not executeOnReturn
. However, if the scope of a similar 'finalizable' is opened at procedure level, the executeOnReturn
must be used.
Two notes:
1. Today, I noticed something else. There are some resources for whom the finalization is constructed when the code is generated. See register_finish
. My searches through code failed to detect these registerFinalizable
initially because the method name is split in AST template definition.
2. I think we will need a new parameter global
for executeOnReturn
for global resources to be finalized when the main top-level procedure returns. Currently, the global resources are finalized with the main scope of that procedure. But if it has a finally:
block where these global resources are used, they might be already finalized. When this parameter is true
, the method should search the first procedure which was stacked and add the global resource at that level instead of using peek
and storing the clean-up code at current procedure level.
Please let me know if you think otherwise.
#5 Updated by Ovidiu Maxiniuc over 2 years ago
I tried to see the problem from another POV. Taking into account these new issues, I think the proper way is to move the executeOnReturn()
to BlockManager
instead of ProcedureManager
.
wa.tm
stack is changed. These are all the cases where a finally:
block can be defined. I think moving the data structure from the ProcedureManager
to TransactionManager.TransactionHelper
or doing a parallel management with wa.tm.pushScope()
/ wa.tm.popScope()
will do the trick. The only problem remains to see:
- which resources must be
finalized
(are reinitialized in a loop block, for example) so they must be registered with theTransactionManager
. They do not survive from one iteration to another and their scope does not include the associatedfinally:
block, if one exist; and - which just need a single time clean-up code to be
executedOnExit()
of the block.
#6 Updated by Constantin Asofiei over 2 years ago
Ovidiu, the complexity from this arises from the fact that a i.e. RecordBuffer.finished
can't be moved by its own to 'executeOnExit', even for buffers scoped to the top-level-block: there is an entire 'finalizable' mechanism in the p2j.persist
package which is related to a buffer. And from the looks of it, even if the documentation at https://docs.progress.com/bundle/openedge-abl-error-handling-117/page/Transaction-scope-in-a-FINALLY-block.html states that the tx is completed (success or failure) before FINALLY is execute, the example above shows that the locking is not released.
So yes, we need tests (especially in the persist area) to determine which resources need to be finalized before the FINALLY and which after it.
An idea might be to take The transaction of the associated block is either complete (success) or undone (failure)
literally and just complete the tx, and not 'finalize' the resources... this would be done after the FINALIZABLE.
#8 Updated by Greg Shah over 2 years ago
- Related to Bug #5651: conditions raised from a finally block added