Project

General

Profile

Feature #5355

_Usertablestat metadata improvements

Added by Eric Faulhaber over 5 years ago. Updated about 3 hours ago.

Status:
WIP
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

90%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

Related issues

Related to Database - Bug #5306: AdaptiveQuery sets a found record into the buffer twice in dynamic mode Closed
Related to Database - Feature #3814: more schema metadata Closed

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 AdaptiveQuery when 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

#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 AdaptiveQuery when 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.

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.

Also available in: Atom PDF