Bug #28165 Falcon: hang after select for update
Submitted: 30 Apr 2007 17:35 Modified: 3 May 2007 12:51
Reporter: Peter Gulutzan
Status: Closed
Category:Server: Falcon Severity:S2 (Serious)
Version:6.0.0-alpha-debug OS:Linux (SUSE 10 64-bit)
Assigned to: Kevin Lewis Target Version:

[30 Apr 2007 17:35] Peter Gulutzan
Description:
I create a Falcon table with two indexed columns.
I insert two rows, select for update, and update.
I rollback and try to update again.
Hang.

To recover from the hang, I have to say 'kill -9'.
Once, unrepeatably, that caused a corrupt database.

ChangeSet@1.2662, 2007-04-30

How to repeat:
set @@autocommit = 0;
create table t (s1 int, s2 int) engine=falcon;
create unique index i1 on t (s1,s2);
insert into t values (5,null),(5,null);
commit;
select * from t for update;
update t set s2 = 2;
update t set s2 = 2 limit 1;
rollback;
update t set s2 = 2 limit 1;
[30 Apr 2007 22:12] Hakan Kuecuekyilmaz
Verified as described. Added test case falcon_bug_28165.test which hangs with 100% CPU
usage.

Best regards,

Hakan
[2 May 2007 5:40] Kevin Lewis
I debugged this problem today and I may have a solution.  This is a very sticky problem.

The hang happens because there is a recordVersion belonging to a previously rolled back
transaction. The recordVersion is a lock record.  The transaction no longer exists, but
the Recordversion still has a pointer to it.  So in Table::fetchForUpdate there is a
for(;;) loop with a switch (state) in it that does a  default:
Log::debug("Table::fetchForUpdate: unexpected state %d\n", state); if the state is not
recognized.  This causes an infinite loop.  The default case should throw an exception to
prevent the hang.

But the real problem is the left over lock record after the rollback.  After stepping
through this over and over, I finally realized that the Transaction::rollback should
rollback records from newest to oldest just like Transaction::rollbackSavepoint() does. 
It pulls the recordVersions off of Transaction::records and stacks them in the opposite
ofer, from newest to oldest.  In this manner, Table::insert() can back up the most recent
version of the record one at a time.  

The reason this is now showing up is the introductino of lock records.  Before this, by
the time a Transaction::rollback occured, there was only one version of a record on the
transaction.  Now, there can be a lock record before a pending record version.
[2 May 2007 8:18] Kevin Lewis
Pushed the change that resorts the pending records so that they are 
rolled back from newest to oldest.  The test case now completes without hanging, and get
the expected results, except that the error message does not identify the correct key
value.  But this problem is reported as Bug#28158.
[2 May 2007 9:07] Hakan Kuecuekyilmaz
Test case falcon_bug_28165 passes now except for wrong error message which is Bug#28158.

Best regards,

Hakan
[3 May 2007 12:51] MC Brown
A note has been added to the 6.0.0 changelog.