Feature #5355
_Usertablestat metadata improvements
90%
Related issues
History
#1 Updated by Eric Faulhaber over 5 years ago
- Related to Bug #5306: AdaptiveQuery sets a found record into the buffer twice in dynamic mode added
#2 Updated by Eric Faulhaber over 5 years ago
Support for this VST was mostly implemented in #3814, however a few things remain to be addressed:
- add update counters for field updates made by the BUFFER-COPY statement/method;
- test/confirm temp-table support works and fix it if not;
- test/confirm the retrieve counter is working correctly for
AdaptiveQuerywhen in dynamic mode after #5306 is addressed.
For the #5306-related item, we know the retrieve counter is incorrectly incremented twice when AdaptiveQuery is in dynamic mode. This will be fixed in #5306, not here, but once that is done, we need to test the VST is working correctly.
#3 Updated by Eric Faulhaber over 5 years ago
- Related to Feature #3814: more schema metadata added
#4 Updated by Eric Faulhaber over 5 years ago
Regarding the temp-table support, there are cases where conversion optimizes 4GL code which deletes temp-table records in a loop to use a bulk delete operation in the converted result instead. This is an optimization worth preserving, but it means that the VST delete counter will be bypassed. Some re-engineering of this optimization to use the result of a SQL DELETE operation to update the VST delete counter (or some other approach) would be needed to deal with this. If not, this would be a permanent limitation/incompatibility with the 4GL's behavior.
#5 Updated by Igor Skornyakov over 5 years ago
Eric Faulhaber wrote:
Support for this VST was mostly implemented in #3814, however a few things remain to be addressed:
- add update counters for field updates made by the BUFFER-COPY statement/method;
- test/confirm temp-table support works and fix it if not;
- test/confirm the retrieve counter is working correctly for
AdaptiveQuerywhen in dynamic mode after #5306 is addressed.For the #5306-related item, we know the retrieve counter is incorrectly incremented twice when
AdaptiveQueryis in dynamic mode. This will be fixed in #5306, not here, but once that is done, we need to test the VST is working correctly.
Please note that we also have to make sure the counters are updated correctly in the presence of triggers (there are some tricky corner cases such as #3814-400)). This can be done after the issues described in #5289 will be resolved.
#6 Updated by Alexandru Lungu almost 4 years ago
- Status changed from New to WIP
- Assignee set to Dănuț Filimon
#7 Updated by Greg Shah 15 days ago
We have a project that reads _usertablestat to log the table activity of a session, so one more item needs to be part of this task.
The in-memory statistics are never flushed when the table is queried. In persist/orm/Query.java (around line 481), a query over _usertablestat calls:
UserTableStatUpdater.persist(db);
Here db is the session's database, which for a metadata query is the META database. UserTableStatUpdater instances are cached by the Database they were created for, and Database equality includes its type. The counters are recorded against the PRIMARY database: RecordBuffer calls update/create/retrieve/delete(getDatabase(), ...). So the flush finds a separate, empty instance and writes nothing. The only other flush happens at disconnect (ConnectTableUpdater). As a result, a query over _usertablestat during a session returns no records, and the table looks unimplemented.
Ovidiu found this and gave the fix:
= p2j/src/com/goldencode/p2j/persist/orm/Query.java
- UserTableStatUpdater.persist(db);
+ UserTableStatUpdater.persist(db.toType(Database.Type.PRIMARY));
Please include a testcase which reads _usertablestat for the current connection before and after creating, reading, updating and deleting records in a table, and checks that the differences are reported within the same session.
#8 Updated by Dănuț Filimon 7 days ago
I added the unit tests in xfer testcases/1957.
Created:- tests/persistence/schema_features/Test_UserTableStat.cls
- tests/persistence/schema_features/Test_UserTableStatTriggers.cls
- tests/persistence/db_triggers/TestFindTriggersInvalidatedQuery.cls
The current status of the tests is:
└─ FWD Test ✔
└─ tests.persistence.schema_features.Test_UserTableStatTriggers ✔
├─ testTriggersAccepting ✘ Expected: 2 but was: 1
├─ testFindRejected ✘ invoke() of program tests.persistence.schema_features.Test_UserTableStatTriggers failed
├─ testCreateRejected ✘ invoke() of program tests.persistence.schema_features.Test_UserTableStatTriggers failed
├─ testWriteRejected ✘ invoke() of program tests.persistence.schema_features.Test_UserTableStatTriggers failed
├─ testDeleteRejected ✘ invoke() of program tests.persistence.schema_features.Test_UserTableStatTriggers failed
├─ testGetCurrentUpdateRejected ✘ invoke() of program tests.persistence.schema_features.Test_UserTableStatTriggers failed
└─ testReadInsideTrigger ✔
└─ FWD Test ✔
└─ tests.persistence.db_triggers.TestFindTriggersInvalidatedQuery ✔
├─ testForEachExclusiveUpdateIndexField ✘ Expected: 3 but was: 5
├─ testForEachShareUpdateIndexField ✘ Expected: 3 but was: 5
├─ testForEachNoLockUpdateIndexFieldOtherBuffer ✔
└─ testQueryExclusiveUpdateIndexField ✘ Expected: 3 but was: 5
└─ FWD Test ✔
└─ tests.persistence.schema_features.Test_UserTableStat ✔
├─ testStatsVisibleInSameSession ✔
├─ testCreate ✔
├─ testRead ✔
├─ testUpdate ✔
├─ testDelete ✔
├─ testForEachRead ✔
├─ testQueryRead ✔
├─ testForEachUpdate ✔
├─ testForEachUpdateIndexField ✘ Expected: 3 but was: 5
├─ testBufferCopyStatement ✔
├─ testBufferCopyMethod ✔
├─ testForEachNoLockUpdateIndexField ✔
├─ testUpdateSameValue ✔
├─ testGetCurrentDelete ✘ Expected: 2 but was: 1
├─ testGetCurrentUpdate ✘ Expected: 2 but was: 1
├─ testTempTableNotCounted ✔
└─ testDeltasAccumulate ✔
testForEachUpdateIndexField test shows a problem where an AdaptiveQuery changes to dynamic mode after the first record and every record is put into the buffer twice (RecordBuffer.setRecord() is called twice and counted into the _usertablestat). TestFindTriggersInvalidatedQuery is an extension of it.
#9 Updated by Dănuț Filimon 7 days ago
I've let /fwd-testcases:canonicalize-ticket create a set of unit tests for this task (it took close to 2h), is it fine if I commit those to testcases too?
#10 Updated by Dănuț Filimon about 3 hours ago
- % Done changed from 0 to 90
5355a/16817 contains the changes for the fixes below.
testcases revisions are 1957 and 1970.
The tests were documented in: Schema_Features_Tests
Branch 5355a: issues fixed¶
| # | Issue | Fix | Why it had to be fixed |
|---|---|---|---|
| 1 | _UserTableStat stayed empty for the whole session |
orm/Query flushes UserTableStatUpdater.persist(db.toType(PRIMARY)) |
Counters are kept under the PRIMARY database, but the VST query runs on META, so the flush hit an empty instance. OE shows the counters at once. |
| 2 | Duplicate VST rows and error 91 in FOR EACH over _UserTableStat |
UserTableStatUpdater.persist() synchronized, skips a nested call; Results.isFetching()(ProgressiveResults, ResultsAdapter); AdaptiveQuery does not cache while fetching |
The flush commit re-ran the query that triggered it: rows were created twice and returned twice. Appeared once fix 1 made the flush work. |
| 3 | Read counted twice when a record is reloaded only to apply a lock | RecordBuffer.setRecord(..., firstLoad); PreselectQuery.coreFetch, RandomAccessQuery pass it |
FOR EACH EXCLUSIVE-LOCK updating an index field: OE 3 reads, FWD 5. |
| 4 | FIND trigger fired twice on the same lock reload | No FIND trigger when firstLoad is false |
OE fires 3 times for 3 records, FWD 5. |
| 5 | FIND CURRENT, GET CURRENT and FIND-CURRENT counted no read | New RecordBuffer.reloadCurrent(), used by RandomAccessQuery, PreselectQuery and BufferImpl |
OE counts one read when the buffer held the record NO-LOCK, none for a new record. |
| 6 | A FIND rejected by its trigger was not counted | Read counted before the FIND trigger runs | OE counts the read even when the trigger rejects it. |
| 7 | A CREATE rejected by its trigger was counted | Create counted in create() after the trigger, and in associate() |
OE does not count a rejected create. |
| 8 | The record restored by UNDO was not counted as read | LightweightUndoable.assign() counts the re-read |
OE re-reads the restored record when the buffer is empty or holds another record, or a full transaction undoes its changes. |
| 9 | The insert of a new record was counted as an update | flush() counts an update only for a changed record that is not new |
OE counts that first write as the create only. |
| 10 | RETURN ERROR in a database session trigger aborted the program | BlockManager.returnWorker rejects it only in UI triggers; return_statements.rules warns only for UI triggers |
OE allows it and rejects the event; FWD threw IllegalArgumentException. Every rejected-trigger test failed. |
Branch 5355a: tests per fix¶
| # | Tests that failed before the fix | Also covered by |
|---|---|---|
| 1 | Test_UserTableStat.TestStatsVisibleInSameSession and every Test_UserTableStat delta check | every usertablestat test (all read the VST); TestCrudCountersSameSession, TestVstReadViaForEachAndFind, TestVstRequery |
| 2 | TestVstReadViaForEachAndFind.TestUnfilteredForEach, TestFilteredForEach; TestTempTableBulkDelete.TestWhereDeleteLoop, TestUnconditionalDeleteLoop, TestEmptyTempTable (error 91) |
TestVstReadMidForEach |
| 3 | Test_UserTableStat.TestForEachUpdateIndexField (Expected: 3 but was: 5) | TestForEachShareIndexUpdate, TestOpenQueryExclusiveIndexUpdate, TestDynamicQueryIndexUpdate, TestDynamicModeRetrieveScaling |
| 4 | TestFindTriggersInvalidatedQuery.TestForEachExclusiveUpdateIndexField, TestForEachShareUpdateIndexField, TestQueryExclusiveUpdateIndexField (Expected: 3 but was: 5) | |
| 5 | Test_UserTableStat.TestGetCurrentDelete, TestGetCurrentUpdate; Test_UserTableStatTriggers.TestTriggersAccepting (Expected: 2 but was: 1) | TestCurrentReread, TestGetCurrentThenUpdateOrDelete.TestGetCurrentUpdate |
| 6 | Test_UserTableStatTriggers.TestFindRejected (Expected: 1 but was: 0; also needs fix 10) | |
| 7 | Test_UserTableStatTriggers.TestCreateRejected (Expected: 0 but was: 1) | TestRejectedTriggersStaticStatements.testCreateRejected, TestRejectedTriggersHandleMethods.TestRejectedBufferCreate |
| 8 | Test_UserTableStatTriggers.TestGetCurrentUpdateRejected (Expected: 3 but was: 2) | TestCreateUndone |
| 9 | TestVstReadInsideOpenTransaction.TestQueriedInsideOpenTransaction (Expected: TRUE but was: no) | TestDynamicBufferCrud |
| 10 | Test_UserTableStatTriggers.TestFindRejected, TestCreateRejected, TestWriteRejected, TestDeleteRejected, TestGetCurrentUpdateRejected; TestRejectedTriggersStaticStatements (4 tests); TestRejectedTriggersHandleMethods (3 rejected-trigger tests) |
Branch 5355a: issues found, not fixed¶
| # | Issue | Why not fixed here |
|---|---|---|
| 1 | FWD writes a new record later than OE (TestCreateAndFail fails) | Changes when FWD inserts records; same as #3814-398, needs its own task |
| 2 | OE serves a stale held copy of a _UserTableStat row (2 tests fail on OE) |
OE behaviour; FWD's current values were kept |
| 3 | ERROR-STATUS:ERROR not set after a rejected BUFFER-RELEASE() NO-ERROR |
Same result on OE and FWD; only the message text differs |
| 4 | Multi-tenant statistics are never written | Existing problem; planned as a separate task |
#11 Updated by Dănuț Filimon about 3 hours ago
Number 2 issues would require too many changes just to support this type of behavior from OE. The main idea is that FWD always returns the current counters, but OE shows the new counters only when the holding buffer releases it. Simple explanation: OE reports the counter as 0 while a row is held and 1 after release, FWD reports 1 in both cases. I'd like another opinion here.
As for number 1 and 3, those should be separate tasks.