Project

General

Profile

Bug #6392

buffer flush and validation when the external program gets deleted can cause unique index validation error

Added by Constantin Asofiei about 2 years ago. Updated about 2 years ago.

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

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:

History

#2 Updated by Constantin Asofiei about 2 years ago

This is a recreate of a buffer being flushed when the external program gets deleted.

The table:

ADD TABLE "topic" 
  AREA "Schema Area" 
  DUMP-NAME "topic" 

ADD FIELD "f1" OF "topic" AS character 
  FORMAT "x(8)" 
  INITIAL "" 
  POSITION 2
  MAX-WIDTH 16
  ORDER 10

ADD FIELD "f2" of "topic" as character 
  FORMAT "x(8)" 
  INITIAL "" 
  POSITION 3
  MAX-WIDTH 16
  ORDER 20

ADD INDEX "idx1" ON "topic" 
  AREA "Schema Area" 
  UNIQUE
  INDEX-FIELD "f2" ASCENDING 

First program (txp1.p):

procedure proc0.
   create topic.
   assign topic.f1 = "123".
          // topic.f2 = "abc".
end.

Second program (txp2.p), run this:

for each topic:
   delete topic.
end.
def var i as int.
def var h as handle.

repeat transaction:
   run txp1.p persistent set h.
   run proc0 in h.
   message "here1".
   delete object h.

   run txp1.p persistent set h.
   run proc0 in h.
   message "here2".
   delete object h.

   run txp1.p persistent set h.
   run proc0 in h.
   message "here3".
   delete object h.

   leave.
end.

Note how in txp1.p the field part of the unique index is not touched. Thus, the 'endBatch' call will not validate the record. This will be performed when the external program gets deleted (and it seems OE does it like this, too).

In FWD, this abends the ProcedureManager.delete call; I've tried wrapping the 'delete' and 'scopeDeleted' calls in ErrorManager.nestedSilent(() -> target.deleted());, like this:

### Eclipse Workspace Patch 1.0
#P p2j6129a
Index: src/com/goldencode/p2j/util/ProcedureManager.java
===================================================================
--- src/com/goldencode/p2j/util/ProcedureManager.java    (revision 3608)
+++ src/com/goldencode/p2j/util/ProcedureManager.java    (working copy)
@@ -2367,12 +2367,12 @@
          // cleanup after the procedure
          for (Finalizable target : pdata.finalizables)
          {
-            target.deleted();
+            ErrorManager.nestedSilent(() -> target.deleted());
          }

          for (Scopeable target : pdata.scopeables)
          {
-            target.scopeDeleted();
+            ErrorManager.nestedSilent(() -> target.scopeDeleted());
          }

          // as the procedure no longer exists, delete the static resources
@@ -3376,7 +3376,7 @@
             wa.pendingResourceDelete = target;
             try
             {
-               ((Deletable) target).delete();
+               ErrorManager.nestedSilent(() -> ((Deletable) target).delete());
             }
             finally
             {

But is not enough, I think what's missing is a rollback in case of ValidationException.

#3 Updated by Constantin Asofiei about 2 years ago

The better recreate is this:

for each topic:
   delete topic.
end.
def var i as int.
def var h as handle.

repeat transaction i = 1 to 4:
   run txp1.p persistent set h.
   run proc0 in h.
   message "here1".
   delete object h.
end.

When the repeat loop iterates, it will trigger a flush which abends the program.

#4 Updated by Constantin Asofiei about 2 years ago

There is this interesting note here https://docs.progress.com/bundle/openedge-abl-reference-117/page/DELETE-PROCEDURE-statement.html :

Note that all buffers are validated before being disconnected (which might cause database write triggers to execute). If the validation fails, the DELETE PROCEDURE statement raises the ERROR condition and pends the deletion until the validation succeeds and all database write triggers have completed.

#5 Updated by Constantin Asofiei about 2 years ago

I've added a trigger, and this gets invoked before the proc0 internal procedure returns.

#6 Updated by Constantin Asofiei about 2 years ago

Constantin Asofiei wrote:

I've added a trigger, and this gets invoked before the proc0 internal procedure returns.

But the actual flush does happen on the external program delete (when the buffer is disconnected).

#7 Updated by Constantin Asofiei about 2 years ago

  • Status changed from New to WIP
  • Assignee set to Constantin Asofiei

#8 Updated by Constantin Asofiei about 2 years ago

In the end I think the root cause was the fact that BufferManager.dirtyBuffer was still referencing the deleted procedure's buffers. After I fixed this (plus the procedure delete code to not abend on error when deleting a resource), things look better).

Also available in: Atom PDF