List:Commits« Previous MessageNext Message »
From:Kevin Lewis Date:April 17 2008 11:59pm
Subject:RE: bk commit into 6.0 tree (vvaintroub:1.2642) BUG#35322
View as plain text  
Vlad, 

After waiting, you have to retry all unique indexes where the field has
changed, not just the current one you are searching. 

Please be sure that the call stack Hakan found does not contain a deadlock
involving syncUnique.

Kevin


>-----Original Message-----
>From: vvaintroub@stripped [mailto:vvaintroub@stripped]
>Sent: Wednesday, April 16, 2008 7:15 AM
>To: commits@stripped
>Subject: bk commit into 6.0 tree (vvaintroub:1.2642) BUG#35322
>
>Below is the list of changes that have just been committed into a local
>6.0 repository of vvaintroub.  When vvaintroub does a push these changes
>will be propagated to the main repository and, within 24 hours after the
>push, to the public repository.
>For information on how to access the public repository
>see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
>
>ChangeSet@stripped, 2008-04-16 14:14:49+02:00, vvaintroub@wva. +3 -0
>  Bug#35322 : Duplicate entries in unique index.
>  Make unique-check and insert/update atomic
>  (exclusive lock on index level)
>
>  storage/falcon/Index.h@stripped, 2008-04-16 14:14:47+02:00, vvaintroub@wva. +1
>-0
>    Bug#35322 : Duplicate entries in unique index.
>    Make unique-check and insert/update atomic
>
>  storage/falcon/Table.cpp@stripped, 2008-04-16 14:14:47+02:00, vvaintroub@wva.
>+74 -74
>    Bug#35322 : Duplicate entries in unique index.
>    Make unique-check and insert/update atomic
>
>  storage/falcon/Table.h@stripped, 2008-04-16 14:14:48+02:00, vvaintroub@wva.
+4
>-2
>    Bug#35322 : Duplicate entries in unique index.
>    Make check for uniqueness and insert atomic
>
>diff -Nrup a/storage/falcon/Index.h b/storage/falcon/Index.h
>--- a/storage/falcon/Index.h	2007-10-11 14:57:40 +02:00
>+++ b/storage/falcon/Index.h	2008-04-16 14:14:47 +02:00
>@@ -152,6 +152,7 @@ public:
> 	int			DIHashTableCounts;
> 	int			DIHashTableSlotsUsed;
> 	SyncObject	syncDIHash;
>+	SyncObject	syncUnique;
> };
>
> #endif //
>!defined(AFX_INDEX_H__02AD6A44_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
>diff -Nrup a/storage/falcon/Table.cpp b/storage/falcon/Table.cpp
>--- a/storage/falcon/Table.cpp	2008-04-11 19:34:16 +02:00
>+++ b/storage/falcon/Table.cpp	2008-04-16 14:14:47 +02:00
>@@ -84,6 +84,7 @@ static const char *relatedTables [] = {
> #undef THIS_FILE
> static const char THIS_FILE[]=__FILE__;
> #endif
>+static bool needUniqueCheck(Index *index, Record *record);
>
> //////////////////////////////////////////////////////////////////////
> // Construction/Destruction
>@@ -347,15 +348,6 @@ void Table::insert(Transaction *transact
> 		// Make insert/update atomic, then check for unique index
>duplicats
>
> 		recordNumber = record->recordNumber = dbb-
>>insertStub(dataSection, transaction);
>-
>-		if (indexes)
>-			{
>-			checkUniqueIndexes(transaction, record);
>-
>-			FOR_INDEXES(index, this);
>-				index->insert(record, transaction);
>-			END_FOR;
>-			}
>
> 		// Verify that record is valid
>
>@@ -363,7 +355,7 @@ void Table::insert(Transaction *transact
> 		transaction->addRecord(record);
> 		insert(record, NULL, recordNumber);
> 		inserted = true;
>-
>+		insertIndexes(transaction, record);
> 		updateInversion(record, transaction);
> 		fireTriggers(transaction, PostInsert, NULL, record);
> 		record->release();
>@@ -999,7 +991,7 @@ Record* Table::rollbackRecord(RecordVers
>
> 		recordToRollback->printRecord("Table::rollbackRecord");
> 		insert(priorRecord, recordToRollback, recordToRollback-
>>recordNumber);
>-		ASSERT(false);
>+		//ASSERT(false);
> 		}
>
> 	if (!priorRecord && recordToRollback->recordNumber >= 0)
>@@ -1182,6 +1174,57 @@ void Table::makeNotSearchable(Field *fie
> 	database->flushInversion(transaction);
> }
>
>+/**
>+@brief		index update , combined with unique check (atomic)
>+
>+		Determine if the record we intend to write will have a
duplicate
>conflict
>+			with any pending or visible records.
>+@details	For each  unique index, obtain an exclusive lock and check
the
>index
>+			update index if the search succeeded by not finding
a
>duplicate.
>+			Retry if a wait occurred.
>+			If a duplicate is found, an exception should be
caught by
>the caller.
>+		non-unique indexes are  updated without any check
>+**/
>+void Table::updateIndexes(Transaction *transaction, RecordVersion *record,
>Record *oldRecord)
>+{
>+	if (indexes)
>+	{
>+	FOR_INDEXES(index, this);
>+		Sync sync(&(index->syncUnique), "Table::updateIndexes");
>+		if(needUniqueCheck(index,record))
>+			for(;;)
>+			{
>+			sync.lock(Exclusive);
>+			if (!checkUniqueIndex(index, transaction, record ,
>&sync))
>+				break;
>+			}
>+		index->update(oldRecord, record, transaction);
>+	END_FOR;
>+	}
>+}
>+
>+/**
>+@brief		Uniqueness check combined with index insert (atomic)
>+**/
>+void Table::insertIndexes(Transaction *transaction, RecordVersion *record)
>+{
>+	if (indexes)
>+	{
>+	FOR_INDEXES(index, this);
>+		Sync sync(&(index->syncUnique), "Table::insertIndexes");
>+		if(needUniqueCheck(index,record))
>+			for(;;)
>+			{
>+			sync.lock(Exclusive);
>+			if(!checkUniqueIndex(index, transaction, record,
&sync))
>+				break;
>+			}
>+		index->insert(record, transaction);
>+	END_FOR;
>+	}
>+}
>+
>+
> void Table::update(Transaction * transaction, Record * oldRecord, int
>numberFields, Field** updateFields, Value * * values)
> {
> 	database->preUpdate();
>@@ -1243,19 +1286,12 @@ void Table::update(Transaction * transac
>
> 		// Make insert/update atomic, then check for unique index
>duplicats
>
>-		if (indexes)
>-			{
>-			checkUniqueIndexes(transaction, record);
>-
>-			FOR_INDEXES(index, this);
>-				index->update(oldRecord, record,
transaction);
>-			END_FOR;
>-			}
>
> 		scavenge.lock(Shared);
> 		validateAndInsert(transaction, record);
> 		transaction->addRecord(record);
> 		updated = true;
>+		updateIndexes(transaction, record, oldRecord);
>
> 		updateInversion(record, transaction);
> 		fireTriggers(transaction, PostUpdate, oldRecord, record);
>@@ -2415,40 +2451,7 @@ bool Table::isDuplicate(Index *index, Re
>
> 	return true;
> }
>-/**
>-@brief		Determine if the record we intend to write will have
a
>duplicate conflict
>-			with any pending or visible records.
>-@details	For each index, call checkUniqueIndex.
>-			Return if the search succeeded by not finding a
>duplicate.
>-			Retry if a wait occurred.
>-			If a duplicate is found, an exception should be
caught by
>the caller.
>-**/
>-
>-void Table::checkUniqueIndexes(Transaction *transaction, RecordVersion
>*record)
>-{
>-	Record *oldRecord = record->getPriorVersion();
>-	bool retry = true;
>
>-	while (retry)
>-		{
>-		retry = false;
>-		FOR_INDEXES(index, this);
>-			{
>-			if (INDEX_IS_UNIQUE(index->type) &&
>-				(!oldRecord || index->changed(record,
oldRecord)))
>-				{
>-				retry = checkUniqueIndex(index, transaction,
>record);
>-				if (retry)
>-					break;
>-				}
>-			if (retry)
>-				break;
>-			}
>-		END_FOR;
>-		}
>-
>-	return;
>-}
>
> /**
> @brief		Determine if the record we intend to write will have
a
>duplicate conflict
>@@ -2458,7 +2461,7 @@ void Table::checkUniqueIndexes(Transacti
> 			Return false if no duplicate was found.
> **/
>
>-bool Table::checkUniqueIndex(Index *index, Transaction *transaction,
>RecordVersion *record)
>+bool Table::checkUniqueIndex(Index *index, Transaction *transaction,
>RecordVersion *record, Sync *sync)
> {
> 	Bitmap bitmap;
> 	IndexKey indexKey(index);
>@@ -2467,7 +2470,7 @@ bool Table::checkUniqueIndex(Index *inde
>
> 	for (int32 recordNumber = 0; (recordNumber =
>bitmap.nextSet(recordNumber)) >= 0; ++recordNumber)
> 		{
>-		int retry = checkUniqueRecordVersion(recordNumber, index,
>transaction, record);
>+		int retry = checkUniqueRecordVersion(recordNumber, index,
>transaction, record, sync);
>
> 		if (retry)
> 			return true;  // restart the search since a wait
>occurred.
>@@ -2485,7 +2488,7 @@ bool Table::checkUniqueIndex(Index *inde
> 			Throw an exception if a duplicate WAS found
> **/
>
>-bool Table::checkUniqueRecordVersion(int32 recordNumber, Index *index,
>Transaction *transaction, RecordVersion *record)
>+bool Table::checkUniqueRecordVersion(int32 recordNumber, Index *index,
>Transaction *transaction, RecordVersion *record, Sync *syncUnique)
> {
> 	Record *rec;
> 	Record *oldRecord = record->getPriorVersion();
>@@ -2578,7 +2581,8 @@ bool Table::checkUniqueRecordVersion(int
> 			if (state == Active)
> 				{
> 				syncPrior.unlock(); // release lock before
wait
>-
>+				syncUnique->unlock(); // release lock before
wait
>+
> 				// Wait for that transaction, then restart
>checkUniqueIndexes()
>
> 				state = transaction->getRelativeState(dup,
>WAIT_IF_ACTIVE);
>@@ -2597,6 +2601,7 @@ bool Table::checkUniqueRecordVersion(int
> 			else if (activeTransaction)
> 				{
> 				syncPrior.unlock(); // release lock before
wait
>+				syncUnique->unlock(); // release lock before
wait
>
> 				state = transaction-
>>getRelativeState(activeTransaction,
>
activeTransaction->transactionId,
>WAIT_IF_ACTIVE);
>@@ -2998,21 +3003,15 @@ uint Table::insert(Transaction *transact
>
> 		// Make insert/update atomic, then check for unique index
>duplicats
>
>-		if (indexes)
>-			{
>-			checkUniqueIndexes(transaction, record);
>-
>-			FOR_INDEXES(index, this);
>-				index->insert (record, transaction);
>-			END_FOR;
>-			}
>
> 		// Do the actual insert
>
> 		transaction->addRecord(record);
> 		bool ret = insert(record, NULL, recordNumber);
>-		ASSERT(ret);
> 		inserted = true;
>+		insertIndexes(transaction, record);
>+		ASSERT(ret);
>+
>
> 		record->release();
> 		}
>@@ -3121,16 +3120,7 @@ void Table::update(Transaction * transac
> 				attachment->preUpdate(this, record);
> 		END_FOR;
>
>-		// Make insert/update atomic, then check for unique index
>duplicats
>-
>-		if (indexes)
>-			{
>-			checkUniqueIndexes(transaction, record);
>
>-			FOR_INDEXES(index, this);
>-				index->update(oldRecord, record,
transaction);
>-			END_FOR;
>-			}
>
> 		//updateInversion(record, transaction);
> 		scavenge.lock(Shared);
>@@ -3144,6 +3134,8 @@ void Table::update(Transaction * transac
> 			}
>
> 		updated = true;
>+		// Make insert/update atomic, then check for unique index
>duplicats
>+		updateIndexes(transaction, record, oldRecord);
> 		//fireTriggers(transaction, PostUpdate, oldRecord, record);
>
> 		// If this is a re-update in the same transaction and the
same
>savepoint,
>@@ -3772,3 +3764,11 @@ SyncObject* Table::getSyncPrior(int reco
> 	return syncPriorVersions + lockNumber;
> }
>
>+
>+static bool needUniqueCheck(Index *index, Record *record)
>+{
>+	Record *oldRecord = record->getPriorVersion();
>+	return (INDEX_IS_UNIQUE(index->type) &&
>+		(!oldRecord || index->changed(record, oldRecord)));
>+
>+}
>diff -Nrup a/storage/falcon/Table.h b/storage/falcon/Table.h
>--- a/storage/falcon/Table.h	2008-04-09 10:23:49 +02:00
>+++ b/storage/falcon/Table.h	2008-04-16 14:14:48 +02:00
>@@ -103,8 +103,8 @@ public:
> 	void		makeNotSearchable (Field *field, Transaction
>*transaction);
> 	bool		dropForeignKey (int fieldCount, Field **fields,
Table
>*references);
> 	void		checkUniqueIndexes (Transaction *transaction,
>RecordVersion *record);
>-	bool		checkUniqueIndex(Index *index, Transaction
*transaction,
>RecordVersion *record);
>-	bool		checkUniqueRecordVersion(int32 recordNumber, Index
>*index, Transaction *transaction, RecordVersion *record);
>+	bool		checkUniqueIndex(Index *index, Transaction
*transaction,
>RecordVersion *record, Sync *sync);
>+	bool		checkUniqueRecordVersion(int32 recordNumber, Index
>*index, Transaction *transaction, RecordVersion *record, Sync *sync);
> 	bool		isDuplicate (Index *index, Record *record1, Record
>*record2);
> 	void		checkDrop();
> 	Field*		findField (const WCString *fieldName);
>@@ -208,9 +208,11 @@ public:
> 	void			insert (Transaction *transaction, int count,
Field
>**fields, Value **values);
> 	uint			insert (Transaction *transaction, Stream
*stream);
> 	bool			insert (Record *record, Record *prior, int
>recordNumber);
>+	void			insertIndexes(Transaction *transaction,
>RecordVersion *record);
>
> 	void			update (Transaction *transaction, Record
*record,
>int numberFields, Field **fields, Value** values);
> 	void			update(Transaction * transaction, Record
>*oldRecord, Stream *stream);
>+	void			updateIndexes(Transaction *transaction,
>RecordVersion *record, Record *oldRecord);
>
> 	void			deleteRecord (Transaction *transaction,
Record
>*record);
> 	void			deleteRecord (int recordNumber);
>
>--
>MySQL Code Commits Mailing List
>For list archives: http://lists.mysql.com/commits
>To unsubscribe:    http://lists.mysql.com/commits?unsub=1

Thread
bk commit into 6.0 tree (vvaintroub:1.2642) BUG#35322vvaintroub16 Apr
  • RE: bk commit into 6.0 tree (vvaintroub:1.2642) BUG#35322Kevin Lewis18 Apr
    • RE: bk commit into 6.0 tree (vvaintroub:1.2642) BUG#35322Vladislav Vaintroub18 Apr