Bug #46377 | falcon_chill_thaw_compare asserts in Record::setEncodedRecord() | ||
---|---|---|---|
Submitted: | 24 Jul 2009 18:28 | Modified: | 26 May 2010 17:46 |
Reporter: | Olav Sandstå | Email Updates: | |
Status: | Unsupported | Impact on me: | |
Category: | MySQL Server: Falcon storage engine | Severity: | S2 (Serious) |
Version: | 6.0.12-alpha | OS: | Any |
Assigned to: | Kevin Lewis | CPU Architecture: | Any |
[24 Jul 2009 18:28]
Olav Sandstå
[24 Jul 2009 18:29]
Olav Sandstå
Setting to verified based on seeing it happen in both of the latest two pushes on both Linux and Windows in Pushbuild 2.
[24 Jul 2009 18:52]
Kevin Lewis
I added this assert, so I will try to figure out why it could possibly fail.
[27 Jul 2009 12:01]
Olav Sandstå
This crash was first seen (at least in Pushbuild) after the following push: http://lists.mysql.com/commits/78794
[19 Aug 2009 16:38]
Kevin Lewis
I reproduced this today while debugging and running RQG combinations with record-memory-max=50Mb and record-chill-threshold=10Kb. The record is being thawed in setEncodedRecord because a call is made to Index::duplicateKey. So Falcon is comparing an updated record version with all previous versions to see if there is a conflict. The current base record is committed on transaction 1713 with savepoint 2 but the prior record is also transaction 1713, but with savepoint 0. Since the transaction was committed and completed, the virtualOffset into the serial log was set to 0, so in order to thaw, the record must be fetched from the page. But only the most recent version is in the page. This is a record version that thawAll did not thaw at complete time. It is a useless record anyway and should not be thawed, it should have been queuedForDelete by releaseSavepoint. So I need to either 1) prevent duplicateKey from looking at these, 2) make sure that these extra useless committed records are thawed, or 3) make sure these extra useless records are not on the prior record chain after the transaction is committed.
[20 Aug 2009 14:52]
Kevin Lewis
The easiest and most correct solution from above is 2 (Make sure thawAll works for these useless records). Solution 1 (don't look at these data buffer) cannot be done because it is indeed necessary to have these data buffers around. That is because indexes are not cleaned up until the record is scavenged. In order to scavenge the indexes, the data buffer must be known. Another reason is that indexes only contain one copy of any key value that points to this record number. So if multiple record versions contain the same key value, that key value is not deleted during scavenging until the last record version with that value is scavenged. In addition, new record version during an update must check all the previous record versions to see if it has a new key value for that record number. Transaction::thawAll() runs by the gopher when the transaction completes in order to prevent unthawable records. But it erroneously did not try to thaw records that were older than the oldest active record. It needs to do this so that their key values can be scavenged correctly. In addition, RecordVersion::thaw() does not try to thaw from the serial log if the transaction is no longer writePending. Transaction::writeComplete is called immediately after thawAll() so normally, this would not matter if thawAll would get them all. But if there were some memory problems, thawAll may give up trying to thaw a a completing record. So the best approach would be to thaw from the serial log whenever there is a virtualOffset recorded with the record. SRLUpdateRecords::thaw() will set it to zero if that offset cannot be found, so if it is available, try to use it. The serial log can contain multiple record versions, each with a different virtualOffset, but the data page can only contain one.
[20 Aug 2009 15:00]
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/81183 2767 Kevin Lewis 2009-08-20 Bug#46377 - Record::setEncodedRecord() asserts if a newly thawed record is not the same length as what was chilled. This was happening because Transaction::thawAll was not thawing ALL old records a complete-time. It was skipping records that were older than the oldest active, which could easily happen if the gophers get a little behind. This patch changes Transaction::thawAll to thaw all older record versions. In addition, RecordVersion::thaw() is changed to thaw from the serial log any time the virtualOffset still exists. If that portion of the serial log is no longer available, the virstualOffset is reset to zero in SRLUpdateRecords::thaw()