
Matthew Vienneau (Customer) asked a question.
Environment is AIX Unix v12.2.17, CHUI.
I’ve encountered an issue that’s confounding me and it’s a bit complicated. I’ve spent a few hours distilling it down to the core code and I’m hoping someone has the curiosity (and knowledge!) to try and help me out. I've been doing this for 30+ years so it's kind of exciting to find something I haven't seen before, though I suspect I've seen hints of it over the decades (some index corruption) and not realized it.
The essence of the issue is that I create a record in one session and lock it, then I create a record in a separate session and try to find the second record. When I do that, the second session gets held by the first session, but only if if the first session also ran a few find statements (confused yet?).
First, let's set up the problem:
Create a table called “ve” with two fields:
Vehicle-no (integer)
Vin-no (char)
Add two indexes:
Vehicle-no (primary, unique, on vehicle-no)
Vin-no (unique, on vin-no).
In one session, run this code:
- create ve.
- ve.vehicle-no = 1.
-
- run du18r( recid( ve)).
du18r:
- def input parameter ve-recid# as recid no-undo.
-
- find ve
- where recid( ve) = ve-recid#.
-
- run du18s( recid( ve)). // "GREEN"
-
- ve.vin-no = "ABC". // "BLUE"
-
- update ve.vin-no. // Holds the record lock
-
du18s:
- def input parameter ve-recid# as recid no-undo.
-
- find ve no-lock
- where recid( ve) = ve-recid#.
-
This creates ve record #1 and locks it. It also does a bunch of record finds for the same record, which seems meaningless, but appear to be core to the issue.
In a separate session, run this code:
- create ve.
- ve.vehicle-no = 2.
-
- run du18f( recid( ve)).
du18f:
- def input parameter ve-recid# as recid no-undo.
-
- find ve no-lock
- where recid( ve) = ve-recid#.
This creates a ve record #2 and attempts to find it. But when it does, and this is the issue, you get this:
ve in use by mviennea on pts/1. Wait or press CTRL-A to stop. (121)
The record is locked by the other session. But not only are we searching with “no-lock”, we’re looking for record #2 and it’s record #1 that’s locked. Record #1 is somehow locking record #2.
Furthermore, and this is where things get really crazy:
If you comment out the "Green" line, the record doesn’t get locked.
If you comment out the "Blue" line, you get a different failure and vehicle 2 isn’t created:
** ve already exists with VIN "". (132)
If you move the Blue line above the Green line, then you don’t get the record lock.
If you change the vin-no index so that it’s not unique, then you don’t get the record lock.
To summarize without the code:
- Create record
- Call a .p and find the same record
- Call a .p and find the same record, then lock it.
- Create second record.
- Call a .p find record #2
…you get locked. But if you skip step #3, or assign the vin-no before step #3, you don’t get locked.
This greatly confuses me. How does the number of times I call separate .p code impact the lock status of a record?
And why does ve.vin-no having a value impact the lock status, but only when there’s a unique index on the field?
For that second question, I have a vague idea of an answer. Somehow the “find” statements are validating the vin-no index even though they’re not using the vin-no index. I’m guessing a metadata table is doing a check and saying, “hold on, we don’t have uniqueness while we wait for record #1 to be saved so let’s lock everything until that’s resolved”.
But why does it only happen when I nest two .p “find” calls in the original record creation? Why doesn’t it happen when I just do it once? Does OE have a rule where if you go two levels down in .p code and run a find statement then index validation is performed?
Anyway, as I said, I'm hoping someone has the patience to wade through this and offer insight or advice. Hopefully I learn something new or realize that I've misunderstood something all these years!
The minimal code that reproduces the issue:
Session #1:
Session #2:
Session #2 issues the message 2624 on FIND CURRENT:
ve in use by <user> on <tty>. Wait or choose CANCEL to stop. (2624)
But we will not get this message if FIND CURRENT in the first session is commented out.
FIND CURRENT creates the key for ve.vin-no with default value.
ASSIGN ve.vin-no deletes this "just-created" key.
But a transaction is not yet committed.