List:Commits« Previous MessageNext Message »
From:Kevin Lewis Date:May 20 2009 4:46am
Subject:bzr commit into mysql-6.0-falcon-team branch (kevin.lewis:2708)
Bug#44946
View as plain text  
#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#44946Kevin Lewis20 May