List:Commits« Previous MessageNext Message »
From:Kevin Lewis Date:September 3 2008 2:52pm
Subject:bzr push into mysql-6.0-falcon branch (klewis:2808)
View as plain text  
 2808 Kevin Lewis	2008-09-03
      SyncHandler class.  A debugging tool for detecting deadlocks. 
      See https://inside.mysql.com/wiki/FalconDeadlockDetector
added:
  storage/falcon/SyncHandler.cpp
  storage/falcon/SyncHandler.h
modified:
  storage/falcon/CMakeLists.txt
  storage/falcon/Database.cpp
  storage/falcon/Database.h
  storage/falcon/Makefile.am
  storage/falcon/Statement.cpp
  storage/falcon/SyncObject.cpp
  storage/falcon/SyncObject.h

=== modified file 'storage/falcon/CMakeLists.txt'
--- a/storage/falcon/CMakeLists.txt	2008-08-27 09:49:44 +0000
+++ b/storage/falcon/CMakeLists.txt	2008-09-03 12:48:49 +0000
@@ -273,10 +273,11 @@ SET(FALCON_SOURCES 
 		SymbolManager.cpp 
 		Sync.cpp 
 		Synchronize.cpp
-		SyncObject.cpp 
-		SyncTest.cpp 
-		SyncWait.cpp 
-		Syntax.cpp 
+		SyncHandler.cpp
+		SyncObject.cpp
+		SyncTest.cpp
+		SyncWait.cpp
+		Syntax.cpp
 		TableAttachment.cpp
 		Table.cpp 
 		TableFilter.cpp 
@@ -555,6 +556,7 @@ SET(FALCON_SOURCES 
 		SymbolManager.h 
 		Sync.h 
 		Synchronize.h
+		SyncHandler.h 
 		SyncObject.h 
 		SyncTest.h 
 		SyncWait.h 

=== modified file 'storage/falcon/Database.cpp'
--- a/storage/falcon/Database.cpp	2008-08-11 13:22:53 +0000
+++ b/storage/falcon/Database.cpp	2008-09-03 12:48:49 +0000
@@ -75,6 +75,7 @@
 #include "RecordScavenge.h"
 #include "LogStream.h"
 #include "SyncTest.h"
+#include "SyncHandler.h"
 #include "PriorityScheduler.h"
 #include "Sequence.h"
 #include "BackLog.h"
@@ -462,6 +463,7 @@ Database::Database(const char *dbName, C
 	zombieTables = NULL;
 	updateCardinality = NULL;
 	backLog = NULL;
+	syncHandler = getFalconSyncHandler();
 	ioScheduler = new PriorityScheduler;
 	lastScavenge = 0;
 	scavengeCycle = 0;
@@ -610,6 +612,8 @@ Database::~Database()
 	delete transactionManager;
 	delete ioScheduler;
 	delete backLog;
+	if (syncHandler)
+		delete syncHandler;
 }
 
 void Database::createDatabase(const char * filename)
@@ -1560,7 +1564,7 @@ void Database::shutdown()
 
 	if (shuttingDown)
 		return;
-	
+
 	if (updateCardinality)
 		{
 		updateCardinality->close();
@@ -2479,6 +2483,10 @@ void Database::debugTrace(void)
 	if (falcon_debug_trace & FALC0N_SYNC_OBJECTS)
 		SyncObject::dump();
 	
+	if (falcon_debug_trace & FALC0N_SYNC_HANDLER)
+		if (syncHandler) 
+			syncHandler->dump();
+
 	if (falcon_debug_trace & FALC0N_REPORT_WRITES)
 		tableSpaceManager->reportWrites();
 	

=== modified file 'storage/falcon/Database.h'
--- a/storage/falcon/Database.h	2008-08-11 13:22:53 +0000
+++ b/storage/falcon/Database.h	2008-09-03 12:48:49 +0000
@@ -45,6 +45,7 @@ static const int FALC0N_SYNC_TEST			= 2;
 static const int FALC0N_SYNC_OBJECTS		= 4;
 static const int FALC0N_FREEZE				= 8;
 static const int FALC0N_REPORT_WRITES		= 16;
+static const int FALC0N_SYNC_HANDLER		= 32;
 
 #define TABLE_HASH_SIZE		101
 
@@ -102,6 +103,7 @@ class RecordScavenge;
 class PriorityScheduler;
 class SQLException;
 class BackLog;
+class SyncHandler;
 
 struct JavaCallback;
 
@@ -284,6 +286,7 @@ public:
 	TransactionManager	*transactionManager;
 	FilterSetManager	*filterSetManager;
 	TableSpaceManager	*tableSpaceManager;
+	SyncHandler			*syncHandler;
 	SearchWords			*searchWords;
 	Thread				*tickerThread;
 	PageWriter			*pageWriter;

=== modified file 'storage/falcon/Makefile.am'
--- a/storage/falcon/Makefile.am	2008-08-11 16:17:26 +0000
+++ b/storage/falcon/Makefile.am	2008-09-03 12:48:49 +0000
@@ -168,7 +168,9 @@ falcon_headers= Agent.h Alias.h Applicat
 		SRLUpdateRecords.h \
 		SRLVersion.h \
 		SRLWordUpdate.h \
-		Stack.h Statement.h StorageConnection.h \
+		Stack.h \
+		Statement.h \
+		StorageConnection.h \
 		StorageDatabase.h \
 		StorageHandler.h \
 		StorageParameters.h \
@@ -176,8 +178,12 @@ falcon_headers= Agent.h Alias.h Applicat
 		StorageTableShare.h \
 		StorageVersion.h \
 		Stream.h \
-		StreamSegment.h SymbolManager.h Sync.h SynchronizationObject.h \
+		StreamSegment.h \
+		SymbolManager.h \
+		Sync.h \
+		SynchronizationObject.h \
 		Synchronize.h \
+		SyncHandler.h \
 		SyncObject.h \
 		SyncTest.h \
 		SyncWait.h \
@@ -347,11 +353,18 @@ falcon_sources= Agent.cpp Alias.cpp \
 		SRLVersion.cpp \
 		SRLWordUpdate.cpp \
 		Stack.cpp \
-		Statement.cpp StorageConnection.cpp \
+		Statement.cpp \
+		StorageConnection.cpp \
 		StorageDatabase.cpp \
 		StorageHandler.cpp \
-		StorageTable.cpp StorageTableShare.cpp Stream.cpp \
-		StreamSegment.cpp SymbolManager.cpp Sync.cpp Synchronize.cpp \
+		StorageTable.cpp \
+		StorageTableShare.cpp \
+		Stream.cpp \
+		StreamSegment.cpp \
+		SymbolManager.cpp \
+		Sync.cpp \
+		Synchronize.cpp \
+		SyncHandler.cpp \
 		SyncObject.cpp\
 		SyncTest.cpp\
 		SyncWait.cpp\

=== modified file 'storage/falcon/Statement.cpp'
--- a/storage/falcon/Statement.cpp	2008-08-18 05:45:29 +0000
+++ b/storage/falcon/Statement.cpp	2008-09-03 12:48:49 +0000
@@ -144,6 +144,7 @@ Statement::Statement(Connection *pConnec
 	special = false;
 	active = false;
 	memset (&stats, 0, sizeof (stats));
+	syncObject.setName("Statement::syncObject");
 }
 
 Statement::~Statement()
@@ -2303,9 +2304,9 @@ void Statement::dropIndex(Syntax *syntax
 
 	checkAlterPriv (table);
 
-		Transaction *sysTransaction = database->getSystemTransaction();
+	Transaction *sysTransaction = database->getSystemTransaction();
 	table->dropIndex(name, sysTransaction);
-		database->commitSystemTransaction();
+	database->commitSystemTransaction();
 
 	Index::deleteIndex (database, schema, name);
 	database->commitSystemTransaction();

=== added file 'storage/falcon/SyncHandler.cpp'
--- a/storage/falcon/SyncHandler.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/falcon/SyncHandler.cpp	2008-09-03 12:48:49 +0000
@@ -0,0 +1,662 @@
+/* Copyright (C) 2008 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <string.h>
+#include <stdio.h>
+#include <memory.h>
+#include "Engine.h"
+#include "Log.h"
+#include "SyncObject.h"
+#include "Sync.h"
+#include "SyncHandler.h"
+#include "SQLError.h"
+#include "Thread.h"
+#include "Dbb.h"
+
+extern uint64		falcon_initial_allocation;
+
+static SyncHandler *syncHandler;
+static bool initialized = false;
+static const char *multipleLockList [] =
+	{
+	"Bdb::syncWrite",
+	NULL
+	};
+
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static const char THIS_FILE[]=__FILE__;
+#endif
+
+SyncHandler*	getFalconSyncHandler(void)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	if (!initialized)
+		{
+		initialized = true;
+		syncHandler = new SyncHandler();
+		}
+	
+	return syncHandler;
+#else
+	return NULL;
+#endif
+}
+
+SyncHandler*	findFalconSyncHandler(void)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	if (initialized && syncHandler)
+		return syncHandler;
+#endif
+	return NULL;
+}
+
+
+SyncHandler::SyncHandler(void)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	syncObjects        = new SyncObjectInfo* [syncObjHashSize];
+	locations          = new SyncLocationInfo* [locationHashSize];
+	threads            = new SyncThreadInfo* [threadHashSize];
+	locationStacks     = new LocationStackInfo* [stackHashSize];
+	possibleDeadlocks  = new DeadlockInfo* [deadlockHashSize];
+
+
+	memset(syncObjects,    0, sizeof(SyncObjectInfo*) * syncObjHashSize);
+	memset(locations,      0, sizeof(SyncLocationInfo*) * locationHashSize);
+	memset(threads,        0, sizeof(SyncThreadInfo*) * threadHashSize);
+	memset(locationStacks, 0, sizeof(LocationStackInfo*) * stackHashSize);
+	memset(possibleDeadlocks, 0, sizeof(DeadlockInfo*) * deadlockHashSize);
+
+	syncObjCount = 0;
+	locationCount = 0;
+	threadCount = 0;
+	locationStackCount = 0;
+	possibleDeadlockCount = 0;
+#endif
+}
+
+SyncHandler::~SyncHandler(void)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	int n;
+
+	for (n = 0; n < syncObjHashSize; ++n)
+		for (SyncObjectInfo *soi; (soi = syncObjects[n]);)
+			{
+			syncObjects[n] = soi->collision;
+			delete soi;
+			}
+
+	for (n = 0; n < locationHashSize; ++n)
+		for (SyncLocationInfo *loc; (loc = locations[n]);)
+			{
+			locations[n] = loc->collision;
+			delete loc;
+			}
+
+	for (n = 0; n < threadHashSize; ++n)
+		for (SyncThreadInfo *thd; (thd = threads[n]);)
+			{
+			threads[n] = thd->collision;
+			delete thd;
+			}
+
+	for (n = 0; n < stackHashSize; ++n)
+		for (LocationStackInfo *stk; (stk = locationStacks[n]);)
+			{
+			locationStacks[n] = stk->collision;
+			delete stk;
+			}
+
+	for (n = 0; n < deadlockHashSize; ++n)
+		for (DeadlockInfo *dli; (dli = possibleDeadlocks[n]);)
+			{
+			possibleDeadlocks[n] = dli->collision;
+			delete dli;
+			}
+
+	delete[] syncObjects;
+	delete[] locations;
+	delete[] threads;
+	delete[] locationStacks;
+	delete[] possibleDeadlocks;
+
+	initialized = false;
+	syncHandler = NULL;
+
+#endif
+}
+
+void SyncHandler::addLock(SyncObject *syncObj, const char* locationName)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	if (syncObj == &syncObject)
+		return;			// prevent recursion
+
+	Thread *thread = thread = Thread::getThread("SyncHandler::addLock");
+	if (locationName == NULL)
+		locationName = syncObj->getName();
+
+	Sync sync(&syncObject, "SyncHandler::addLock");
+	sync.lock(Exclusive);
+
+	SyncThreadInfo *thd = addThread(thread->threadId);
+	SyncObjectInfo *soi = addSyncObject(syncObj->getName());
+	SyncLocationInfo *loc = addLocation(locationName, soi);
+
+	addToThread(thd, loc);
+#endif
+}
+
+void SyncHandler::delLock(SyncObject *syncObj)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	if (syncObj == &syncObject)
+		return;
+
+	Sync sync(&syncObject, "SyncHandler::delLock");
+	sync.lock(Exclusive);
+
+	SyncThreadInfo *thd = findThread();
+	SyncObjectInfo * soi = findSyncObject(syncObj->getName());
+	if (soi == NULL)
+		Log::debug("* Error; %s (%s) could not be deleted from the thread. Not found.\n",
syncObj->getLocation(), syncObj->getName());
+	else
+		delFromThread(thd, soi);
+#endif
+}
+
+void SyncHandler::dump(void)
+{
+#ifdef USE_FALCON_SYNC_HANDLER
+	Sync sync(&syncObject, "SyncHandler::addLock");
+	sync.lock(Exclusive);
+
+	time_t now;
+	time(&now);
+	Log::debug("== Falcon Deadlock Detector - %24s ==\n", ctime(&now));
+	countLocationStacks();
+	validate();
+	showSyncObjects();
+	showLocations();
+	showLocationStacks();
+	showPossibleDeadlockStacks();
+#endif
+}
+
+#ifdef USE_FALCON_SYNC_HANDLER
+
+SyncThreadInfo* SyncHandler::findThread()
+{
+	Thread *thread = thread = Thread::getThread("SyncHandler::delLock");
+	int slot = thread->threadId % threadHashSize;
+	return findThread(thread->threadId, slot);
+}
+
+SyncThreadInfo* SyncHandler::findThread(int thdId, int slot)
+{
+	for (SyncThreadInfo *thd = threads[slot]; thd; thd = thd->collision)
+		if (thd->Id == thdId)
+			return thd;
+
+	return NULL;
+}
+SyncThreadInfo * SyncHandler::addThread(int thdId)
+{
+	int slot = thdId % threadHashSize;
+	SyncThreadInfo *thd = findThread(thdId, slot);
+
+	if (!thd)
+		{
+		thd = new SyncThreadInfo;
+		thd->Id = thdId;
+		thd->height = 0;
+		thd->isStackRecorded = true;  // No need to record it until it is higher than 2.
+		thd->collision = threads[slot];
+		memset(thd->stack, 0, sizeof(SyncLocationInfo*) * syncStackSize);
+		threads[slot] = thd;
+		if ((++threadCount % 100) == 0)
+			Log::debug("* SyncHandler has found %d unique threads IDs\n", threadCount);
+		}
+
+	ASSERT(thd->collision != thd);
+	return thd;
+}
+
+SyncObjectInfo *SyncHandler::findSyncObject(const char* syncObjName)
+{
+	int slot = JString::hash(syncObjName, syncObjHashSize);
+	return findSyncObject(syncObjName, slot);
+}
+
+SyncObjectInfo *SyncHandler::findSyncObject(const char* syncObjName, int slot)
+{
+	for (SyncObjectInfo *soi = syncObjects[slot]; soi; soi = soi->collision)
+		{
+		if (soi->name == syncObjName)
+			return soi;
+		}
+
+	return NULL;
+}
+
+SyncObjectInfo *SyncHandler::addSyncObject(const char* syncObjName)
+{
+	ASSERT(syncObjName != NULL);
+	ASSERT(strlen(syncObjName) != 0);
+
+	int slot = JString::hash(syncObjName, syncObjHashSize);
+	SyncObjectInfo *soi = findSyncObject(syncObjName, slot);
+
+	if (!soi)
+		{
+		soi = new SyncObjectInfo;
+		soi->prev = NULL;
+		soi->next = NULL;
+		soi->name = syncObjName;
+		soi->collision = syncObjects[slot];
+		syncObjects[slot] = soi;
+
+		soi->multiple = false;
+		for (int n = 0; (multipleLockList[n]); n++)
+			if (soi->name == multipleLockList[n])
+				soi->multiple = true;
+
+		if ((++syncObjCount % 100) == 0)
+			Log::debug("* SyncHandler has found %d unique sync objects\n", syncObjCount);
+		}
+
+	ASSERT(soi->collision != soi);
+	
+	return soi;
+}
+
+void SyncHandler::showSyncObjects(void)
+{
+	Log::debug("\n\n== SyncHandler has found %d unique sync objects ==\n", syncObjCount);
+	Log::debug("  _____SyncObjectName_____\n", syncObjCount);
+
+	for (int slot = 0; slot < syncObjHashSize; slot++)
+		for (SyncObjectInfo *soi = syncObjects[slot]; soi; soi = soi->collision)
+			Log::debug("  %s\n", soi->name);
+}
+
+SyncLocationInfo *SyncHandler::findLocation(const char* locationName, int slot)
+{
+	for (SyncLocationInfo *loc = locations[slot]; loc; loc = loc->collision)
+		{
+		if (loc->name == locationName)
+			return loc;
+		}
+
+	return NULL;
+}
+SyncLocationInfo *SyncHandler::addLocation(const char* locationName, SyncObjectInfo *soi)
+{
+	ASSERT(locationName != NULL);
+	ASSERT(strlen(locationName) != 0);
+
+	int slot = JString::hash(locationName, locationHashSize);
+	SyncLocationInfo *loc = findLocation(locationName, slot);
+
+	if (!loc)
+		{
+		loc = new SyncLocationInfo;
+		loc->name = locationName;
+		loc->soi = soi;
+		loc->collision = locations[slot];
+		locations[slot] = loc;
+		if ((++locationCount % 100) == 0)
+			Log::debug("* SyncHandler has found %d unique locations\n",locationCount);
+		}
+
+	ASSERT(loc->soi == soi);
+	ASSERT(loc->collision != loc);
+	
+	return loc;
+}
+
+void SyncHandler::showLocations(void)
+{
+	Log::debug("\n\n== SyncHandler has found %d unique locations ==\n",locationCount);
+	Log::debug("  _____LocationName_____\t_____SyncObjectName_____\n");
+
+	for (int slot = 0; slot < locationHashSize; slot++)
+		for (SyncLocationInfo *loc = locations[slot]; loc; loc = loc->collision)
+			Log::debug("  %s\t%s\n", loc->name, loc->soi->name);
+}
+
+
+void SyncHandler::addToThread(SyncThreadInfo* thd, SyncLocationInfo *loc)
+{
+	// Be sure this soi is only recorded once.
+
+	if (loc->soi->multiple)
+		for (int n = 0; n < thd->height; n++)
+			if (thd->stack[n]->soi == loc->soi)
+				return;
+
+	// add this Sync location to the thread's stack
+	ASSERT(thd->height < syncStackSize);
+	thd->stack[thd->height++] = loc;
+
+	// Only track stacks of 2 or more
+
+	if (thd->height > 1)
+		thd->isStackRecorded =  false;
+}
+
+void SyncHandler::delFromThread(SyncThreadInfo* thd, SyncObjectInfo *soi)
+{
+	// del this Sync location from the thread's stack
+	ASSERT(thd->height > 0);
+	ASSERT(thd->stack[thd->height] == NULL);
+	ASSERT(thd->stack[thd->height - 1] != NULL);
+
+	// Before we take off this location and soi, let's record it.
+	// Do it here so that we can avoid recording sub-stacks.
+
+	if (!thd->isStackRecorded)
+		addStack(thd);
+
+	// Ususally it will be the last one
+
+	if (thd->stack[thd->height - 1]->soi == soi)
+		{
+		thd->stack[--thd->height] = NULL;
+		return;
+		}
+
+	ASSERT(thd->height > 1);
+
+	for (int z = thd->height - 2; z >= 0; z--)
+		{
+		if (thd->stack[z]->soi == soi)
+			{
+			for (int a = z; a < thd->height - 1; a++)
+				thd->stack[z] = thd->stack[z + 1];
+
+			thd->stack[--thd->height] = NULL;
+			return;
+			}
+		}
+
+	ASSERT (false);  // Did not find the soi being unlocked.
+}
+
+LocationStackInfo* SyncHandler::findStack(LocationStackInfo* lsi, int slot)
+{
+	for (LocationStackInfo* stack = locationStacks[slot]; stack; stack =
stack->collision)
+		{
+		if (stack->hash != lsi->hash)
+			continue;
+
+		if (stack->height != lsi->height)
+			continue;
+
+		for (int n = 0; n < stack->height; n++)
+			if (stack->loc[n] != lsi->loc[n])
+				break;
+
+		// The two stacks matched.
+		return stack;
+		}
+
+	return NULL;
+}
+
+void SyncHandler::addStack(SyncThreadInfo* thd)
+{
+	// Only add stacks of 2 or more
+	ASSERT(thd->height > 1);
+
+	LocationStackInfo* locationStk = new LocationStackInfo;
+	memset(locationStk, 0, sizeof(LocationStackInfo));
+	locationStk->height = thd->height;
+
+	for (int n = 0; n < thd->height; n++)
+		{
+		ASSERT(thd->stack[n]);
+		locationStk->loc[n] = thd->stack[n];
+		}
+
+	// Calulate the hash numbers.
+
+	int64 locHash = 0;
+	for (int n = 0; n < thd->height; n++)
+		locHash += (int) locationStk->loc[n];
+
+	locationStk->hash = (int) ((locHash >> 5) & 0x00000000FFFFFFFF);
+	int locSlot = locationStk->hash % stackHashSize;
+	
+	LocationStackInfo* stack = findStack(locationStk, locSlot);
+	if (!stack)
+		{
+		locationStk->collision = locationStacks[locSlot];
+		locationStacks[locSlot] = locationStk;
+		if ((++locationStackCount % 100) == 0)
+			Log::debug("* SyncHandler has found %d unique location Stacks\n", locationStackCount);
+		}
+	else
+		delete locationStk;
+
+	thd->isStackRecorded = true;
+}
+
+void SyncHandler::countLocationStacks(void)
+{
+	int stackCount = 0;
+
+	for (int slot = 0; slot < stackHashSize; slot++)
+		for (LocationStackInfo *lsi = locationStacks[slot]; lsi; lsi = lsi->collision)
+			lsi->count = ++stackCount;
+}
+
+void SyncHandler::showLocationStacks(void)
+{
+	Log::debug("\n\n== SyncHandler has found %d unique Location Stacks ==\n",
locationStackCount);
+	Log::debug("     Count; LocationStack\n");
+	int stackCount = 0;
+
+	for (int slot = 0; slot < stackHashSize; slot++)
+		for (LocationStackInfo *lsi = locationStacks[slot]; lsi; lsi = lsi->collision)
+			{
+			int stackHeight = 0;
+			stackCount++;
+			for (int n = 0; n < lsi->height - 1; n++)
+				Log::debug("  %4d-%03d; %s (%s) ->\n", 
+				           stackCount, ++stackHeight, 
+				           lsi->loc[n]->name, lsi->loc[n]->soi->name);
+
+			Log::debug("  %4d-%03d; %s (%s)\n\n", 
+			           stackCount, ++stackHeight, 
+			           lsi->loc[lsi->height - 1]->name, 
+			           lsi->loc[lsi->height - 1]->soi->name);
+			}
+}
+
+DeadlockInfo* SyncHandler::findDeadlock(DeadlockInfo* dli, int slot)
+{
+	for (DeadlockInfo* dead = possibleDeadlocks[slot]; dead; dead = dead->collision)
+		{
+		if (dead->hash == dli->hash)
+			{
+			if (   (dead->soi[0] == dli->soi[0])
+			    && (dead->soi[1] == dli->soi[1]))
+				return dead;
+
+			if (   (dead->soi[0] == dli->soi[1])
+			    && (dead->soi[1] == dli->soi[0]))
+				return dead;
+			}
+		}
+
+	return NULL;
+}
+
+// Traverse all the known sync objects, and put them in order by the order they occur in
the stacks.
+void SyncHandler::validate(void)
+{
+	possibleDeadlockCount = 0;
+	for (int n = 0; n < deadlockHashSize; ++n)
+		for (DeadlockInfo *dli; (dli = possibleDeadlocks[n]);)
+			{
+			possibleDeadlocks[n] = dli->collision;
+			delete dli;
+			}
+
+	int a,b,c,d,e;
+	for (a = 0; a < syncObjHashSize; a++)
+		for (SyncObjectInfo *soi = syncObjects[a]; soi; soi = soi->collision)
+			{
+			// Make a list of all SyncObjects that must occur before and after and this.
+
+			SyncObjectInfo *before[1000];
+			memset(before, 0, sizeof(before));
+			int beforeCount = 0;
+
+			SyncObjectInfo *after[1000];
+			memset(after, 0, sizeof(after));
+			int afterCount = 0;
+
+			// search each location stack for this soi, make a list of
+			// SyncObjects that occur before and after
+
+			for (b = 0; b < stackHashSize; b++)
+				for (LocationStackInfo *lsi = locationStacks[b]; lsi; lsi = lsi->collision)
+					{
+					for (c = 0; c < lsi->height; c++)
+						if (soi == lsi->loc[c]->soi)
+							{
+							for (d = 0; d < c; d++) 
+								{
+								for (e = 0; e < beforeCount; e++)
+									if (before[e] == lsi->loc[d]->soi)
+										break;
+
+								if (e == beforeCount)
+									before[beforeCount++] = lsi->loc[d]->soi;
+
+								ASSERT(lsi->loc[d]->soi);
+								ASSERT(beforeCount < 1000);
+								}
+							for (d = c + 1; d < lsi->height; d++)
+								{
+								for (e = 0; e < afterCount; e++)
+									if (after[e] == lsi->loc[d]->soi)
+										break;
+
+								if (e == afterCount)
+									after[afterCount++] = lsi->loc[d]->soi;
+
+								ASSERT(lsi->loc[d]->soi);
+								ASSERT(afterCount < 1000);
+								}
+							}
+					}
+
+			// Make sure none of the SyncObjects in before are also in after.
+
+			for (b = 0; b < beforeCount; b++)
+				if (soi != before[b])
+					for (c = 0; c < afterCount; c++)
+						if (before[b] == after[c])
+							addPossibleDeadlock(soi, after[c]);
+			}
+}
+
+void SyncHandler::addPossibleDeadlock(SyncObjectInfo *soi1, SyncObjectInfo *soi2)
+{
+	ASSERT(soi1 && soi2);
+	//ASSERT(soi1 != soi2);
+
+	DeadlockInfo* dli = new DeadlockInfo;
+	memset(dli, 0, sizeof(DeadlockInfo));
+
+	dli->soi[0] = soi1;
+	dli->soi[1] = soi2;
+
+	// Now calulate the hash number and slot.  
+	// This hash algorithm must return the same slot for two SyncObjectInfo *
+	// whichever is first or second.
+
+	int64 hash = (int64) soi1 + (int64) soi2;
+	dli->hash  = (int) ((hash >> 5) & 0x00000000FFFFFFFF);
+	int slot = dli->hash % deadlockHashSize;
+
+	DeadlockInfo *stack = findDeadlock(dli, slot);
+
+	if (!stack)
+		{
+		dli->collision = possibleDeadlocks[slot];
+		possibleDeadlocks[slot] = dli;
+		possibleDeadlockCount++;
+		Log::debug("  %d - Possible Deadlock;  %s and %s\n", possibleDeadlockCount,
soi1->name, soi2->name);
+		return;
+		}
+
+	delete dli;
+}
+
+#define FOUND_FIRST 1
+#define FOUND_SECOND 2
+#define FOUND_BOTH 3
+void SyncHandler::showPossibleDeadlockStacks(void)
+{
+	int a,b,c;
+	int possibleDeadlockCount = 0;
+	for (a = 0; a < deadlockHashSize; a++)
+		for (DeadlockInfo *dli = possibleDeadlocks[a]; dli; dli = dli->collision)
+			possibleDeadlockCount++;
+
+	Log::debug("\n== SyncHandler has found %d possible deadlocks ==\n",
possibleDeadlockCount);
+
+	for (a = 0; a < deadlockHashSize; a++)
+		for (DeadlockInfo *dli = possibleDeadlocks[a]; dli; dli = dli->collision)
+			{
+			int stackCount = 0;
+			Log::debug("\n=== Possible Deadlock;  %s and %s ===\n    Stacks =",
dli->soi[0]->name, dli->soi[1]->name);
+
+			// Reference all call stacks with these two SyncObjects.
+
+			for (b = 0; b < stackHashSize; b++)
+				for (LocationStackInfo *lsi = locationStacks[b]; lsi; lsi = lsi->collision)
+					{
+					// Does this location stack have both SyncObjects?
+
+					int numFound = 0;
+					for (c = 0; c < lsi->height; c++)
+						{
+						if (lsi->loc[c]->soi == dli->soi[0])
+							numFound |= FOUND_FIRST;
+						else if (lsi->loc[c]->soi == dli->soi[1])
+							numFound |= FOUND_SECOND;
+						}
+
+					if (numFound == FOUND_BOTH)
+						{
+						if (stackCount && ((stackCount % 10) == 0))
+							Log::debug("\n   ");
+						stackCount++;
+						Log::debug(" %d", lsi->count);
+						}
+					}
+			Log::debug("\n");
+			}
+}
+#endif

=== added file 'storage/falcon/SyncHandler.h'
--- a/storage/falcon/SyncHandler.h	1970-01-01 00:00:00 +0000
+++ b/storage/falcon/SyncHandler.h	2008-09-03 12:48:49 +0000
@@ -0,0 +1,135 @@
+/* Copyright (C) 2006 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef _SYNC_HANDLER_H_
+#define _SYNC_HANDLER_H_
+
+// The Falcon SyncHandler tracks the usage and call stacks of all SyncObjects.
+// It allows you to find potential deadlocks in various call stacks
+// Note: it serializes all locks and unlocks, so only use it for analysis.
+
+// Uncomment this to use the SyncHandler
+//#define USE_FALCON_SYNC_HANDLER
+
+static const int syncObjHashSize = 101;
+static const int locationHashSize = 503;
+static const int threadHashSize = 100;
+static const int stackHashSize = 1000;
+static const int deadlockHashSize = 100;
+static const int syncStackSize = 20;
+
+struct SyncObjectInfo
+{
+	JString name;
+	SyncObjectInfo *prev;
+	SyncObjectInfo *next;
+	SyncObjectInfo *collision;
+	bool multiple;
+};
+
+struct SyncLocationInfo
+{
+	JString name;
+	SyncObjectInfo *soi;
+	SyncLocationInfo *collision;
+};
+
+struct SyncThreadInfo
+{
+	int Id;
+	int height;
+	bool isStackRecorded;
+	SyncLocationInfo *stack[syncStackSize];
+	SyncThreadInfo *collision;
+};
+
+struct LocationStackInfo
+{
+	SyncLocationInfo *loc[syncStackSize];
+	int height;
+	int hash;
+	int count;
+	LocationStackInfo *collision;
+};
+
+struct DeadlockInfo
+{
+	SyncObjectInfo *soi[2];
+	int hash;
+	DeadlockInfo *collision;
+};
+
+class SyncHandler;
+extern "C" 
+{
+	SyncHandler*	getFalconSyncHandler(void);
+	SyncHandler*	findFalconSyncHandler(void);
+}
+
+class SyncHandler
+{
+public:
+	SyncHandler(void);
+	virtual ~SyncHandler(void);
+
+	void	addLock(SyncObject *syncObj, const char *locationName);
+	void	delLock(SyncObject *syncObj);
+	void	dump(void);
+
+#ifdef USE_FALCON_SYNC_HANDLER
+
+private:
+	SyncThreadInfo *	findThread();
+	SyncThreadInfo *	findThread(int thdId, int slot);
+	SyncThreadInfo *	addThread(int thdId);
+	SyncObjectInfo *	findSyncObject(const char* syncObjectName);
+	SyncObjectInfo *	findSyncObject(const char* syncObjectName, int slot);
+	SyncObjectInfo *	addSyncObject(const char* syncObjectName);
+	void				showSyncObjects(void);
+	SyncLocationInfo *	findLocation(const char* locationName, int slot);
+	SyncLocationInfo *	addLocation(const char* locationName, SyncObjectInfo *soi);
+	void				showLocations(void);
+	LocationStackInfo *	findStack(LocationStackInfo* stk, int slot);
+	void				addStack(SyncThreadInfo* thd);
+	void				showLocationStacks(void);
+	void				countLocationStacks(void);
+
+	DeadlockInfo *		findDeadlock(DeadlockInfo* dli, int slot);
+
+	void				addToThread(SyncThreadInfo *thd, SyncLocationInfo *loc);
+	void				delFromThread(SyncThreadInfo* thd, SyncObjectInfo *soi);
+
+	void				validate(void);
+	void				addPossibleDeadlock(SyncObjectInfo *soi1, SyncObjectInfo *soi2);
+	void				showPossibleDeadlockStacks(void);
+
+	SyncObject			syncObject;
+
+	SyncObjectInfo**	syncObjects;
+	SyncLocationInfo**	locations;
+	SyncThreadInfo**	threads;
+	LocationStackInfo**	locationStacks;
+	DeadlockInfo**		possibleDeadlocks;
+
+	int syncObjCount;
+	int locationCount;
+	int threadCount;
+	int locationStackCount;
+	int possibleDeadlockCount;
+#endif
+
+};
+
+#endif

=== modified file 'storage/falcon/SyncObject.cpp'
--- a/storage/falcon/SyncObject.cpp	2008-08-01 17:56:28 +0000
+++ b/storage/falcon/SyncObject.cpp	2008-09-03 12:48:49 +0000
@@ -39,6 +39,7 @@
 #include "Thread.h"
 #include "Threads.h"
 #include "Sync.h"
+#include "SyncHandler.h"
 #include "Interlock.h"
 #include "LinkedList.h"
 #include "Log.h"
@@ -142,10 +143,15 @@ void SyncObject::lock(Sync *sync, LockTy
 	Thread *thread;
 
 #ifdef TRACE_SYNC_OBJECTS
-	if (sync)
-		location = sync->location;
+	location = (sync ? sync->location : NULL);
+
+#ifdef USE_FALCON_SYNC_HANDLER
+	SyncHandler *syncHandler = getFalconSyncHandler();
+	if (sync && syncHandler)
+		syncHandler->addLock(this, location);
 #endif
-	
+#endif
+
 	// Shared case
 	
 	if (type == Shared)
@@ -309,10 +315,15 @@ void SyncObject::lock(Sync *sync, LockTy
 	Thread *thread;
 
 #ifdef TRACE_SYNC_OBJECTS
-	if (sync)
-		location = sync->location;
+	location = (sync ? sync->location : NULL);
+
+#ifdef USE_FALCON_SYNC_HANDLER
+	SyncHandler *syncHandler = getFalconSyncHandler();
+	if (sync && syncHandler)
+		syncHandler->addLock(this, location);
 #endif
-	
+#endif
+
 	if (type == Shared)
 		{
 		thread = NULL;
@@ -491,6 +502,12 @@ void SyncObject::unlock(Sync *sync, Lock
 #else // FAST_SHARED
 void SyncObject::unlock(Sync *sync, LockType type)
 {
+#if defined TRACE_SYNC_OBJECTS && defined USE_FALCON_SYNC_HANDLER
+	SyncHandler *syncHandler = findFalconSyncHandler();
+	if (sync && syncHandler)
+		syncHandler->delLock(this);
+#endif
+
 	//ASSERT(lockState != 0);
 	
 	if (monitorCount)
@@ -1060,6 +1077,22 @@ void SyncObject::setName(const char* str
 	name = string;
 #endif
 }
+const char*	SyncObject::getName(void)
+{
+#ifdef TRACE_SYNC_OBJECTS
+	return name;
+#else
+	return NULL;
+#endif
+}
+const char*	SyncObject::getLocation(void)
+{
+#ifdef TRACE_SYNC_OBJECTS
+	return location;
+#else
+	return NULL;
+#endif
+}
 
 void SyncObject::timedout(int timeout)
 {

=== modified file 'storage/falcon/SyncObject.h'
--- a/storage/falcon/SyncObject.h	2008-08-01 17:56:28 +0000
+++ b/storage/falcon/SyncObject.h	2008-09-03 12:48:49 +0000
@@ -75,6 +75,8 @@ public:
 	bool		ourExclusiveLock(void);
 	void		frequentStaller(Thread *thread, Sync *sync);
 	void		setName(const char* name);
+	const char*	getName(void);
+	const char*	getLocation(void);
 	void		timedout(int timeout);
 	void		backoff(Thread* thread);
 

Thread
bzr push into mysql-6.0-falcon branch (klewis:2808) Kevin Lewis3 Sep