#At file:///C:/Work/bzr/Merge/mysql-6.0-falcon-team/ based on revid:olav@stripped
2708 Kevin Lewis 2009-05-19
Bug#44946 - ASSERT(vector[index] < size); is hit.
--------------------------------
Record.cpp & Record.h
Protect Record::highWater from being incremented in lock-step with another thread also running Record::getEncodedValue(). Do this by using a local copy of highWater and updating it by CAS only if it is higher than what is there. We assume that multiple threads can update the vector at the same time since they are all writing the same values to the vector. If multiple threads thawing the same record rarely ever happens, there will not be too much performance cost due to cache line bounces. And this patch allows it safely. In order to use CAS, Record::highWater must change from a short to an INTERLOCK_TYPE.
Change the assert to a FATAL message if (vector[index] > size - getSize()). The size includes the bytes used by the Record or RecordVersion object.
In Record::setEncodedRecord(), 'size' only needs to be adjusted for non-interlocked calls. The interlocked calls are done during a thaw. When a record is chilled, the size variable is left the same.
--------------------------------
RecordVersion.cpp & SRLUpdateRecords.cpp
RecordVersion::thaw() should also check the virtualOffset before calling Transaction::thaw(). And if the Transaction cannot thaw, the virtualOffset should be immediately set to zero.
Add ASSERTs to RecordVersion::hasRecord() and RecordVersion::getRecordData() to make sure that there are no more 'unthawable' records.
--------------------------------
Transaction.cpp & Transaction.h
In order to prevent 'unthawable' records, make sure all records attached to a transaction are thawed by the gopher thread when the transaction is fully complete. Do this by adding a ne function; Transaction::thawAll()
modified:
storage/falcon/Record.cpp
storage/falcon/Record.h
storage/falcon/RecordVersion.cpp
storage/falcon/SRLUpdateRecords.cpp
storage/falcon/Transaction.cpp
storage/falcon/Transaction.h
=== modified file 'storage/falcon/Record.cpp'
--- a/storage/falcon/Record.cpp 2009-05-14 05:16:08 +0000
+++ b/storage/falcon/Record.cpp 2009-05-20 04:46:31 +0000
@@ -669,17 +669,25 @@ void Record::getEncodedValue(char* recor
if (highWater < index)
{
+ INTERLOCK_TYPE prevHighWater, myHighWater = highWater;
const UCHAR *p = (UCHAR*) recordData + vector[highWater];
- while (highWater < index)
+ while (myHighWater < index)
{
const UCHAR *q = EncodedDataStream::skip(p);
- vector[++highWater] = (USHORT) (q - (UCHAR*) recordData);
+ vector[++myHighWater] = (USHORT) (q - (UCHAR*) recordData);
p = q;
}
+
+ while (myHighWater > (prevHighWater = highWater))
+ if (COMPARE_EXCHANGE(&highWater, prevHighWater, myHighWater))
+ break;
}
- ASSERT(vector[index] < size);
+ if (vector[index] > size - getSize())
+ FATAL("vector[index] is too big; vector[index]=%d, size=%d, index=%d, highWater=%d\n",
+ vector[index], size, index, highWater);
+
const UCHAR *q = EncodedDataStream::decode((UCHAR*) recordData + vector[index], value, false);
if (++index < format->count && highWater < index)
@@ -734,11 +742,10 @@ char* Record::setEncodedRecord(Stream *s
// This could be called during a thaw, in which case the size is already set.
- if (size == getSize())
- size += totalLength;
-
if (interlocked)
{
+ ASSERT(size == getSize() + totalLength);
+
// If data.record has changed since allocating the new buffer, then free the new buffer
if (!COMPARE_EXCHANGE_POINTER(&data.record, NULL, dataBuffer))
@@ -748,7 +755,10 @@ char* Record::setEncodedRecord(Stream *s
}
}
else
+ {
+ size += totalLength;
data.record = dataBuffer;
+ }
return dataBuffer;
}
=== modified file 'storage/falcon/Record.h'
--- a/storage/falcon/Record.h 2009-05-12 22:58:23 +0000
+++ b/storage/falcon/Record.h 2009-05-20 04:46:31 +0000
@@ -186,7 +186,7 @@ public:
volatile INTERLOCK_TYPE useCount;
int recordNumber;
int size;
- short highWater;
+ volatile INTERLOCK_TYPE highWater;
UCHAR encoding;
UCHAR state;
=== modified file 'storage/falcon/RecordVersion.cpp'
--- a/storage/falcon/RecordVersion.cpp 2009-05-12 22:58:23 +0000
+++ b/storage/falcon/RecordVersion.cpp 2009-05-20 04:46:31 +0000
@@ -414,20 +414,20 @@ char *RecordVersion::thaw()
// is false, then the record data has been written to the data pages.
Transaction *trans = findTransaction();
-
if (trans)
{
- if (trans->writePending)
+ if (trans->writePending && virtualOffset)
recordData = trans->thaw(this, &bytesReallocated);
trans->release();
}
- // The record data is no longer available in the serial log, so zap the
- // virtual offset and restore from the data page.
+ // If the record data is no longer available in the serial log,
+ // zap the virtual offset and restore from the data page.
- if (bytesReallocated == 0)
+ if (recordData == recordIsChilled)
{
+ setVirtualOffset(0);
Stream stream;
Table *table = format->table;
@@ -439,7 +439,6 @@ char *RecordVersion::thaw()
if (bytesReallocated > 0)
{
- virtualOffset = 0;
table->debugThawedRecords++;
table->debugThawedBytes += bytesReallocated;
@@ -524,6 +523,7 @@ bool RecordVersion::hasRecord(void)
if (recordData == recordIsChilled)
{
recordData = thaw();
+ ASSERT(recordData != recordIsChilled);
return (recordData != NULL);
}
@@ -535,7 +535,10 @@ char* RecordVersion::getRecordData()
char* recordData = data.record;
if (recordData == recordIsChilled)
+ {
recordData = thaw();
+ ASSERT(recordData != recordIsChilled);
+ }
return recordData;
}
=== modified file 'storage/falcon/SRLUpdateRecords.cpp'
--- a/storage/falcon/SRLUpdateRecords.cpp 2009-05-12 22:58:23 +0000
+++ b/storage/falcon/SRLUpdateRecords.cpp 2009-05-20 04:46:31 +0000
@@ -74,11 +74,14 @@ char* SRLUpdateRecords::thaw(RecordVersi
SerialLogWindow *window = log->findWindowGivenOffset(record->getVirtualOffset());
- // Return if the serial log window is no longer available
+ // If the serial log window is no longer available, then this virtualOffset is
+ // no longer any good. Reset it and return.
if (!window)
+ {
+ record->setVirtualOffset(0);
return 0;
-
+ }
Sync sync(&log->syncWrite, "SRLUpdateRecords::thaw");
sync.lock(Exclusive);
@@ -97,7 +100,7 @@ char* SRLUpdateRecords::thaw(RecordVersi
control->getInt(); // sectionId
int recordNumber = control->getInt();
- ASSERT(recordNumber == record->recordNumber);
+ ASSERT(recordNumber == record->recordNumber); // validate the record number.
int dataLength = control->getInt();
*bytesReallocated = 0;
@@ -105,7 +108,7 @@ char* SRLUpdateRecords::thaw(RecordVersi
sync.unlock();
// setRecordData() handles race conditions with an interlocked compare and exchange,
- // but check the state and record number anyway
+ // but check the state anyway.
dataRecord = record->findRecordData();
if (dataRecord == recordIsChilled)
=== modified file 'storage/falcon/Transaction.cpp'
--- a/storage/falcon/Transaction.cpp 2009-05-12 14:35:40 +0000
+++ b/storage/falcon/Transaction.cpp 2009-05-20 04:46:31 +0000
@@ -557,6 +557,11 @@ char* Transaction::thaw(RecordVersion* r
if (dataRecord != recordIsChilled)
return dataRecord;
+ // If the virtualOffset is zero, it cannot be thawed from the serial log.
+ if (record->getVirtualOffset() == 0)
+ return dataRecord;
+
+
// Get pointer to record data in serial log
SerialLogControl control(database->dbb->serialLog);
@@ -1471,6 +1476,7 @@ void Transaction::fullyCommitted(void)
if (useCount < 2)
Log::debug("Transaction::fullyCommitted: Unusual use count=%d\n", useCount);
+ thawAll(); // Make sure all record versions are thawed.
writeComplete();
releaseCommittedTransaction();
}
@@ -1595,3 +1601,14 @@ bool Transaction::committedBefore(TransI
{
return (transactionState->commitId && transactionState->commitId < transactionId);
}
+
+void Transaction::thawAll(void)
+{
+ Sync syncRec(&syncRecords,"Transaction::thawAll");
+ syncRec.lock(Shared);
+
+ for (RecordVersion *record = firstRecord; record && record->nextInTrans; record = record->nextInTrans)
+ {
+ char* recordData = record->getRecordData();
+ }
+}
=== modified file 'storage/falcon/Transaction.h'
--- a/storage/falcon/Transaction.h 2009-05-12 14:35:40 +0000
+++ b/storage/falcon/Transaction.h 2009-05-20 04:46:31 +0000
@@ -95,6 +95,7 @@ public:
void printBlockage(void);
void getInfo(InfoTable* infoTable);
void fullyCommitted(void);
+ void thawAll(void);
void releaseCommittedTransaction(void);
void commitNoUpdates(void);
void validateRecords(void);
Attachment: [text/bzr-bundle] bzr/kevin.lewis@sun.com-20090520044631-csc5nrin437ol2go.bundle
| Thread |
|---|
| • bzr commit into mysql-6.0-falcon-team branch (kevin.lewis:2708)Bug#44946 | Kevin Lewis | 20 May |