| Bug #40893 | Falcon concurrent unlock can cause invalid fetches | ||
|---|---|---|---|
| Submitted: | 20 Nov 2008 16:19 | Modified: | 13 Dec 2008 7:25 |
| Reporter: | Kevin Lewis | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Falcon storage engine | Severity: | S3 (Non-critical) |
| Version: | 6.0.8 | OS: | Any |
| Assigned to: | Kevin Lewis | CPU Architecture: | Any |
| Tags: | F_RECORD TREE | ||
[20 Nov 2008 16:20]
Kevin Lewis
Both Olav and Kevin have reproduced this.
[20 Nov 2008 17:06]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/59418 2914 Kevin Lewis 2008-11-20 Code cleanup and a comment change related to Bug#40893
[20 Nov 2008 17:23]
Kevin Lewis
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/59408 2912 Kevin Lewis 2008-11-19 Do not use Record::state = recUnlock. It is not recognized by many parts of the code and can cause the wrong behavior. Also, A lock record that is unlocked should stay on the transaction. It is still replaced on the recordLeaf, but other threads with pointers to it from a concurrent Table::fetch need to be able to see the transaction. It will be taken off the transaction later with all the other records on the transaction.
[11 Dec 2008 14:19]
Bugs System
Pushed into 6.0.9-alpha (revid:klewis@mysql.com-20081120170550-p48a7rrjs4by8ag1) (version source revid:hky@sun.com-20081127084516-nbu7693932vcz2st) (pib:5)
[13 Dec 2008 7:25]
MC Brown
No documentation needed.

Description: During the course of replacing the old transaction dependency linkages with a newer event counter system, Olav discovered that records being evaluated in Transaction::getRelativeState() were detached from transactions that were still active. A record needs to keep the transaction pointer until the transaction is visible to all. This is especially important once the new dependency manager is used, since there is no longer a direct link between transactions. The problem occured during Table::unlockRecord(). This function (1) changes the state of the record to recUnlock, (2) sets RecordVersion::transaction to null, and (3) puts it prior record back into the record tree (RecordLeaf). Steps 1 and 2 are both problems that need to be fixed. In a concurrent environment, another thread can find this lock record in the record tree just before it is detached and replaced with the prior. So while it has this pointer the record changes state and looses its pointer to the transaction. 1) There are about 25 places in the code that checks for Record::state == recLock and only one that also checks for recUnlock. We need to quit using recUnlock. 2) The pointer to the transaction needs to remain so that another thread in getrelativeState can do its job correctly. The current code sees this null pointer and assumes that this lock record which is going away is actually a committed record. In Falcon's default isolation of consistent-read, it is reported as committedInvisible, which causes the caller to look at the prior, which happens to be the right thing to do, but for the wrong reason. If, however, the isolation mode is read-committed, the caller would definitely get the wrong record. Maybe there would be an assert down the road, or wrong results from a query. Either way this is serious for read-committed isolation. How to repeat: Put a breakpoint on this line in Transaction::getRelativeState() while running falcon_bug_22165. for (int n = 0; n < numberStates; ++n) if (states [n].transactionId == transId) return CommittedInvisible; <-- break here If the record has state==recUnlock you see the problem. Suggested fix: Patch is on the way