Bug #8273
avoid ErrorConditionException for FIND ... NO-ERROR if no record is found
100%
Related issues
History
#1 Updated by Constantin Asofiei almost 2 years ago
- Related to Bug #9032: Reduce the number of exceptions that are being thrown added
#4 Updated by Andrei Iacob about 1 year ago
- Assignee set to Andrei Iacob
- Status changed from New to WIP
Based on #9663, I've noticed that for a FIND ... NO-ERROR that is executed ~130k times with no record found, executing errorReport inside finalzeFind takes about 40%. This is because ErrorConditionException is thrown and caught multiple times.
My idea is to introduce a new flag for ErrorManager, preventThrow, that can be enabled in between errorReport.run() when silent mode is active and to return instead of *throw*ing in recordOrThrowError.
With this I expect a 5% total gain on the scenario of #9633.
Committed changes to 8273a/16020. Please review!
#5 Updated by Andrei Iacob about 1 year ago
- Status changed from WIP to Review
- reviewer Alexandru Lungu, Constantin Asofiei added
#6 Updated by Constantin Asofiei about 1 year ago
Andrei, the raised ERROR condition still needs to properly set ERROR-STATUS:ERROR and record as ERROR-STATUS:GET/NUM-MESSAGE - I don't think this is happening with your changes.
#7 Updated by Andrei Iacob about 1 year ago
ERROR-STATUS is still set. Changes are targeted to only skip the throw. Check the following testcase (it works with FIND / FIRST / LAST):
define temp-table tt
field f1 as int.
message error-status:error.
find tt no-error.
message error-status:error
error-status:num-messages
error-status:get-message(1).
#8 Updated by Constantin Asofiei about 1 year ago
- Status changed from Review to Internal Test
Understood now. Lets test it.
#9 Updated by Andrei Iacob about 1 year ago
- customer unit tests;
- #9663;
- reports + harness;
- performance tests (as) - minor improvement;
- performance tests (sp) - nothing noticeable;
- Andrei (ap) to finish another unit tests suite.
Let me know if you think testing plan should be extended.
#10 Updated by Andrei Plugaru about 1 year ago
Andrei Iacob wrote:
I'm waiting a response from:
- Andrei (ap) to finish another unit tests suite.
Unit tests showed no regressions! ✅
#11 Updated by Constantin Asofiei about 1 year ago
ETF passed.
#12 Updated by Alexandru Lungu about 1 year ago
- % Done changed from 0 to 50
- Status changed from Internal Test to WIP
Review of 8273a:
- I think there is an issue with
setPreventThrowbracketing. IferrorReport.run();is throwing an exception, the reset won't be done. Please embederrorHelper.setPreventThrow(false);in afinallyblock.errorReportis usually a trivial call toErrorManager, but any non-expected exception can cause havoc (a NPE for instance).
Concern on the current implementation:
- Please check a
CompoundQuerywithFOR EACH ..., FIRST ...syntax unoptimized. As the second component is a RAQ, it will be executed within theCompoundQuery- First table have several records, the second has none. Do a
GET FIRST ..... It will find something in the first component, but within the second there will be nothing, so it should throw a Query off-end exception, so thatCompoundQueryknows that there is no proper match with the second component. If theGET FIRSTis run within a silent batch (NO-ERROR), the second component will think it is running a silentFirst and will not throw query off-end exception. This is theory and should be tested ... does it work as expected? Same applies toGET LAST. - My point is that
isSilentmay be set somewhere higher up the stream, so that the RAQ will think that it should avoid throwing errors, but, in fact, the SILENT was not meant for it.
- First table have several records, the second has none. Do a
- CAN-FIND and CAN-FIND also converts to a FindQuery. Can we run the CAN-FIND inside a silent-block so the RAQ within will incorrectly think that the SILENT was for it?
Overall, I think it is risky to use errorHelper.isSilent(). I would rather make use of the existing silentFirst, silentLast, etc. method to properly target your changes for these constructs. A CompoundQuery or CAN-FIND will use the usual API of first, last, etc., but only FIND ... NO-ERROR will convert to a silent* method.
Now that I am looking to the code I see inside silentFirst:
boolean wasLenientOffEnd = isLenientOffEnd();
if (!wasLenientOffEnd)
{
setLenientOffEnd(true);
}
This is basically forcing the query to be lenient-off-end (aka not throw errors when running off-end). This flag is used on setRecord so that RecordBuffer will call RB.throwOffEnd if the DMO is null. However, this check is done only for NEXT and PREVIOUS. FIRST, UNIQUE and LAST use finalizeFind as you noted.
- with 8273a,
isSilentis used and may represent a relaxed condition. We should drive the supressing by setting a flag insilentUnique,silentFirstandsilentLast.- double-check how NEXT and PREVIOUS work with
silent*. They do not usefinalizeFind.
- double-check how NEXT and PREVIOUS work with
- with trunk,
silentNextandsilentPreviousmay not set theerror-statusproperly.lenientOffEndshould be used internally inCompoundQueryfor instance or FOR EACH blocks that do NEXT under the hood.
- ensure that the suppressing of QOEE is only for
FIND ... NO-ERRORpattern and not for other embedded usages inside CAN-FIND, CompoundQuery or invalidated AdaptiveQuery.
Maybe we should unify the implementation to use lenientOffEnd, but rather rename it to offEndBehavior make it an enum: NONE, SILENT (only log), THROW. This will force us to implement the lenientOffEnd properly once and for all.
Also, I do not like that we also have a errorIfNull separate flag. Why would that be any different? Look at RecordBuffer.setRecord javadoc:
* @param errorIfNull
* {@code false} to raise an end condition if the record being set is {@code null};
* else {@code true} (caller is responsible for handling appropriately in the latter case).
* @param lenientOffEnd
* {@code false} to raise an end condition if the record being set is {@code null};
* else {@code true} (caller is responsible for handling appropriately in the latter case).#13 Updated by Andrei Iacob about 1 year ago
Rebased 8273a with trunk/16028.
Alexandru Lungu wrote:
Review of 8273a:
I suggest extending the scope of this task to better handle NEXT/PREVIOUS/FIRST/UNIQUE/LAST query-off-end throwing, because:
- with 8273a,
isSilentis used and may represent a relaxed condition. We should drive the supressing by setting a flag insilentUnique,silentFirstandsilentLast.
- double-check how NEXT and PREVIOUS work with
silent*. They do not usefinalizeFind.
NEXT and PREVIOUS do the same things as finalizeFind, except the errorReport. IMO making NEXT and PREV also use finalizeFind with a new errorReport makes sense.
- with trunk,
silentNextandsilentPreviousmay not set theerror-statusproperly.
Yes, error-status is not set in trunk. In OE, FIND NEXT/PREV ... NO-ERROR only sets error-status:error, while error message is empty.
Maybe we should unify the implementation to use
lenientOffEnd, but rather rename it tooffEndBehaviormake it an enum: NONE, SILENT (only log), THROW. This will force us to implement thelenientOffEndproperly once and for all.
Committed a prototype of it (please ignore leftover TODOs over javadocs and missing history entry).
Also, I do not like that we also have a
errorIfNullseparate flag. Why would that be any different? Look atRecordBuffer.setRecordjavadoc:
I traced back most of the uses of RecordBuffer.setRecords. Mostly, this flag is passed as false, in other cases AbstractQuery.errorIfNull is passed or some in a boolean expression containing other parameters.
Consider that for silentUnique/silent*,silent(() -> {...}) block, errorIfNull is set to true.
lenientOffEndshould be used internally inCompoundQueryfor instance or FOR EACH blocks that do NEXT under the hood.
- ensure that the suppressing of QOEE is only for
FIND ... NO-ERRORpattern and not for other embedded usages inside CAN-FIND, CompoundQuery or invalidated AdaptiveQuery.
I'm looking into this now.
#14 Updated by Andrei Iacob about 1 year ago
- Status changed from WIP to Review
Andrei Iacob wrote:
lenientOffEndshould be used internally inCompoundQueryfor instance or FOR EACH blocks that do NEXT under the hood.
- ensure that the suppressing of QOEE is only for
FIND ... NO-ERRORpattern and not for other embedded usages inside CAN-FIND, CompoundQuery or invalidated AdaptiveQuery.I'm looking into this now.
None of these hit the changes made.
Committed the rest of the changes. Please take a look!
#15 Updated by Alexandru Lungu about 1 year ago
- Status changed from Review to WIP
- % Done changed from 50 to 80
Review of 8273a:
The changes are good; only minor things to assess:
- The save/restore logic in
RandomAccessQueryandAbstractQueryshould rather save theOffEndBehaviorthen a boolean. It would seem more natural than actual processing that and restoring from processed behavior. - For
CompoundQueryretrieve logic, the query underneath should beOffEndBehavior.NONE. Otherwise, when reaching the off-end of a component in CQ will set the ERROR-STATUS, which is not correct. Please unit test this case. - For
PreselectQuery, when doing an OPEN, I am not sure that running off-end will set ERROR-STATUS. I tend to think that it should beOffEndBehavior.NONE. Please unit test this case. - For
QueryWrapper, are the OPEN QUERY in generalOffEndBehavior.SILENT? I would expected these to beOffEndBehavior.NONE. In other words, doing GET NEXT off-end should or should not set the error status? Please unit test this case. - I really think
BlockManagershould setOffEndBehavior.NONE. Definitely an off-endFOR EACHblock is not going to set the ERROR-STATUS. Please unit test this case. - Please make the save/restore logic in
finalizeFindmore canonic. In other words, please save theisPreventThrowand set it back. You may have nestedsetPreventThrowand I don't quite enjoy hard-coding the true/false when setting.
While I understand that currently OffEndBehavior.SILENT and OffEndBehavior.NONE are handled the same, this should not semantically be the case. NONE should not set the error-status. Even though your implementation doesn't ever reach that point, the semantic is confusing (some SILENT are registering the ERROR and some are not). Places that shouldn't set the ERROR should be made NONE instead of SILENT.
#16 Updated by Andrei Iacob about 1 year ago
- Status changed from WIP to Review
Alexandru Lungu wrote:
Review of 8273a:
The changes are good; only minor things to assess:
- For
CompoundQueryretrieve logic, the query underneath should beOffEndBehavior.NONE. Otherwise, when reaching the off-end of a component in CQ will set the ERROR-STATUS, which is not correct. Please unit test this case.- For
PreselectQuery, when doing an OPEN, I am not sure that running off-end will set ERROR-STATUS. I tend to think that it should beOffEndBehavior.NONE. Please unit test this case.- For
QueryWrapper, are the OPEN QUERY in generalOffEndBehavior.SILENT? I would expected these to beOffEndBehavior.NONE. In other words, doing GET NEXT off-end should or should not set the error status? Please unit test this case.- I really think
BlockManagershould setOffEndBehavior.NONE. Definitely an off-endFOR EACHblock is not going to set the ERROR-STATUS. Please unit test this case.While I understand that currently
OffEndBehavior.SILENTandOffEndBehavior.NONEare handled the same, this should not semantically be the case.NONEshould not set the error-status. Even though your implementation doesn't ever reach that point, the semantic is confusing (some SILENT are registering the ERROR and some are not). Places that shouldn't set the ERROR should be madeNONEinstead ofSILENT.
None of the above set error status, so I agree that from a semantically point of view offEndBehavior should be set to NONE.
- The save/restore logic in
RandomAccessQueryandAbstractQueryshould rather save theOffEndBehaviorthen a boolean. It would seem more natural than actual processing that and restoring from processed behavior.- Please make the save/restore logic in
finalizeFindmore canonic. In other words, please save theisPreventThrowand set it back. You may have nestedsetPreventThrowand I don't quite enjoy hard-coding the true/false when setting.
Done. Committed changes, current revision 16032.
#17 Updated by Alexandru Lungu about 1 year ago
Review of 8273a:
- public boolean isLenientOffEnd()
+ public boolean isOffEndThrow()
{
- return buffer.txHelper.errHlp.isSilent() || super.isLenientOffEnd();
+ return buffer.txHelper.errHlp.isSilent() || offEndBehavior != OffEndBehavior.THROW;
}
AdaptiveFind: This doesn't make sense.isOffEndThrowshould happen if the error helper is not silent or is OffEndBehavior.THROW.DynamicResultsshould set query on NONE instead of SILENT.CompoundQuery: plenty of empty line changes. Please rollback.PreselectQuery: javadoc forinitializeis slightly misaligned. Please use { @ code .... } syntax instead of tags.
Please take time to carefully go through the changes and ensure there are no mistakes while replacing lenientOffEnd with offEndBehavior in terms of logical conditionals (e.g. negating condition).
#18 Updated by Andrei Iacob about 1 year ago
Done. I've removed every reference of 'lenientOffEnd' from all sources.
#19 Updated by Alexandru Lungu 12 months ago
- % Done changed from 80 to 100
- Status changed from Review to Internal Test
I am OK with the changes. Please proceed with comprehensive testing.
#20 Updated by Razvan-Nicolae Chichirau 12 months ago
Smoke-test for 8273a on another customer application showed no regressions.
#21 Updated by Andrei Iacob 12 months ago
- % Done changed from 100 to 90
- Status changed from Internal Test to WIP
- majority of them are caused by
RAA.prevdue to introducingfinalizeFindwithnoRecordOrThrowError. Reverting this fixes the issue; - half of
gso_rfq_testsfail - One test has a crash and the other depend on it. I'm looking into it.
#22 Updated by Alexandru Lungu 12 months ago
Please add any reproduction of these problems to the suite of unit tests you made for #8273 changes.
#23 Updated by Andrei Iacob 12 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
Andrei Iacob wrote:
- majority of them are caused by
RAA.prevdue to introducingfinalizeFindwithnoRecordOrThrowError. Reverting this fixes the issue;
This is caused by how finalizeFind for RAA.next and RAA.previous was used. In both cases, finalizeFind executed updateBuffer with errNull as isErrorIfNull(), but next and prev always sent this param as false. Alongside this, for RAA.prev, offEnd was sent as BACK instead of FRONT.
- half of
gso_rfq_testsfail - One test has a crash and the other depend on it. I'm looking into it.
Following the discussion in #7143-1631 this is a regression from trunk.
Committed changes.
#24 Updated by Alexandru Lungu 11 months ago
- Status changed from Review to Internal Test
I am OK with the changes in 8273a.
#26 Updated by Alexandru Lungu 11 months ago
- Status changed from Internal Test to Merge Pending
Testing completed and passed for:
Love it! Please merge 8273a to trunk now.