List:Commits« Previous MessageNext Message »
From:Hakan Kuecuekyilmaz Date:September 25 2007 5:14am
Subject:bk commit into 6.0 tree (hakank:1.2596)
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of hakan. When hakan 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, 2007-09-25 07:14:45+02:00, hakank@stripped +32 -0
  Latest changes of Jim Starkey from 5.1-falcon tree.

  sql/CMakeLists.txt@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +2 -3
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/CMakeLists.txt@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +4 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Database.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +33 -155
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Database.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +5 -10
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Format.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +4 -2
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Format.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +2 -1
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Makefile.am@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +7 -2
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/MemFreeBlock.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +483 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/MemFreeBlock.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +0 -0

  storage/falcon/MemFreeBlock.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +51 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/MemFreeBlock.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +0 -0

  storage/falcon/MemMgr.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +92 -47
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/MemMgr.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +11 -5
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Record.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +42 -32
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Record.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +15 -16
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordGroup.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +7 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordGroup.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +8 -6
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordLeaf.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +17 -15
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordLeaf.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +1 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordScavenge.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +102 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordScavenge.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +0 -0

  storage/falcon/RecordScavenge.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +50 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordScavenge.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +0 -0

  storage/falcon/RecordSection.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +8 -6
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordVersion.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +12 -5
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/RecordVersion.h@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +1 -1
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/SRLUpdateRecords.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +2 -1
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/SerialLog.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +7 -7
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/SerialLogControl.cpp@stripped, 2007-09-25 07:14:41+02:00, hakank@stripped +5 -5
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/SerialLogWindow.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +1 -1
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Table.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +46 -8
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Table.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +4 -2
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Transaction.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +78 -10
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/Transaction.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +9 -7
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/TransactionManager.cpp@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +19 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

  storage/falcon/TransactionManager.h@stripped, 2007-09-25 07:14:42+02:00, hakank@stripped +2 -0
    Latest changes of Jim Starkey from 5.1-falcon tree.

diff -Nrup a/sql/CMakeLists.txt b/sql/CMakeLists.txt
--- a/sql/CMakeLists.txt	2007-09-20 17:41:27 +02:00
+++ b/sql/CMakeLists.txt	2007-09-25 07:14:41 +02:00
@@ -98,9 +98,8 @@ SET_TARGET_PROPERTIES(mysqld PROPERTIES 
 # Work around for 2.4.6 bug, OUTPUT_NAME will not set the right .PDB
 # file name. Note that COMPILE_FLAGS set some temporary pdb during build,
 # LINK_FLAGS sets the real one.
-SET_TARGET_PROPERTIES(mysqld PROPERTIES
-                      COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb"
-                      LINK_FLAGS  "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb")
+#                      COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb"
+#                      LINK_FLAGS  "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb")
 
 IF(EMBED_MANIFESTS)
   MYSQL_EMBED_MANIFEST("mysqld" "asInvoker")
diff -Nrup a/storage/falcon/CMakeLists.txt b/storage/falcon/CMakeLists.txt
--- a/storage/falcon/CMakeLists.txt	2007-09-20 17:41:32 +02:00
+++ b/storage/falcon/CMakeLists.txt	2007-09-25 07:14:41 +02:00
@@ -118,6 +118,7 @@ ADD_LIBRARY(ha_falcon
 		LogStream.cpp 
 		MemMgr.cpp 
 		MemControl.cpp 
+		MemFreeBlock.cpp 
 		MemoryResultSetColumn.cpp
 		MemoryResultSet.cpp 
 		MemoryResultSetMetaData.cpp
@@ -167,6 +168,7 @@ ADD_LIBRARY(ha_falcon
 		RecordLeaf.cpp 
 		RecordLocatorPage.cpp
 		RecordSection.cpp
+		RecordScavenge.cpp
 		RecordVersion.cpp 
 		RecoveryObjects.cpp
 		RecoveryPage.cpp
@@ -378,6 +380,7 @@ ADD_LIBRARY(ha_falcon
 		LogStream.h 
 		MemMgr.h 
 		MemControl.h 
+		MemFreeBlock.h 
 		MemoryManager.h
 		MemoryResultSetColumn.h
 		MemoryResultSet.h 
@@ -430,6 +433,7 @@ ADD_LIBRARY(ha_falcon
 		RecordGroup.h 
 		RecordLeaf.h 
 		RecordLocatorPage.h
+		RecordScavenge.h
 		RecordSection.h
 		RecordVersion.h 
 		RecoveryObjects.h
diff -Nrup a/storage/falcon/Database.cpp b/storage/falcon/Database.cpp
--- a/storage/falcon/Database.cpp	2007-09-20 17:41:36 +02:00
+++ b/storage/falcon/Database.cpp	2007-09-25 07:14:41 +02:00
@@ -69,7 +69,9 @@
 #include "TableSpace.h"
 #include "InfoTable.h"
 #include "MemoryManager.h"
-#include "Record.h"
+#include "MemMgr.h"
+#include "RecordScavenge.h"
+#include "LogStream.h"
 
 #ifndef STORAGE_ENGINE
 #include "Applications.h"
@@ -398,9 +400,9 @@ Database::Database(const char *dbName, C
 	memset(tablesModId, 0, sizeof (tablesModId));
 	memset(unTables, 0, sizeof (unTables));
 	memset(schemas, 0, sizeof (schemas));
-	currentAgeGroup = 1;
-	overflowSize = 0;
-	memset((void*) ageGroupSizes, 0, sizeof (ageGroupSizes));
+	currentGeneration = 1;
+	//overflowSize = 0;
+	//memset((void*) ageGroupSizes, 0, sizeof (ageGroupSizes));
 	tableList = NULL;
 	recordMemoryMax = configuration->recordMemoryMax;
 	recordScavengeFloor = configuration->recordScavengeFloor;
@@ -448,7 +450,6 @@ Database::Database(const char *dbName, C
 	zombieTables = NULL;
 	updateCardinality = NULL;
 	lastScavenge = 0;
-	lastRetireRecords = 0;
 	scavengeCycle = 0;
 	longSync = false;
 	recordDataPool = MemMgrGetFixedPool(MemMgrPoolRecordData);
@@ -1184,60 +1185,6 @@ Transaction* Database::startTransaction(
 	return transactionManager->startTransaction(connection);
 }
 
-/**
-int32 Database::insertStub(int32 recordSection, Transaction *transaction)
-{
-	int32 recordNumber = dbb->insertStub (recordSection, TRANSACTION_ID(transaction));
-	//Log::debug ("Created %d/%d\n", recordSection, recordNumber);
-
-	return recordNumber;
-}
-***/
-
-/***
-void Database::logRecord(int32 section, int32 recordNumber, Stream * stream, Transaction *transaction)
-{
-	dbb->logRecord (section, recordNumber, stream, transaction);
-}
-***/
-
-/***
-void Database::updateRecord(int32 section, int32 recordNumber, Stream *stream, Transaction *transaction)
-{
-	dbb->updateRecord (section, recordNumber, stream, TRANSACTION_ID(transaction), false);
-}
-***/
-
-/***
-void Database::updateBlob(int32 section, int32 recordNumber, Stream *stream, Transaction *transaction)
-{
-	dbb->updateBlob (section, recordNumber, stream, TRANSACTION_ID(transaction));
-	transaction->pendingPageWrites = true;
-}
-***/
-
-/***
-void Database::expungeRecord(int32 section, int32 recordNumber)
-{
-	dbb->expungeRecord (section, recordNumber);
-}
-***/
-
-/***
-int32 Database::findNextRecord(int32 sectionId, int32 recordNumber, Stream *stream)
-{
-	int32 number = dbb->findNextRecord (sectionId, recordNumber, stream);
-
-	return number;
-}
-***/
-
-/***
-bool Database::fetchRecord(int32 sectionId, int32 recordNumber, Stream * stream)
-{
-	return dbb->fetchRecord (sectionId, recordNumber, stream);
-}
-***/
 
 void Database::flush()
 {
@@ -1251,27 +1198,6 @@ void Database::commitSystemTransaction()
 	systemConnection->commit();
 }
 
-/***
-int32 Database::createIndex(Transaction *transaction)
-{
-	return dbb->createIndex(TRANSACTION_ID(transaction));
-}
-***/
-
-/***
-bool Database::addIndexEntry(int32 indexId, int indexVersion, IndexKey *key, int32 recordNumber, Transaction *transaction)
-{
-	return dbb->addIndexEntry (indexId, indexVersion, key, recordNumber, TRANSACTION_ID(transaction));
-}
-***/
-
-/***
-void Database::deleteIndex(int32 indexId, int indexVersion, Transaction *transaction)
-{
-	dbb->deleteIndex (indexId, indexVersion, TRANSACTION_ID(transaction));
-}
-***/
-
 void Database::setDebug()
 {
 	dbb->setDebug();
@@ -1684,6 +1610,7 @@ void Database::scavenge()
 
 void Database::retireRecords(bool forced)
 {
+	//transactionManager->printBlockage();
 	int cycle = scavengeCycle;
 	Sync lock(&syncScavenge, "Database::retireRecords");
 	lock.lock(Exclusive);
@@ -1696,50 +1623,36 @@ void Database::retireRecords(bool forced
 	if (forced)
 		Log::log("Forced record scavenge cycle\n");
 	
-	if (systemConnection->transaction)
+	if (!forced && systemConnection->transaction)
 		commitSystemTransaction();
 		
-	int threshold = 0;
-	int64 total = 0;
 	transactionManager->purgeTransactions();
 	TransId oldestActiveTransaction = transactionManager->findOldestActive();
-	int n;
-
-	// Compute record memory in use.  Note point we pass lower limit
-
-	for (n = 0; n < AGE_GROUPS; ++n)
-		{
-		int64 size = ageGroupSizes[n];
-		
-		if (size > 0)
-			total += size;
-			
-		if (!threshold && total > (int64)recordScavengeFloor)
-			threshold = currentAgeGroup - n;
-		}
-
-	total += overflowSize;
-	RecordScavenge recordScavenge;
-	memset(&recordScavenge, 0, sizeof(recordScavenge));
-	recordScavenge.age = threshold;
-	recordScavenge.transactionId = oldestActiveTransaction;
-
-	if (forced)
-		recordScavenge.age = MAX(threshold, currentAgeGroup - AGE_GROUPS / 2);
-		
+	int threshold = 0;
+	uint64 total = recordDataPool->activeMemory;
+	RecordScavenge recordScavenge(this, oldestActiveTransaction);
+	
 	// If we passed the upper limit, scavenge.  If we didn't pick up
 	// a significant amount of memory since the last cycle, don't bother
 	// bumping the age group.
 
-	if (forced || total > (int64)recordScavengeThreshold)
+	if (forced || total >  recordScavengeThreshold)
 		{
-		printRecordMemory (threshold, total);
-		Sync sync (&syncTables, "Database::retireRecords");
-		sync.lock (Shared);
+		LogStream stream;
+		recordDataPool->analyze(0, &stream, NULL, NULL);
+		Sync syncTbl (&syncTables, "Database::retireRecords");
+		syncTbl.lock (Shared);
+		Table *table;
+		
+		for (table = tableList; table; table = table->next)
+			table->inventoryRecords(&recordScavenge);
+		
+		threshold = recordScavenge.computeThreshold(recordScavengeFloor);
+		recordScavenge.printRecordMemory();	
 		int count = 0;
 		int skipped = 0;
 		
-		for (Table *table = tableList; table; table = table->next)
+		for (table = tableList; table; table = table->next)
 			{
 			try
 				{
@@ -1752,68 +1665,33 @@ void Database::retireRecords(bool forced
 				}
 			catch (SQLException &exception)
 				{
-				sync.unlock();
+				//syncTbl.unlock();
 				Log::debug ("Exception during scavenger of table %s.%s: %s\n",
 						table->schemaName, table->name, exception.getText());
 				}
 			}
 
-		sync.unlock();
-		int64 newTotal = overflowSize;
-		
-		for (int n = 0; n < AGE_GROUPS; ++n)
-			newTotal += ageGroupSizes [n];
-		
+		syncTbl.unlock();
 		Log::log(LogScavenge, " %d records, " I64FORMAT " bytes reclaimed\n", 
 					recordScavenge.recordsReclaimed, recordScavenge.spaceReclaimed);
 			
-		total = newTotal;
+		total = recordScavenge.spaceRemaining;
 		}
-	else if ((total - lastRecordMemory) < (int64) recordScavengeThreshold / 4)
+	else if ((total - lastRecordMemory) < recordScavengeThreshold / AGE_GROUPS)
 		{
-		recordScavenge.age = -1;
+		recordScavenge.scavengeGeneration = -1;
 		cleanupRecords (&recordScavenge);
 		
 		return;
 		}
 	else
 		{
-		recordScavenge.age = -1;
+		recordScavenge.scavengeGeneration = -1;
 		cleanupRecords (&recordScavenge);
-		printRecordMemory (threshold, total);
-		}
-
-	lastRecordMemory = total;
-	INTERLOCKED_INCREMENT (currentAgeGroup);
-	INTERLOCKED_ADD(&overflowSize, ageGroupSizes [AGE_GROUPS - 1]);
-	//overflowSize += ageGroupSizes [AGE_GROUPS - 1];
-
-	for (n = AGE_GROUPS - 1; n > 0; --n)
-		{
-		long size = ageGroupSizes [n - 1];
-		INTERLOCKED_EXCHANGE(ageGroupSizes + n, (size >= 0) ? size : 0);
 		}
-		
-	//ageGroupSizes [0] = 0;
-	INTERLOCKED_EXCHANGE(ageGroupSizes + 0, 0);
-	lastRetireRecords = timestamp;
-}
-
-void Database::printRecordMemory(int64 threshold, int64 total)
-{
-	Log::debug ("Record Memory usage for %s:\n", (const char*) name);
-	int max;
-
-	for (max = AGE_GROUPS - 1; max > 0; --max)
-		if (ageGroupSizes [max])
-			break;
-
-	for (int n = 0; n <= max; ++n)
-		if (ageGroupSizes [n])
-			Log::debug ("  %d. %d\n", currentAgeGroup - n, ageGroupSizes [n]);
 
-	Log::log(LogScavenge, " total: " I64FORMAT ", threshold " I64FORMAT "%s\n", total, threshold,
-				(total > (int64)recordScavengeThreshold) ? " -- scavenge" : "");
+	lastRecordMemory = recordDataPool->activeMemory;
+	INTERLOCKED_INCREMENT (currentGeneration);
 }
 
 void Database::ticker(void * database)
diff -Nrup a/storage/falcon/Database.h b/storage/falcon/Database.h
--- a/storage/falcon/Database.h	2007-09-20 17:41:36 +02:00
+++ b/storage/falcon/Database.h	2007-09-25 07:14:41 +02:00
@@ -35,7 +35,7 @@
 #define ODS_MINOR_VERSION2	2		// Has SequencePages external to the section tree
 #define ODS_MINOR_VERSION3	3		// Switch to variable length record numbers in index
 #define ODS_MINOR_VERSION	ODS_MINOR_VERSION3
-#define AGE_GROUPS			32
+//#define AGE_GROUPS			32
 
 #define COMBINED_VERSION(major,minor)	(major * 100 + minor)
 #define VERSION_CURRENT					COMBINED_VERSION(ODS_VERSION, ODS_MINOR_VERSION)					
@@ -93,9 +93,9 @@ class IndexKey;
 class InfoTable;
 class TableSpace;
 class MemMgr;
+class RecordScavenge;
 
 struct JavaCallback;
-struct RecordScavenge;
 
 class Database
 {
@@ -106,7 +106,6 @@ public:
 	void			shutdownNow();
 	void			dropDatabase();
 	void			rollback (Transaction *transaction);
-	//void			updateBlob(int32 section, int32 recordNumber, Stream *stream, Transaction *transaction);
 	void			commit (Transaction *transaction);
 	void			start();
 	void			deleteRepositoryBlob(const char *schema, const char *repositoryName, int volume, int64 blobId, Transaction *transaction);
@@ -119,7 +118,6 @@ public:
 	void			licenseCheck();
 	void			cleanupRecords (RecordScavenge *recordScavenge);
 	void			serverOperation (int op, Parameters *parameters);
-	void			printRecordMemory(int64 threshold, int64 tota);
 	void			retireRecords(bool forced);
 	int				getMemorySize (const char *string);
 	JString			analyze(int mask);
@@ -186,7 +184,6 @@ public:
 	void			addRef();
 	PreparedStatement* prepareStatement (const char *sqlStr);
 	void			addSystemTables();
-	//int32			createSection(Transaction *transaction);
 	Table*			addTable (User *owner, const char *name, const char *schema, TableSpace *tableSpace);
 	Table*			findTable (const char *schema, const char *name);
 	Statement*		createStatement();
@@ -267,7 +264,6 @@ public:
 	PageWriter			*pageWriter;
 	PreparedStatement	*updateCardinality;
 	MemMgr				*recordDataPool;
-	//MemMgr			*recordObjectPool;
 	
 	volatile time_t	timestamp;
 	volatile int	numberQueries;
@@ -277,16 +273,15 @@ public:
 	int				odsVersion;
 	int				noSchedule;
 
-	volatile INTERLOCK_TYPE	currentAgeGroup;
-	volatile long	overflowSize;
-	volatile long 	ageGroupSizes [AGE_GROUPS];
+	volatile INTERLOCK_TYPE	currentGeneration;
+	//volatile long	overflowSize;
+	//volatile long 	ageGroupSizes [AGE_GROUPS];
 	uint64			recordMemoryMax;
 	uint64			recordScavengeThreshold;
 	uint64			recordScavengeFloor;
 	int64			lastRecordMemory;
 	time_t			creationTime;
 	volatile time_t	lastScavenge;
-	volatile time_t	lastRetireRecords;
 };
 
 #endif // !defined(AFX_DATABASE_H__5EC961D1_A406_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/Format.cpp b/storage/falcon/Format.cpp
--- a/storage/falcon/Format.cpp	2007-09-20 17:41:42 +02:00
+++ b/storage/falcon/Format.cpp	2007-09-25 07:14:41 +02:00
@@ -38,8 +38,9 @@ static const char THIS_FILE[]=__FILE__;
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-Format::Format(Table *table, int newVersion)
+Format::Format(Table *tbl, int newVersion)
 {
+	table = tbl;
 	version = newVersion;
 	maxId = 0;
 	saved = false;
@@ -83,8 +84,9 @@ Format::Format(Table *table, int newVers
 	length = offset;
 }
 
-Format::Format(ResultSet * resultSet)
+Format::Format(Table *tbl, ResultSet * resultSet)
 {
+	table = tbl;
 	format = NULL;
 	saved = false;
 
diff -Nrup a/storage/falcon/Format.h b/storage/falcon/Format.h
--- a/storage/falcon/Format.h	2007-09-20 17:41:42 +02:00
+++ b/storage/falcon/Format.h	2007-09-25 07:14:41 +02:00
@@ -40,7 +40,7 @@ class Format  
 {
 public:
 	void save (Table *table);
-	Format (ResultSet *resultSet);
+	Format (Table *tbl, ResultSet *resultSet);
 	bool validate (Table *table);
 	Format(Table *table, int newVersion);
 	virtual ~Format();
@@ -50,6 +50,7 @@ public:
 	int32		length;
 	int			count;
 	FieldFormat	*format;
+	Table		*table;
 	Format		*hash;
 	bool		saved;
 };
diff -Nrup a/storage/falcon/Makefile.am b/storage/falcon/Makefile.am
--- a/storage/falcon/Makefile.am	2007-09-20 17:41:56 +02:00
+++ b/storage/falcon/Makefile.am	2007-09-25 07:14:41 +02:00
@@ -78,8 +78,9 @@ falcon_headers= Agent.h Alias.h Applicat
 		Log.h \
 		LogLock.h \
 		LogStream.h \
-		MemControl.h \
 		MemMgr.h \
+		MemControl.h \
+		MemFreeBlock.h \
 		MemoryManager.h \
 		MemoryResultSetColumn.h \
 		MemoryResultSet.h MemoryResultSetMetaData.h \
@@ -98,7 +99,9 @@ falcon_headers= Agent.h Alias.h Applicat
 		Protocol.h PStatement.h Queue.h QueryString.h RecordGroup.h \
 		Record.h RecordLeaf.h \
 		RecordLocatorPage.h \
-		RecordSection.h RecordVersion.h \
+		RecordSection.h \
+		RecordScavenge.h \
+		RecordVersion.h \
 		RecoveryObjects.h \
 		RecoveryPage.h \
 		Registry.h Repository.h RepositoryManager.h RepositoryVolume.h \
@@ -228,6 +231,7 @@ falcon_sources= Agent.cpp Alias.cpp \
 		LogLock.cpp \
 		LogStream.cpp \
 		MemControl.cpp \
+		MemFreeBlock.cpp \
 		MemMgr.cpp \
 		MemoryResultSetColumn.cpp \
 		MemoryResultSet.cpp MemoryResultSetMetaData.cpp \
@@ -248,6 +252,7 @@ falcon_sources= Agent.cpp Alias.cpp \
 		RecordGroup.cpp RecordLeaf.cpp \
 		RecordLocatorPage.cpp \
 		RecordSection.cpp \
+		RecordScavenge.cpp \
 		RecordVersion.cpp \
 		RecoveryObjects.cpp \
 		RecoveryPage.cpp \
diff -Nrup a/storage/falcon/MemFreeBlock.cpp b/storage/falcon/MemFreeBlock.cpp
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/storage/falcon/MemFreeBlock.cpp	2007-09-25 07:14:42 +02:00
@@ -0,0 +1,483 @@
+/* Copyright (C) 2007 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 <stdio.h>
+#include "Engine.h"
+#include "MemMgr.h"
+#include "MemFreeBlock.h"
+
+static const int TWIN	= 10;
+
+#define RESET_PARENT(newChild)		\
+	if (parent->smaller == this)		\
+		parent->smaller = newChild;	 \
+	else							\
+		parent->larger = newChild;
+
+static int lastRemove;
+
+MemFreeBlock::MemFreeBlock(void)
+{
+	larger = NULL;
+	smaller = NULL;
+	balance = 0;
+	nextTwin = priorTwin = this;
+	memHeader.length = 0;
+}
+
+MemFreeBlock::~MemFreeBlock(void)
+{
+}
+
+void MemFreeBlock::rotateLeft(void)
+{
+	MemFreeBlock *root = larger;
+	
+	if ( (larger = larger->smaller) )
+		larger->parent = this;
+
+	root->smaller = this;
+	balance -= (1 + MAX(root->balance, 0));
+	root->balance -= (1 - MIN(balance, 0));
+	RESET_PARENT(root);
+	root->parent = parent;
+	parent = root;
+}
+
+void MemFreeBlock::rotateRight(void)
+{
+	MemFreeBlock *root = smaller;
+	
+	if ( (smaller = smaller->larger) )
+		smaller->parent = this;
+		
+	root->larger = this;
+	balance += (1 - MIN(root->balance, 0));
+	root->balance += (1 + MAX(balance, 0));
+	RESET_PARENT(root);
+	root->parent = parent;
+	parent = root;
+}
+
+void MemFreeBlock::insert(MemFreeBlock *newNode)
+{
+	newNode->larger = NULL;
+	newNode->smaller = NULL;
+	newNode->balance = 0;
+	MemFreeBlock *node = this;
+	
+	// Find insertion point and insert new node as leaf
+	
+	while (node)
+		if (newNode->memHeader.length < node->memHeader.length)
+			{
+			if (node->smaller)
+				node = node->smaller;
+			else
+				{
+				node->smaller = newNode;
+				--node->balance;
+				break;
+				}
+			}
+		else if (newNode->memHeader.length > node->memHeader.length)
+			{
+			if (node->larger)
+				node = node->larger;
+			else
+				{
+				node->larger = newNode;
+				++node->balance;
+				break;
+				}
+			}
+		else
+			{
+			newNode->balance = TWIN;
+			newNode->nextTwin = node->nextTwin;
+			newNode->nextTwin->priorTwin = newNode;
+			newNode->priorTwin = node;
+			node->nextTwin = newNode;
+			//node->nextLarger = NULL;
+			
+			return;
+			}
+	
+	// New node is inserted.  Balance tree upwards
+	
+	newNode->parent = node;
+	newNode->nextTwin = newNode->priorTwin = newNode;
+
+	for (MemFreeBlock *nodeParent; node->balance && (nodeParent = node->parent) && nodeParent->parent; node = nodeParent)
+		{
+		if (nodeParent->smaller == node)
+			{
+			if (--nodeParent->balance < -1)
+				{
+				nodeParent->rebalance();
+				break;
+				}
+			}
+		else
+			{
+			if (++nodeParent->balance > +1)
+				{
+				nodeParent->rebalance();
+				break;
+				}
+			}
+		}
+}
+
+MemFreeBlock* MemFreeBlock::findNextLargest(int size)
+{
+	ASSERT(size > 0);
+	MemFreeBlock *block = this;
+	
+	// Travse down the tree looking for a block that fits
+	
+	while (block)
+		if (size < block->memHeader.length)
+			{
+			if (block->smaller)
+				block = block->smaller;
+			else
+				break;
+			}
+		else if (size > block->memHeader.length)
+			{
+			if (block->larger)
+				block = block->larger;
+			else
+				break;
+			}
+		else
+			break;
+			
+	for (; block; block = block->parent)
+		if (size <= block->memHeader.length)
+			{
+			if (block->nextTwin == block)
+				{
+				block->remove();
+				
+				return block;
+				}
+				
+			// We've got a twin of the same size.  Take it out of the twin list.
+			
+			MemFreeBlock *twin = block->nextTwin;
+			twin->nextTwin->priorTwin = twin->priorTwin;
+			twin->priorTwin->nextTwin = twin->nextTwin;
+			
+			return twin;
+			}
+			
+	return NULL;
+}
+
+void MemFreeBlock::remove()
+{
+	// If we a simple twin, zip out of the twin list and we're done
+	
+	if (balance == TWIN)
+		{
+		nextTwin->priorTwin = priorTwin;
+		priorTwin->nextTwin = nextTwin;
+		lastRemove = 1;
+		
+		return;
+		}
+		
+	// If we have a twin, promote the first twin into the tree
+	
+	if (nextTwin != this)
+		{
+		MemFreeBlock *twin = nextTwin;
+		priorTwin->nextTwin = twin;
+		twin->priorTwin = priorTwin;
+		
+		twin->balance = balance;
+		twin->parent = parent;
+		
+		if ( (twin->smaller = smaller) )
+			smaller->parent = twin;
+			
+		if ( (twin->larger = larger) )
+			larger->parent = twin;
+	
+		RESET_PARENT(twin);
+		parent->validate();
+		//validateFreeList();
+		lastRemove = 2;
+		
+		return;
+		}
+		
+	// There are three cases a) No children, b) One child, c) Two children
+
+	if (!smaller || !larger)
+		{
+		MemFreeBlock *next = (smaller) ? smaller : larger;
+		
+		if (next)
+			next->parent = parent;
+		
+		if (parent->smaller == this)
+			{
+			parent->smaller = next;
+			parent->rebalanceUpward(+1);
+			}
+		else
+			{
+			parent->larger = next;
+			parent->rebalanceUpward(-1);
+			}	
+
+		lastRemove = 3;
+		
+		return;	
+		}
+
+	// We're an equality with two children.  Bummer.  Find successor node (next larger value)
+	// and swap it into our place
+	
+	bool shallower;
+	MemFreeBlock *node = larger->getSuccessor(&larger, &shallower);
+	
+	if ( (node->smaller = smaller) )
+		smaller->parent = node;
+		
+	if ( (node->larger = larger) )
+		larger->parent = node;
+		
+	node->balance = balance;
+	node->parent = parent;
+	RESET_PARENT(node);
+	lastRemove = 4;
+	
+	// If we got shallower, adjust balance and rebalance if necessary
+
+	if (shallower)
+		{
+		lastRemove = 5;
+		node->rebalanceUpward(-1);
+		}
+}
+
+void MemFreeBlock::rebalance(void)
+{
+	if (balance > 1)
+		{
+		if (larger->balance < 0)
+			larger->rotateRight();
+					
+		rotateLeft();
+		}
+	else if (balance < 1)
+		{
+		if (smaller->balance > 0)
+			smaller->rotateLeft();
+			
+		rotateRight();
+		}
+}
+
+bool MemFreeBlock::rebalanceDelete()
+{
+	if (balance > 1)
+		{
+		if (larger->balance < 0)
+			{
+			larger->rotateRight();
+			rotateLeft();
+			
+			return true;
+			}
+					
+		rotateLeft();
+		
+		return parent->balance == 0;
+		}
+		
+	if (balance < 1)
+		{
+		if (smaller->balance > 0)
+			{
+			smaller->rotateLeft();
+			rotateRight();
+			
+			return true;
+			}
+			
+		rotateRight();
+		
+		return parent->balance == 0;
+		}
+	
+	return false;
+}
+
+MemFreeBlock* MemFreeBlock::getSuccessor(MemFreeBlock** parentPointer, bool* shallower)
+{
+	// If there's a smaller node, recurse down it rebalancing
+	// if the subtree gets shallower
+	
+	if (smaller)
+		{
+		int was = balance;
+		MemFreeBlock *node = smaller->getSuccessor(&smaller, shallower);
+
+		// If we got shallower, adjust balance and rebalance if necessary
+
+		if (*shallower)
+			{
+			if (++balance > 1)
+				*shallower = rebalanceDelete();
+			else if (!was && (*parentPointer)->balance)
+				*shallower = false;
+			}
+			
+		return node;
+		}
+	
+	// We're the bottom.  Remove us from our parent and we're done.
+	
+	RESET_PARENT(larger);
+	
+	if (larger)
+		larger->parent = parent;
+		
+	*shallower = true;
+
+	return this;
+}
+
+void MemFreeBlock::rebalanceUpward(int delta)
+{
+	MemFreeBlock *node = this;
+	
+	for (;;)
+		{
+		MemFreeBlock *nodeParent = node->parent;
+		
+		if (!nodeParent)
+			{
+			node->balance += delta;
+			
+			return;
+			}
+
+		int parentDelta = (nodeParent->smaller == node) ? 1 : -1;
+		node->balance += delta;
+		
+		if (node->balance == delta)
+			break;
+		
+		if (node->balance > 1 || node->balance < -1)
+			if (!node->rebalanceDelete())
+				break;
+		
+		delta = parentDelta;			
+		node = nodeParent;
+		}
+}
+
+MemFreeBlock* MemFreeBlock::getFirst(void)
+{
+	MemFreeBlock *node = larger;
+	
+	if (!node)
+		return node;
+	
+	while (node->smaller)
+		node = node->smaller;
+	
+	return node;	
+}
+
+MemFreeBlock* MemFreeBlock::getNext(void)
+{
+	MemFreeBlock *node = larger;
+	
+	if (node)
+		{
+		while (node->smaller)
+			node = node->smaller;
+		
+		return node;
+		}
+
+	for (node = this; node && node->parent; node = node->parent)
+		if (node == parent->smaller)
+			return parent;
+	
+	return NULL;
+}
+
+int MemFreeBlock::validate(void)
+{
+	int rightDepth = 0;
+	int leftDepth = 0;
+	
+	if (smaller)
+		{
+		if (smaller->memHeader.length >= memHeader.length)
+			corrupt("out of order");
+			
+		if (smaller->parent != this)
+			corrupt("bad parent");
+		
+		leftDepth = smaller->validate();
+		}
+	
+	if (larger)
+		{
+		if (larger->memHeader.length < memHeader.length)
+			corrupt("out of order");
+			
+		if (larger->parent != this)
+			corrupt("bad right parent");
+		
+		rightDepth = larger->validate();
+		}
+	
+	if (parent && balance != rightDepth - leftDepth)
+		corrupt("bad balance");
+		
+	return MAX(rightDepth, leftDepth) + 1;
+}
+
+void MemFreeBlock::corrupt(const char *text)
+{
+	ASSERT(false);
+}
+
+int MemFreeBlock::count(void)
+{
+	int count = 1;
+	
+	for (MemFreeBlock *block = nextTwin; block != this; block = block->nextTwin)
+		++count;
+		
+	if (smaller)
+		count += smaller->count();
+	
+	if (larger)
+		count += larger->count();
+		
+	return count;
+}
diff -Nrup a/storage/falcon/MemFreeBlock.h b/storage/falcon/MemFreeBlock.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/storage/falcon/MemFreeBlock.h	2007-09-25 07:14:42 +02:00
@@ -0,0 +1,51 @@
+/* Copyright (C) 2007 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 _MEM_FREE_BLOCK_H_
+#define _MEM_FREE_BLOCK_H_
+
+class MemFreeBlock :
+	public MemBigObject
+{
+public:
+	MemFreeBlock(void);
+	~MemFreeBlock(void);
+
+	MemFreeBlock	*smaller;
+	MemFreeBlock	*larger;
+	MemFreeBlock	*parent;
+	MemFreeBlock	*nextTwin;
+	MemFreeBlock	*priorTwin;
+	
+	int				balance;
+	
+	void			rotateLeft(void);
+	void			rotateRight(void);
+	void			insert(MemFreeBlock *node);
+	MemFreeBlock*	findNextLargest(int size);
+	void			rebalance(void);
+	bool			rebalanceDelete();
+	MemFreeBlock*	getSuccessor(MemFreeBlock** parentPointer, bool* shallower);
+	void			remove();
+	void			rebalanceUpward(int delta);
+	MemFreeBlock*	getFirst(void);
+	MemFreeBlock*	getNext(void);
+	int				validate(void);
+	void			corrupt(const char *text);
+	int				count(void);
+};
+
+#endif
diff -Nrup a/storage/falcon/MemMgr.cpp b/storage/falcon/MemMgr.cpp
--- a/storage/falcon/MemMgr.cpp	2007-09-24 12:56:42 +02:00
+++ b/storage/falcon/MemMgr.cpp	2007-09-25 07:14:41 +02:00
@@ -207,8 +207,6 @@ void MemMgrAnalyze(int mask, Stream *str
 	memoryManager.analyze (mask, stream, NULL, NULL);
 	stream->putSegment ("Records\n");
 	recordManager.analyze (mask, stream, NULL, NULL);
-	stream->putSegment ("Record Objects\n");
-	recordManager.analyze (mask, stream, NULL, NULL);
 	//LEAVE_CRITICAL_SECTION;
 	}
 
@@ -285,6 +283,7 @@ MemMgr::MemMgr(int rounding, int cutoff,
 	currentMemory		= 0;
 	blocksAllocated		= 0;
 	blocksActive		= 0;
+	activeMemory		= 0;
 	numberBigHunks		= 0;
 	numberSmallHunks	= 0;
 	bigHunks			= NULL;
@@ -296,8 +295,9 @@ MemMgr::MemMgr(int rounding, int cutoff,
 
 	freeObjects = (MemBlock**) allocRaw (l);
 	memset (freeObjects, 0, l);
-	freeBlocks.nextLarger = freeBlocks.priorSmaller = &freeBlocks;
-	junk.nextLarger = junk.priorSmaller = &junk;
+	//freeBlocks.nextLarger = freeBlocks.priorSmaller = &freeBlocks;
+	//freeBlockTree = NULL;
+	junk.larger = junk.smaller = &junk;
 }
 
 
@@ -402,50 +402,54 @@ MemBlock* MemMgr::alloc(int length)
 	 */
 	
 	
-	//Sync sync (&mutex, "MemMgr::alloc");
-	//sync.lock(Exclusive);
-	MemFreeBlock *freeBlock;
 
 	if (length < (int) (OFFSET(MemBlock*, body) + sizeof (MemFreeBlock) - sizeof (MemBigObject)))
 		length = (int) (OFFSET(MemBlock*, body) + sizeof (MemFreeBlock) - sizeof (MemBigObject));	
 	
-	for (freeBlock = freeBlocks.nextLarger; freeBlock != &freeBlocks; freeBlock = freeBlock->nextLarger)
-		if (freeBlock->memHeader.length >= length)
-			{
-			remove (freeBlock);
-			MemBlock *block = (MemBlock*) &freeBlock->memHeader;
-			
-			// Compute length (MemHeader + body) for new free block
-			
-			int tail = block->length - length;
-			
-			// If there isn't room to split off a new free block, allocate the whole thing
-			
-			if (tail < (int) sizeof (MemFreeBlock))
-				{
-				block->pool = this;
-				return block;
-				}
-			
-			// Otherwise, chop up the block
+	MemFreeBlock *freeBlock = freeBlockTree.findNextLargest(length);
+	
+	if (!freeBlock && freeBlockTree.larger)
+		freeBlock = freeBlockTree.findNextLargest(length);	
 			
-			MemBigObject *newBlock = freeBlock;
-			freeBlock = (MemFreeBlock*) ((UCHAR*) block + length);
-			freeBlock->memHeader.length = tail - sizeof (MemBigHeader); 
-			block->length = length;
+	if (freeBlock)
+		{
+		//freeBlockTree.validate();
+		MemBlock *block = (MemBlock*) &freeBlock->memHeader;
+		
+		// Compute length (MemHeader + body) for new free block
+		
+		int tail = block->length - length;
+		
+		// If there isn't room to split off a new free block, allocate the whole thing
+		
+		if (tail < (int) sizeof (MemFreeBlock))
+			{
 			block->pool = this;
-			
-			if ( (freeBlock->next = newBlock->next) )
-				freeBlock->next->prior = freeBlock;
-			
-			newBlock->next = freeBlock;
-			freeBlock->prior = newBlock;
-			freeBlock->memHeader.pool = NULL;		// indicate block is free
-			insert (freeBlock);
-			//validateFreeList();
+			activeMemory += block->length;
 			
 			return block;
 			}
+		
+		// Otherwise, chop up the block
+		
+		MemBigObject *newBlock = freeBlock;
+		freeBlock = (MemFreeBlock*) ((UCHAR*) block + length);
+		freeBlock->memHeader.length = tail - sizeof (MemBigHeader); 
+		block->length = length;
+		block->pool = this;
+		activeMemory += length;
+		
+		if ( (freeBlock->next = newBlock->next) )
+			freeBlock->next->prior = freeBlock;
+		
+		newBlock->next = freeBlock;
+		freeBlock->prior = newBlock;
+		freeBlock->memHeader.pool = NULL;		// indicate block is free
+		insert (freeBlock);
+		//validateFreeList();
+		
+		return block;
+		}
 
 			 
 	// Didn't find existing space -- allocate new hunk
@@ -478,6 +482,7 @@ MemBlock* MemMgr::alloc(int length)
 	MemBlock *block = (MemBlock*) &newBlock->memHeader;
 	block->pool = this;
 	block->length = length;
+	activeMemory += length;
 	
 	// If there is space left over, create a free block
 	
@@ -631,6 +636,8 @@ void MemMgr::releaseBlock(MemBlock *bloc
 	sync.lock(Exclusive);
 	//validateFreeList();
 	block->pool = NULL;
+	ASSERT(length <= activeMemory);
+	activeMemory -= length;
 	
 	if (freeBlock->next && !freeBlock->next->memHeader.pool)
 		{
@@ -697,6 +704,20 @@ void* MemMgr::memoryIsExhausted(void)
 
 void MemMgr::remove(MemFreeBlock* block)
 {
+	//freeBlockTree.validate();
+	//int count = freeBlockTree.count();
+	
+	block->remove();
+	
+	/***
+	freeBlockTree.validate();
+	int count2 = freeBlockTree.count();
+	
+	if (count - 1 != count2)
+		corrupt("bad count");
+	***/
+	
+	/***
 	// If this is junk, chop it out and be done with it
 	
 	if (block->memHeader.length < threshold)
@@ -709,6 +730,7 @@ void MemMgr::remove(MemFreeBlock* block)
 		block->nextTwin->priorTwin = block->priorTwin;
 		block->priorTwin->nextTwin = block->nextTwin;
 		//validateFreeList();
+		
 		return;
 		}
 	
@@ -725,6 +747,7 @@ void MemMgr::remove(MemFreeBlock* block)
 		twin->priorSmaller->nextLarger = twin;
 		twin->nextLarger->priorSmaller = twin;
 		//validateFreeList();
+		
 		return;
 		}
 	
@@ -733,10 +756,25 @@ void MemMgr::remove(MemFreeBlock* block)
 	block->priorSmaller->nextLarger = block->nextLarger;
 	block->nextLarger->priorSmaller = block->priorSmaller;
 	//validateFreeList();
+	***/
 }
 
 void MemMgr::insert(MemFreeBlock* freeBlock)
 {
+	//freeBlockTree.validate();
+	//int count = freeBlockTree.count();
+	
+	freeBlockTree.insert(freeBlock);
+	
+	/***
+	freeBlockTree.validate();
+	int count2 = freeBlockTree.count();
+	
+	if (count + 1 != count2)
+		corrupt("bad count");
+	***/
+	
+	/***
 	// If this is junk (too small for pool), stick it in junk
 	
 	if (freeBlock->memHeader.length < threshold)
@@ -770,6 +808,7 @@ void MemMgr::insert(MemFreeBlock* freeBl
 	
 	freeBlock->nextTwin = freeBlock->priorTwin = freeBlock;
 	//validateFreeList();
+	***/
 }
 
 void* MemMgr::allocRaw(int length)
@@ -796,37 +835,40 @@ void MemMgr::validateFreeList(void)
 	int len = 0;
 	int count = 0;
 	MemFreeBlock *block;
-	MemFreeBlock *prior = &freeBlocks;
 	
-	for (block = freeBlocks.nextLarger; block != &freeBlocks; prior = block, block = block->nextLarger)
+	for (block = freeBlockTree.getFirst(); block; block = block->getNext())
 		{
 		if (block->memHeader.length <= len)
 			corrupt ("bad free list\n");
-		if (block->priorSmaller != prior)
-			corrupt ("bad prior pointer");
+			
 		len = block->memHeader.length;
 		++count;
 		int twins = 0;
 		MemFreeBlock *twin;
 		MemFreeBlock *priorTwin = block;
+		
 		for (twin = block->nextTwin; twin != block; priorTwin = twin, twin = twin->nextTwin)
 			{
 			if (twin->priorTwin != priorTwin)
 				corrupt("bad priorTwin pointer");
+				
 			++twins;
 			}
+			
 		for (twin = block->priorTwin; twin != block; twin = twin->priorTwin)
 			--twins;
+			
 		if (twins)
 			corrupt("bad twin list");
 		}
 	
 	len += 1;
 	
-	for (block = freeBlocks.priorSmaller; block != &freeBlocks; block = block->priorSmaller)
+	for (block = freeBlockTree.getFirst(); block; block = block->getNext())
 		{
 		if (block->memHeader.length >= len)
 			corrupt ("bad free list\n");
+			
 		len = block->memHeader.length;
 		}
 
@@ -1048,8 +1090,9 @@ void MemMgr::analyze(int mask, Stream *s
 		int batch = 0;
 		int64 orderedSpace = 0;
 		int sizes = 0;
-
-		for (MemFreeBlock *blk = freeBlocks.nextLarger; blk != &freeBlocks; blk = blk->nextLarger)
+		
+		//for (MemFreeBlock *blk = freeBlocks.nextLarger; blk != &freeBlocks; blk = blk->nextLarger)
+		for (MemFreeBlock *blk = freeBlockTree.getFirst(); blk; blk = blk->getNext())
 			{
 			++sizes;
 			int count = 1;
@@ -1087,7 +1130,9 @@ void MemMgr::analyze(int mask, Stream *s
 		{
 		int sizes = 0;
 
-		for (MemFreeBlock *blk = freeBlocks.nextLarger; blk != &freeBlocks; blk = blk->nextLarger)
+		
+		for (MemFreeBlock *blk = freeBlockTree.getFirst(); blk; blk = blk->getNext())
+		//for (MemFreeBlock *blk = freeBlocks.nextLarger; blk != &freeBlocks; blk = blk->nextLarger)
 			{
 			++sizes;
 			int count = 1;
diff -Nrup a/storage/falcon/MemMgr.h b/storage/falcon/MemMgr.h
--- a/storage/falcon/MemMgr.h	2007-09-20 17:41:59 +02:00
+++ b/storage/falcon/MemMgr.h	2007-09-25 07:14:41 +02:00
@@ -71,16 +71,20 @@ public:
 	MemHeader		memHeader;
 };
 
-
+/***
 class MemFreeBlock : public MemBigObject 
 {
 public:
-	MemFreeBlock	*nextLarger;
-	MemFreeBlock	*priorSmaller;
+	//MemFreeBlock	*nextLarger;
+	//MemFreeBlock	*priorSmaller;
+	MemFreeBlock	*smaller;
+	MemFreeBlock	*larger;
 	MemFreeBlock	*nextTwin;
 	MemFreeBlock	*priorTwin;
+	int				balance;
 };
-
+***/
+#include "MemFreeBlock.h"
 
 class MemSmallHunk 
 {
@@ -117,10 +121,12 @@ public:
 	MemBigHunk		*bigHunks;
 	MemSmallHunk	*smallHunks;
 	MemControl		*memControl;
-	MemFreeBlock	freeBlocks;
+	//MemFreeBlock	freeBlocks;
+	MemFreeBlock	freeBlockTree;
 	MemFreeBlock	junk;
 	Mutex			mutex;		// Win32 critical regions are faster than SyncObject
 	int64			currentMemory;
+	uint64			activeMemory;
 	int				blocksAllocated;
 	int				blocksActive;
 
diff -Nrup a/storage/falcon/Record.cpp b/storage/falcon/Record.cpp
--- a/storage/falcon/Record.cpp	2007-09-20 17:42:11 +02:00
+++ b/storage/falcon/Record.cpp	2007-09-25 07:14:41 +02:00
@@ -59,15 +59,17 @@ static int offsetVectorSize;
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-Record::Record(Table *tbl, int32 recordNum, Stream *stream)
+Record::Record(Table *table, int32 recordNum, Stream *stream)
 {
-	ASSERT (tbl);
+	//ASSERT (tbl);
 	useCount = 1;
-	table = tbl;
+	//table = tbl;
+	format = table->getCurrentFormat();
 	state = recData;
 	recordNumber = recordNum;
 	const short *p = (short*) stream->segments->address;
 	size = sizeof (*this);
+	generation = table->database->currentGeneration;
 #ifdef CHECK_RECORD_ACTIVITY
 	active = false;
 #endif
@@ -78,8 +80,8 @@ Record::Record(Table *tbl, int32 recordN
 		data.record = stream->decompress(table->tableId, recordNumber);
 		format = table->getFormat (*(short*) data.record);
 		size += format->length;
-		setAgeGroup();
-
+		//setAgeGroup();
+		
 		if (stream->decompressedLength != format->length)
 			throw SQLEXCEPTION (RUNTIME_ERROR,
 					"wrong length record (got %d, expected %d), table %s.%s, section %d, record %d",
@@ -104,12 +106,15 @@ Record::Record(Table * tbl, Format *fmt)
 {
 	ASSERT (tbl);
 	useCount = 1;
-	format = fmt;
-	table = tbl;
+	
+	if ( !(format = fmt) )
+		format = tbl->getCurrentFormat();
+		
+	//table = tbl;
 	size = sizeof (RecordVersion);
 	encoding = noEncoding;
 	state = recData;
-	ageGroup = table->database->currentAgeGroup;	// to avoid a Valgrind warning
+	generation = format->table->database->currentGeneration;
 	
 #ifdef CHECK_RECORD_ACTIVITY
 	active = false;
@@ -130,10 +135,11 @@ Record::~Record()
 #ifdef CHECK_RECORD_ACTIVITY
 	ASSERT(!active);
 #endif
-	
+	/***
 	if (table)
 		unsetAgeGroup();
-
+	***/
+	
 	deleteData();
 }
 
@@ -205,7 +211,7 @@ void Record::setValue(Transaction * tran
 
 		case Asciiblob:
 		case Binaryblob:
-			*(int32*) ptr = table->getBlobId (value, *(int32*) ptr, cloneFlag, transaction);
+			*(int32*) ptr = format->table->getBlobId (value, *(int32*) ptr, cloneFlag, transaction);
 			break;
 
 		case Date:
@@ -282,7 +288,7 @@ Record* Record::fetchVersion(Transaction
 
 void Record::getValue(int fieldId, Value * value)
 {
-	ASSERT (table);
+	//ASSERT (table);
 	ASSERT (format);
 	value->clear();
 
@@ -312,7 +318,7 @@ void Record::getValue(int fieldId, Value
 				{
 				case Asciiblob:
 					{
-					AsciiBlob *blob = table->getAsciiBlob(value->getBlobId());
+					AsciiBlob *blob = format->table->getAsciiBlob(value->getBlobId());
 					value->setValue (blob);
 					blob->release();
 					}
@@ -320,7 +326,7 @@ void Record::getValue(int fieldId, Value
 
 				case Binaryblob:
 					{
-					BinaryBlob *blob = table->getBinaryBlob(value->getBlobId());
+					BinaryBlob *blob = format->table->getBinaryBlob(value->getBlobId());
 					value->setValue (blob);
 					blob->release();
 					}
@@ -433,7 +439,7 @@ void Record::getValue(int fieldId, Value
 
 		case Asciiblob:
 			{
-			AsciiBlob *blob = table->getAsciiBlob (*(int32*) ptr);
+			AsciiBlob *blob = format->table->getAsciiBlob (*(int32*) ptr);
 			value->setValue (blob);
 			blob->release();
 			}
@@ -441,7 +447,7 @@ void Record::getValue(int fieldId, Value
 
 		case Binaryblob:
 			{
-			BinaryBlob *blob = table->getBinaryBlob (*(int32*) ptr);
+			BinaryBlob *blob = format->table->getBinaryBlob (*(int32*) ptr);
 			value->setValue (blob);
 			blob->release();
 			}
@@ -641,7 +647,7 @@ void Record::finalize(Transaction *trans
 {
 	ASSERT(encoding == valueVector);
 	Stream stream;
-	EncodedRecord encodedStream(table, transaction, &stream);
+	EncodedRecord encodedStream(format->table, transaction, &stream);
 	short version = (short) - format->version;
 	stream.putSegment(sizeof(version), (char*) &version, true);
 	Value *values = (Value*) data.record;
@@ -677,7 +683,6 @@ int Record::setEncodedRecord(Stream *str
 	encoding = shortVector;
 	int vectorLength = format->count * sizeof(short);
 	int totalLength = vectorLength + stream->totalLength;
-	//char *dataBuffer = ALLOCATE_RECORD(totalLength);
 	char *dataBuffer = allocRecordData(totalLength);
 	memset(dataBuffer, 0, vectorLength);
 	stream->getSegment(0, stream->totalLength, dataBuffer + vectorLength);
@@ -685,7 +690,8 @@ int Record::setEncodedRecord(Stream *str
 	
 	highWater = 0;
 	size +=  vectorLength + stream->totalLength;
-	setAgeGroup();
+	//setAgeGroup();
+	generation = format->table->database->currentGeneration;
 
 	if (interlocked)
 		{
@@ -798,21 +804,21 @@ bool Record::isNull(int fieldId)
 
 // Set age group and add size to database
 
+/***
 void Record::setAgeGroup()
 {
 	Database *database = table->database;
-	ageGroup = database->currentAgeGroup;
+	generation = database->currentGeneration;
 	//database->ageGroupSizes [0] += size;
 	INTERLOCKED_ADD(database->ageGroupSizes + 0, size);
 }
 
-
 void Record::unsetAgeGroup(void)
 {
 	if (table)
 		{
 		Database *database = table->database;
-		int n = database->currentAgeGroup - ageGroup;
+		int n = database->currentGeneration - generation;
 		
 		if (n >= AGE_GROUPS)
 			INTERLOCKED_ADD(&database->overflowSize, -size);
@@ -821,18 +827,25 @@ void Record::unsetAgeGroup(void)
 		}
 
 }
+***/
 
 void Record::poke()
 {
+	int gen = format->table->database->currentGeneration;
+	
+	if (generation != gen)
+		generation = gen;
+	
+	/***
 	Database *database = table->database;
-	int32 currentAgeGroup = database->currentAgeGroup;
-	int32 n = currentAgeGroup - ageGroup;
+	int32 currentGeneration = database->currentGeneration;
+	int32 n = currentGeneration - generation;
 
 	if (n == 0)
 		return;
 
 	ASSERT (n > 0);
-	ageGroup = currentAgeGroup;
+	generation = currentGeneration;
 
 	if (n >= AGE_GROUPS)
 		INTERLOCKED_ADD(&database->overflowSize, -size);
@@ -840,6 +853,7 @@ void Record::poke()
 		INTERLOCKED_ADD(database->ageGroupSizes + n, -size);
 
 	INTERLOCKED_ADD(database->ageGroupSizes + 0, size);
+	***/
 }
 
 Record* Record::releaseNonRecursive(void)
@@ -885,10 +899,6 @@ int Record::setRecordData(const UCHAR * 
 	return (totalLength);
 }
 
-char* Record::getRecordData()
-{
-	return data.record;
-}
 
 void Record::deleteData(void)
 {
@@ -911,7 +921,7 @@ void Record::deleteData(void)
 void Record::print(void)
 {
 	printf("  %p\tId %d, enc %d, state %d, use %d, grp %d\n",
-			this, recordNumber, encoding, state, useCount, ageGroup);
+			this, recordNumber, encoding, state, useCount, generation);
 }
 
 void Record::printRecord(const char* header)
@@ -930,14 +940,14 @@ char* Record::allocRecordData(int length
 	for (int n = 0;; ++n)
 		try
 			{
-			return POOL_NEW(table->database->recordDataPool) char[length];
+			return POOL_NEW(format->table->database->recordDataPool) char[length];
 			}
 		catch (SQLException& exception)
 			{
 			if (n > 2 || exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR)
 				throw;
 			
-			table->database->forceRecordScavenge();
+			format->table->database->forceRecordScavenge();
 			}
 	
 	return NULL;
diff -Nrup a/storage/falcon/Record.h b/storage/falcon/Record.h
--- a/storage/falcon/Record.h	2007-09-20 17:42:11 +02:00
+++ b/storage/falcon/Record.h	2007-09-25 07:14:41 +02:00
@@ -29,17 +29,6 @@
 
 #define CHECK_RECORD_ACTIVITY
 
-struct RecordScavenge
-	{
-	TransId	transactionId;
-	int		age;
-	uint	recordsReclaimed;
-	uint	recordsRemaining;
-	uint	versionsRemaining;
-	uint64	spaceReclaimed;
-	uint64	spaceRemaining;
-	};
-	
 enum RecordEncoding {
 	noEncoding = 0,
 	traditional,
@@ -64,6 +53,7 @@ class Transaction;
 class Value;
 class Stream;
 class Database;
+class RecordScavenge;
 CLASS(Field);
 
 extern char	*RecordAllocate (int size, const char *file, int line);
@@ -89,7 +79,7 @@ public:
 	virtual int		thaw();
 	virtual const char*	getEncodedRecord();
 	virtual int		setRecordData(const UCHAR *dataIn, int dataLength);
-	virtual char*	getRecordData();
+	//virtual char*	getRecordData();
 	
 	const UCHAR*	getEncoding (int index);
 	int				setEncodedRecord(Stream *stream, bool interlocked);
@@ -104,11 +94,13 @@ public:
 	void			getEncodedValue (int fieldId, Value *value);
 	void			getRecord (Stream *stream);
 	int				getEncodedSize();
-	void			setAgeGroup();
 	void			deleteData(void);
 	void			printRecord(const char* header);
 	void			validateData(void);
 	char*			allocRecordData(int length);
+	
+	//void			setAgeGroup();
+	//void			unsetAgeGroup(void);
 
 	Record (Table *table, Format *recordFormat);
 	Record(Table *table, int32 recordNumber, Stream *stream);
@@ -117,6 +109,14 @@ public:
 		{
 		return data.record != NULL;
 		};
+
+	inline char* getRecordData()
+	{
+		if (state == recChilled)
+			thaw();
+		
+		return data.record;
+	}
 		
 protected:
 	virtual ~Record();
@@ -128,11 +128,11 @@ protected:
 
 public:
 	volatile INTERLOCK_TYPE useCount;
-	Table		*table;
+	//Table		*table;
 	Format		*format;
 	int			recordNumber;
 	int			size;
-	int			ageGroup;
+	int			generation;
 	short		highWater;
 	UCHAR		encoding;
 	UCHAR		state;
@@ -140,7 +140,6 @@ public:
 #ifdef CHECK_RECORD_ACTIVITY
 	UCHAR		active;					// this is for debugging only
 #endif
-	void unsetAgeGroup(void);
 };
 
 #endif // !defined(AFX_RECORD_H__02AD6A50_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/RecordGroup.cpp b/storage/falcon/RecordGroup.cpp
--- a/storage/falcon/RecordGroup.cpp	2007-09-20 17:42:11 +02:00
+++ b/storage/falcon/RecordGroup.cpp	2007-09-25 07:14:41 +02:00
@@ -184,3 +184,10 @@ bool RecordGroup::retireSections(Table *
 		
 	return inactive();
 }
+
+void RecordGroup::inventoryRecords(RecordScavenge* recordScavenge)
+{
+	for (RecordSection **section = records, **end = records + RECORD_SLOTS; section < end; ++section)
+		if (*section)
+			(*section)->inventoryRecords(recordScavenge);
+}
diff -Nrup a/storage/falcon/RecordGroup.h b/storage/falcon/RecordGroup.h
--- a/storage/falcon/RecordGroup.h	2007-09-20 17:42:11 +02:00
+++ b/storage/falcon/RecordGroup.h	2007-09-25 07:14:41 +02:00
@@ -29,15 +29,17 @@
 class RecordGroup : public RecordSection  
 {
 public:
-	virtual int countActiveRecords();
-	virtual int retireRecords(Table *table, int base, RecordScavenge *recordScavenge);
-	virtual bool retireSections(Table * table, int id);
-	virtual bool inactive();
 	RecordGroup(int32 base, int32 id, RecordSection *section);
 	RecordGroup(int32 base);
-	virtual bool store (Record *record, Record *prior, int32 id, RecordSection **parentPtr);
-	virtual Record* fetch (int32 id);
 	virtual ~RecordGroup();
+
+	virtual int		countActiveRecords();
+	virtual bool	store (Record *record, Record *prior, int32 id, RecordSection **parentPtr);
+	virtual void	inventoryRecords(RecordScavenge* recordScavenge);
+	virtual Record* fetch (int32 id);
+	virtual int		retireRecords(Table *table, int base, RecordScavenge *recordScavenge);
+	virtual bool	retireSections(Table * table, int id);
+	virtual bool	inactive();
 	
 	RecordSection	*records [RECORD_SLOTS];
 	int32			base;
diff -Nrup a/storage/falcon/RecordLeaf.cpp b/storage/falcon/RecordLeaf.cpp
--- a/storage/falcon/RecordLeaf.cpp	2007-09-20 17:42:12 +02:00
+++ b/storage/falcon/RecordLeaf.cpp	2007-09-25 07:14:41 +02:00
@@ -27,6 +27,7 @@
 #include "Sync.h"
 #include "Interlock.h"
 #include "Bitmap.h"
+#include "RecordScavenge.h"
 
 #ifdef _DEBUG
 #undef THIS_FILE
@@ -119,7 +120,6 @@ int RecordLeaf::retireRecords (Table *ta
 #ifdef NON_BLOCKING_SCAVENGING
 	Sync sync(&syncObject, "RecordLeaf::retireRecords");
 	sync.lock(Shared);
-	bool redo = false;
 	
 	// Get a shared lock to find at least one record to scavenge
 	
@@ -132,27 +132,19 @@ int RecordLeaf::retireRecords (Table *ta
 			if (record->isVersion())
 				{
 				if ((record->scavenge(recordScavenge)) &&
-				    ((!record->hasRecord()) || ((record->useCount == 1) && (record->ageGroup <= recordScavenge->age))))
-				    {
-				    redo = true;
-				    
+				    ((!record->hasRecord()) || ((record->useCount == 1) && (record->generation <= recordScavenge->scavengeGeneration))))
 				    break;
-				    }
 				else
 					++count;
 				}
-			else if (record->ageGroup <= recordScavenge->age && record->useCount == 1)
-				{
-				redo = true;
-				
+			else if (record->generation <= recordScavenge->scavengeGeneration && record->useCount == 1)
 				break;
-				}
 			else
 				++count;
 			}
 		}
 
-	if (!redo)
+	if (ptr >= end)
 		return count;
 	
 	// Get an exclusive lock and do the actual scavenging
@@ -162,7 +154,7 @@ int RecordLeaf::retireRecords (Table *ta
 	count = 0;
 #endif
 	
-	for (ptr = records, end = records + RECORD_SLOTS; ptr < end; ++ptr)
+	for (ptr = records; ptr < end; ++ptr)
 		{
 		Record *record = *ptr;
 		
@@ -171,7 +163,7 @@ int RecordLeaf::retireRecords (Table *ta
 			if (record->isVersion())
 				{
 				if ((record->scavenge(recordScavenge)) &&
-				    ((!record->hasRecord()) || ((record->useCount == 1) && (record->ageGroup <= recordScavenge->age))))
+				    ((!record->hasRecord()) || ((record->useCount == 1) && (record->generation <= recordScavenge->scavengeGeneration))))
 					{
 					*ptr = NULL;
 					recordScavenge->spaceReclaimed += record->size;
@@ -188,7 +180,7 @@ int RecordLeaf::retireRecords (Table *ta
 					++count;
 					}
 				}
-			else if (record->ageGroup <= recordScavenge->age && record->useCount == 1)
+			else if (record->generation <= recordScavenge->scavengeGeneration && record->useCount == 1)
 				{
 				*ptr = NULL;
 				recordScavenge->spaceReclaimed += record->size;
@@ -243,4 +235,14 @@ int RecordLeaf::countActiveRecords()
 			++count;
 
 	return count;
+}
+
+void RecordLeaf::inventoryRecords(RecordScavenge* recordScavenge)
+{
+	Sync sync(&syncObject, "RecordLeaf::inventoryRecords");
+	sync.lock(Shared);
+
+	for (Record **ptr = records, **end = records + RECORD_SLOTS; ptr < end; ++ptr)
+		if (*ptr)
+			recordScavenge->inventoryRecord(*ptr);
 }
diff -Nrup a/storage/falcon/RecordLeaf.h b/storage/falcon/RecordLeaf.h
--- a/storage/falcon/RecordLeaf.h	2007-09-20 17:42:14 +02:00
+++ b/storage/falcon/RecordLeaf.h	2007-09-25 07:14:41 +02:00
@@ -42,6 +42,7 @@ public:
 
 	Record		*records [RECORD_SLOTS];
 	SyncObject	syncObject;
+	void inventoryRecords(RecordScavenge* recordScavenge);
 };
 
 #endif // !defined(AFX_RECORDLEAF_H__02AD6A56_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/RecordScavenge.cpp b/storage/falcon/RecordScavenge.cpp
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/storage/falcon/RecordScavenge.cpp	2007-09-25 07:14:42 +02:00
@@ -0,0 +1,102 @@
+/* Copyright (C) 2007 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 <memory.h>
+#include "Engine.h"
+#include "RecordScavenge.h"
+#include "Database.h"
+#include "Record.h"
+#include "Log.h"
+#include "MemMgr.h"
+
+
+RecordScavenge::RecordScavenge(Database *db, TransId oldestTransaction)
+{
+	database = db;
+	transactionId = oldestTransaction;
+	baseGeneration = database->currentGeneration;
+	memset(ageGroups, 0, sizeof(ageGroups));
+	recordsReclaimed = 0;
+	recordsRemaining = 0;
+	versionsRemaining = 0;
+	spaceReclaimed = 0;
+	spaceRemaining = 0;
+	overflowSpace = 0;
+	numberRecords = 0;
+	recordSpace = 0;
+}
+
+RecordScavenge::~RecordScavenge(void)
+{
+}
+
+void RecordScavenge::inventoryRecord(Record* record)
+{
+	for (Record *rec = record; rec; rec = rec->getPriorVersion())
+		{
+		++numberRecords;
+		recordSpace += record->size;
+		int age = baseGeneration - record->generation;
+		int size = record->size + sizeof(MemBigHeader);
+		
+		if (record->getRecordData())
+			size += sizeof(MemBigHeader);
+			
+		if (age >= 0 && age < AGE_GROUPS)
+			ageGroups[age] += size;
+		else if (age >= AGE_GROUPS)
+			overflowSpace += size;
+		else
+			ageGroups[0] = size;
+		}
+}
+
+int RecordScavenge::computeThreshold(uint64 target)
+{
+	totalSpace = 0;
+	scavengeGeneration = 0;
+	
+	for (int n = 0; n < AGE_GROUPS; ++n)
+		{
+		totalSpace += ageGroups[n];
+		
+		if (totalSpace >= target && scavengeGeneration == 0)
+			scavengeGeneration = baseGeneration - n;
+		}
+
+	totalSpace += overflowSpace;
+
+	if (scavengeGeneration == 0 && totalSpace > target)
+		scavengeGeneration = baseGeneration + AGE_GROUPS;
+	
+	return scavengeGeneration;
+}
+
+void RecordScavenge::printRecordMemory(void)
+{
+	Log::debug ("Record Memory usage for %s:\n", (const char*) database->name);
+	int max;
+
+	for (max = AGE_GROUPS - 1; max > 0; --max)
+		if (ageGroups[max])
+			break;
+
+	for (int n = 0; n <= max; ++n)
+		if (ageGroups [n])
+			Log::debug ("  %d. %d\n", baseGeneration - n, ageGroups[n]);
+
+	Log::log(LogScavenge, " total: " I64FORMAT ", threshold %d%s\n", totalSpace, scavengeGeneration,
+				(scavengeGeneration > 0) ? " -- scavenge" : "");
+}
diff -Nrup a/storage/falcon/RecordScavenge.h b/storage/falcon/RecordScavenge.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/storage/falcon/RecordScavenge.h	2007-09-25 07:14:42 +02:00
@@ -0,0 +1,50 @@
+/* Copyright (C) 2007 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 _RECORD_SCAVENGE_H_
+#define _RECORD_SCAVENGE_H_
+
+static const int AGE_GROUPS = 20;
+
+class Database;
+class Record;
+
+class RecordScavenge
+{
+public:
+	Database	*database;
+	TransId		transactionId;
+	int			scavengeGeneration;
+	int			baseGeneration;
+	uint		recordsReclaimed;
+	uint		recordsRemaining;
+	uint		numberRecords;
+	uint		versionsRemaining;
+	uint64		spaceReclaimed;
+	uint64		spaceRemaining;
+	uint64		ageGroups[AGE_GROUPS];
+	uint64		overflowSpace;
+	uint64		totalSpace;
+	uint64		recordSpace;
+	
+	RecordScavenge(Database *db, TransId oldestTransaction);
+	~RecordScavenge(void);
+
+	void		inventoryRecord(Record* record);
+	int computeThreshold(uint64 target);
+	void printRecordMemory(void);
+};
+
+#endif
diff -Nrup a/storage/falcon/RecordSection.h b/storage/falcon/RecordSection.h
--- a/storage/falcon/RecordSection.h	2007-09-20 17:42:14 +02:00
+++ b/storage/falcon/RecordSection.h	2007-09-25 07:14:41 +02:00
@@ -26,21 +26,23 @@
 
 class Record;
 class Table;
+class RecordScavenge;
 
-struct RecordScavenge;
 
 #define RECORD_SLOTS		100
 
 class RecordSection  
 {
 public:
-	virtual ~RecordSection();
-	virtual Record* fetch (int32 id) = 0;
-	virtual bool store (Record *record, Record *prior, int32 id, RecordSection **parentPtr) = 0;
-	virtual int retireRecords(Table *table, int base, RecordScavenge *recordScavenge) = 0;
 	virtual bool retireSections(Table * table, int id) = 0;
 	virtual bool inactive() = 0;
-	virtual int countActiveRecords() = 0;
+	virtual		~RecordSection();
+	
+	virtual	Record*	fetch (int32 id) = 0;
+	virtual	bool	store (Record *record, Record *prior, int32 id, RecordSection **parentPtr) = 0;
+	virtual	int		retireRecords(Table *table, int base, RecordScavenge *recordScavenge) = 0;
+	virtual	void	inventoryRecords(RecordScavenge* recordScavenge) = 0;
+	virtual	int		countActiveRecords() = 0;
 };
 
 #endif // !defined(AFX_RECORDSECTION_H__02AD6A54_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/RecordVersion.cpp b/storage/falcon/RecordVersion.cpp
--- a/storage/falcon/RecordVersion.cpp	2007-09-20 17:42:14 +02:00
+++ b/storage/falcon/RecordVersion.cpp	2007-09-25 07:14:41 +02:00
@@ -28,6 +28,9 @@
 #include "SerialLogControl.h"
 #include "Stream.h"
 #include "Dbb.h"
+#include "RecordScavenge.h"
+#include "Format.h"
+
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
@@ -45,6 +48,7 @@ RecordVersion::RecordVersion(Table *tbl,
 		{
 		priorVersion->addRef();
 		recordNumber = oldVersion->recordNumber;
+		
 		if (trans == priorVersion->getTransaction())
 			oldVersion->setSuperceded (true);
 		}
@@ -116,7 +120,7 @@ Record* RecordVersion::rollback()
 	if (superceded)
 		return NULL;
 
-	return table->rollbackRecord (this);
+	return format->table->rollbackRecord (this);
 }
 
 bool RecordVersion::isVersion()
@@ -145,7 +149,7 @@ bool RecordVersion::scavenge(RecordScave
 
 	if (transaction || (transactionId >= recordScavenge->transactionId))
 		{
-		table->activeVersions = true;
+		format->table->activeVersions = true;
 
 		if (priorVersion)
 			priorVersion->scavenge(recordScavenge);
@@ -154,7 +158,7 @@ bool RecordVersion::scavenge(RecordScave
 		}
 
 	if (priorVersion)
-		table->expungeRecordVersions(this, recordScavenge);
+		format->table->expungeRecordVersions(this, recordScavenge);
 
 	return true;
 }
@@ -194,7 +198,7 @@ void RecordVersion::scavenge(TransId tar
 	prior->addRef();
 	setPriorVersion(rec);
 	ptr->setPriorVersion(NULL);
-	table->garbageCollect(prior, this, transaction, false);
+	format->table->garbageCollect(prior, this, transaction, false);
 	prior->release();
 }
 
@@ -287,6 +291,7 @@ int RecordVersion::thaw()
 	if (bytesRestored == 0)
 		{
 		Stream stream;
+		Table *table = format->table;
 		
 		if (table->dbb->fetchRecord(table->dataSection, recordNumber, &stream))
 			{
@@ -319,6 +324,7 @@ int RecordVersion::thaw()
 	return bytesRestored;
 }
 
+/***
 char* RecordVersion::getRecordData()
 {
 	if (state == recChilled)
@@ -326,12 +332,13 @@ char* RecordVersion::getRecordData()
 		
 	return data.record;
 }
+***/
 
 void RecordVersion::print(void)
 {
 	Log::debug("  %p\tId %d, enc %d, state %d, tid %d, use %d, grp %d, prior %p\n",
 			this, recordNumber, encoding, state, transactionId, useCount,
-			ageGroup, priorVersion);
+			generation, priorVersion);
 	
 	if (priorVersion)
 		priorVersion->print();
diff -Nrup a/storage/falcon/RecordVersion.h b/storage/falcon/RecordVersion.h
--- a/storage/falcon/RecordVersion.h	2007-09-20 17:42:14 +02:00
+++ b/storage/falcon/RecordVersion.h	2007-09-25 07:14:41 +02:00
@@ -49,7 +49,7 @@ public:
 	virtual void		setVirtualOffset(uint64 offset);
 	virtual uint64		getVirtualOffset();
 	virtual int			thaw();
-	virtual char*		getRecordData();
+	//virtual char*		getRecordData();
 	virtual void		print(void);
 
 	void				commit();
diff -Nrup a/storage/falcon/SRLUpdateRecords.cpp b/storage/falcon/SRLUpdateRecords.cpp
--- a/storage/falcon/SRLUpdateRecords.cpp	2007-09-20 17:42:26 +02:00
+++ b/storage/falcon/SRLUpdateRecords.cpp	2007-09-25 07:14:41 +02:00
@@ -26,6 +26,7 @@
 #include "Log.h"
 #include "Sync.h"
 #include "SerialLogWindow.h"
+#include "Format.h"
 
 SRLUpdateRecords::SRLUpdateRecords(void)
 {
@@ -153,7 +154,7 @@ void SRLUpdateRecords::append(Transactio
 			if (record->state == recNoChill)
 				continue;
 
-			Table *table = record->table;
+			Table *table = record->format->table;
 			tableSpaceId = table->dbb->tableSpaceId;
 			Stream stream;
 			
diff -Nrup a/storage/falcon/SerialLog.cpp b/storage/falcon/SerialLog.cpp
--- a/storage/falcon/SerialLog.cpp	2007-09-20 17:42:34 +02:00
+++ b/storage/falcon/SerialLog.cpp	2007-09-25 07:14:41 +02:00
@@ -442,7 +442,7 @@ void SerialLog::overflowFlush(void)
 	writeBlock->length = (int) (writePtr - (UCHAR*) writeBlock);
 	writeWindow->setLastBlock(writeBlock);
 	lastReadBlock = writeBlock->readBlockNumber = getReadBlock();
-	ASSERT(writeWindow->validate(writeBlock));
+	//ASSERT(writeWindow->validate(writeBlock));
 	
 	// Keep track of what needs to be written
 
@@ -463,7 +463,7 @@ void SerialLog::overflowFlush(void)
 		throw;
 		}	
 		
-	ASSERT(flushWindow->validate(flushBlock));
+	//ASSERT(flushWindow->validate(flushBlock));
 	++physicalFlushes;
 	mutex.unlock();		
 	
@@ -570,7 +570,7 @@ uint64 SerialLog::flush(bool forceNewWin
 		throw;
 		}
 			
-	ASSERT(flushWindow->validate(flushBlock));
+	//ASSERT(flushWindow->validate(flushBlock));
 	++physicalFlushes;
 	mutex.unlock();
 	
@@ -581,7 +581,7 @@ uint64 SerialLog::flush(bool forceNewWin
 	wakeupFlushQueue(thread);
 	ASSERT(writer != thread);
 	ASSERT(writer || !srlQueue);
-	ASSERT(writeWindow->validate(writeBlock));
+	//ASSERT(writeWindow->validate(writeBlock));
 	syncPtr->unlock();
 
 	return nextBlockNumber;
@@ -619,7 +619,7 @@ void SerialLog::createNewWindow(void)
 	writeWindow->firstBlockNumber = nextBlockNumber;
 	initializeWriteBlock(writeWindow->firstBlock());
 	ASSERT(writeWindow->firstBlockNumber == writeBlock->blockNumber);
-	ASSERT(writeWindow->validate(writeBlock));
+	//ASSERT(writeWindow->validate(writeBlock));
 }
 
 void SerialLog::shutdown()
@@ -686,7 +686,7 @@ void SerialLog::putData(uint32 length, c
 	writeBlock->length = (int) (writePtr - (UCHAR*) writeBlock);
 	writeWindow->currentLength = (int) (writePtr - writeWindow->buffer);
 	recordStart = writeBlock->data;
-	ASSERT(writeWindow->validate(writeBlock));
+	//ASSERT(writeWindow->validate(writeBlock));
 }
 
 void SerialLog::startRecord()
@@ -988,7 +988,7 @@ void SerialLog::initializeWriteBlock(Ser
 	writeBlock->length = (int) (writePtr - (UCHAR*) writeBlock);
 	writeWindow->setLastBlock(writeBlock);
 	writeWarningTrack = writeWindow->warningTrack;
-	ASSERT(writeWindow->validate(writeBlock));
+	//ASSERT(writeWindow->validate(writeBlock));
 }
 
 
diff -Nrup a/storage/falcon/SerialLogControl.cpp b/storage/falcon/SerialLogControl.cpp
--- a/storage/falcon/SerialLogControl.cpp	2007-09-20 17:42:34 +02:00
+++ b/storage/falcon/SerialLogControl.cpp	2007-09-25 07:14:41 +02:00
@@ -170,10 +170,10 @@ SerialLogRecord* SerialLogControl::getRe
 
 void SerialLogControl::setWindow(SerialLogWindow *window, SerialLogBlock *block, int offset)
 {
-	ASSERT(window->validate(block));
+	//ASSERT(window->validate(block));
 	SerialLogWindow *priorWindow = inputWindow;
 	SerialLogBlock *priorBlock = inputBlock;
-	ASSERT(!priorWindow || priorWindow->validate(priorBlock));
+	//ASSERT(!priorWindow || priorWindow->validate(priorBlock));
 
 	if (inputWindow != window)
 		{
@@ -186,8 +186,8 @@ void SerialLogControl::setWindow(SerialL
 
 	Sync sync(&log->syncWrite, "SerialLogControl::setWindow");
 	sync.lock(Shared);
-	inputWindow->validate(block);
-	ASSERT(inputWindow->validate(block));
+	//inputWindow->validate(block);
+	//ASSERT(inputWindow->validate(block));
 	inputBlock = block;
 	input = inputBlock->data;
 	inputEnd = (const UCHAR*) inputBlock + block->length;
@@ -196,7 +196,7 @@ void SerialLogControl::setWindow(SerialL
 	if (inputBlock == log->writeBlock && log->recordIncomplete)
 		inputEnd = log->recordStart;
 	
-	ASSERT(inputWindow->validate(inputEnd));	
+	//ASSERT(inputWindow->validate(inputEnd));	
 	version = srlVersion0;
 
 	if (input < inputEnd)
diff -Nrup a/storage/falcon/SerialLogWindow.cpp b/storage/falcon/SerialLogWindow.cpp
--- a/storage/falcon/SerialLogWindow.cpp	2007-09-20 17:42:36 +02:00
+++ b/storage/falcon/SerialLogWindow.cpp	2007-09-25 07:14:42 +02:00
@@ -184,7 +184,7 @@ SerialLogBlock* SerialLogWindow::nextBlo
 		 nextBlk->creationTime == (uint32) log->creationTime &&
 		 nextBlk->blockNumber == block->blockNumber + 1)
 		{
-		ASSERT(validate(nextBlk));
+		//ASSERT(validate(nextBlk));
 		return nextBlk;
 		}
 
diff -Nrup a/storage/falcon/Table.cpp b/storage/falcon/Table.cpp
--- a/storage/falcon/Table.cpp	2007-09-20 17:42:43 +02:00
+++ b/storage/falcon/Table.cpp	2007-09-25 07:14:42 +02:00
@@ -52,6 +52,7 @@
 #include "Interlock.h"
 #include "Collation.h"
 #include "TableSpace.h"
+#include "RecordScavenge.h"
 
 #ifndef STORAGE_ENGINE
 #include "Trigger.h"
@@ -331,7 +332,13 @@ void Table::insert(Transaction *transact
 		// Verify that record is valid
 
 		checkNullable(record);
-		checkUniqueIndexes(transaction, record);
+		Sync sync(&syncUpdate, "Table::insert");
+		
+		if (indexes)
+			{
+			sync.lock(Exclusive);
+			checkUniqueIndexes(transaction, record);
+			}
 
 		recordNumber = record->recordNumber = dbb->insertStub(dataSection, transaction);
 		transaction->addRecord(record);
@@ -392,7 +399,7 @@ Format* Table::getFormat(int version)
 	statement->setInt(1, tableId);
 	statement->setInt(2, version);
 	RSet set = statement->executeQuery();
-	format = NEW Format(set);
+	format = NEW Format(this, set);
 	sync2.unlock();
 	addFormat(format);
 
@@ -583,7 +590,7 @@ Record* Table::fetchNext(int32 start)
 Record* Table::databaseFetch(int32 recordNumber)
 {
 	Stream stream;
-	ageGroup = database->currentAgeGroup;
+	ageGroup = database->currentGeneration;
 
 	if (!dataSection)
 		dataSection = dbb->findSection(dataSectionId);
@@ -761,7 +768,7 @@ void Table::loadIndexes()
 
 void Table::init(int id, const char *schema, const char *tableName, TableSpace *tblSpace)
 {
-	ageGroup = database->currentAgeGroup;
+	ageGroup = database->currentGeneration;
 
 	if ( (tableSpace = tblSpace) )
 		dbb = tableSpace->dbb;
@@ -1065,7 +1072,13 @@ void Table::update(Transaction * transac
 
 		// Make sure no uniqueness rules are violated
 
-		checkUniqueIndexes(transaction, record);
+		Sync sync(&syncUpdate, "Table::update");
+		
+		if (indexes)
+			{
+			sync.lock(Exclusive);
+			checkUniqueIndexes(transaction, record);
+			}
 
 		// Checkin with any table attachments
 
@@ -1258,7 +1271,7 @@ void Table::deleteRecord(Transaction * t
 		}
 
 	record->state = recDeleted;
-	record->setAgeGroup();
+	//record->setAgeGroup();
 	fireTriggers(transaction, PreDelete, oldRecord, NULL);
 
 	// Do any necessary cascading
@@ -1589,9 +1602,19 @@ int Table::retireRecords(RecordScavenge 
 	return count;
 }
 
+void Table::inventoryRecords(RecordScavenge* recordScavenge)
+{
+	if (!records)
+		return;
+		
+	Sync sync(&syncObject, "Table::inventoryRecords");
+	sync.lock(Shared);
+	records->inventoryRecords(recordScavenge);
+}
+
 bool Table::insert(Record * record, Record *prior, int recordNumber)
 {
-	ageGroup = database->currentAgeGroup;
+	ageGroup = database->currentGeneration;
 	Sync sync(&syncObject, "Table::insert");
 
 	if (record)
@@ -2613,9 +2636,13 @@ uint Table::insert(Transaction *transact
 			
 		record = allocRecordVersion(fmt, transaction, NULL);
 		record->setEncodedRecord(stream, false);
+		Sync sync(&syncUpdate, "Table::insert");
 		
 		if (indexes)
+			{
+			sync.lock(Exclusive);
 			checkUniqueIndexes(transaction, record);
+			}
 			
 		recordNumber = record->recordNumber = dbb->insertStub(dataSection, transaction);
 		transaction->addRecord(record);
@@ -2727,7 +2754,13 @@ void Table::update(Transaction * transac
 
 		// Make sure no uniqueness rules are violated
 
-		checkUniqueIndexes(transaction, record);
+		Sync sync(&syncUpdate, "Table::update");
+		
+		if (indexes)
+			{
+			sync.lock(Exclusive);
+			checkUniqueIndexes(transaction, record);
+			}
 
 		// Checkin with any table attachments
 
@@ -3243,4 +3276,9 @@ Record* Table::allocRecord(int recordNum
 			}
 	
 	return NULL;
+}
+
+Format* Table::getCurrentFormat(void)
+{
+	return getFormat(formatVersion);;
 }
diff -Nrup a/storage/falcon/Table.h b/storage/falcon/Table.h
--- a/storage/falcon/Table.h	2007-09-20 17:42:44 +02:00
+++ b/storage/falcon/Table.h	2007-09-25 07:14:42 +02:00
@@ -67,8 +67,7 @@ class AsciiBlob;
 class BinaryBlob;
 class Section;
 class TableSpace;
-
-struct RecordScavenge;
+class RecordScavenge;
 
 class Table : public PrivilegeObject
 {
@@ -203,6 +202,7 @@ public:
 	SyncObject		syncObject;
 	SyncObject		syncTriggers;
 	SyncObject		syncScavenge;
+	SyncObject		syncUpdate;
 	SyncObject		syncAlter;				// prevent concurrent Alter statements.
 	Table			*collision;				// Hash collision in database
 	Table			*idCollision;			// mod(id) collision in database
@@ -247,6 +247,8 @@ protected:
 public:
 	RecordVersion* allocRecordVersion(Format* format, Transaction* transaction, Record* priorVersion);
 	Record* allocRecord(int recordNumber, Stream* stream);
+	void inventoryRecords(RecordScavenge* recordScavenge);
+	Format* getCurrentFormat(void);
 };
 
 #endif // !defined(AFX_TABLE_H__02AD6A42_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/Transaction.cpp b/storage/falcon/Transaction.cpp
--- a/storage/falcon/Transaction.cpp	2007-09-20 17:42:46 +02:00
+++ b/storage/falcon/Transaction.cpp	2007-09-25 07:14:42 +02:00
@@ -39,6 +39,7 @@
 #include "SerialLogControl.h"
 #include "InfoTable.h"
 #include "Thread.h"
+#include "Format.h"
 
 static const char *stateNames [] = {
 	"Active",
@@ -54,6 +55,8 @@ static const char *stateNames [] = {
 	"Initial"
 	};
 
+static const int INDENT = 5;
+
 #ifdef _DEBUG
 #undef THIS_FILE
 static const char THIS_FILE[]=__FILE__;
@@ -113,6 +116,7 @@ void Transaction::initialize(Connection*
 	numberStates = 0;
 	blockedBy = 0;
 	inList = true;
+	thread = NULL;
 	//scavenged = false;
 	
 	if (seq == 0)
@@ -131,6 +135,8 @@ void Transaction::initialize(Connection*
 		freeSavePoints = localSavePoints + n;
 		}
 	
+	blockingRecord = NULL;
+	thread = Thread::getThread("Transaction::init");
 	syncActive.lock(NULL, Exclusive);
 	Transaction *oldest = transactionManager->findOldest();
 	oldestActive = (oldest) ? oldest->transactionId : transactionId;
@@ -264,12 +270,12 @@ void Transaction::commit()
 
 	for (RecordVersion *record = firstRecord; record; record = record->nextInTrans)
 		if (!record->isSuperceded() && record->state != recLock)
-			record->table->updateRecord (record);
+			record->format->table->updateRecord (record);
 
 	if (commitTriggers)
 		for (RecordVersion *record = firstRecord; record; record = record->nextInTrans)
 			if (!record->isSuperceded() && record->state != recLock)
-				record->table->postCommit (this, record);
+				record->format->table->postCommit (this, record);
 
 	releaseDependencies();
 	database->flushInversion(this);
@@ -278,9 +284,9 @@ void Transaction::commit()
 	
 	for (RecordVersion *record = firstRecord; record; record = record->nextInTrans)
 		if (!record->priorVersion)
-			++record->table->cardinality;
-		else if (record->state == recDeleted && record->table->cardinality > 0)
-			--record->table->cardinality;
+			++record->format->table->cardinality;
+		else if (record->state == recDeleted && record->format->table->cardinality > 0)
+			--record->format->table->cardinality;
 			
 	syncActiveTransactions.unlock();
 	Sync syncCommitted(&transactionManager->committedTransactions.syncObject, "Transaction::commit");
@@ -413,7 +419,7 @@ void Transaction::rollback()
 		record->nextInTrans = NULL;
 
 		if (record->state == recLock)
-			record->table->unlockRecord(record, false);
+			record->format->table->unlockRecord(record, false);
 		else
 			record->rollback();
 		
@@ -747,7 +753,11 @@ void Transaction::commitRecords()
 
 State Transaction::getRelativeState(Record* record, uint32 flags)
 {
-	return getRelativeState(record->getTransaction(), record->getTransactionId(), flags);
+    blockingRecord = record;
+	State state = getRelativeState(record->getTransaction(), record->getTransactionId(), flags);
+	blockingRecord = NULL;
+
+	return state;
 }
 
 /***
@@ -833,7 +843,7 @@ void Transaction::dropTable(Table* table
 	// Keep exclusive lock to avoid race condition with writeComplete
 	
 	for (RecordVersion **ptr = &firstRecord, *rec; (rec = *ptr);)
-		if (rec->table == table)
+		if (rec->format->table == table)
 			removeRecord(rec);
 		else
 			ptr = &rec->nextInTrans;
@@ -842,7 +852,7 @@ void Transaction::dropTable(Table* table
 bool Transaction::hasUncommittedRecords(Table* table)
 {
 	for (RecordVersion *rec = firstRecord; rec; rec = rec->nextInTrans)
-		if (rec->table == table)
+		if (rec->format->table == table)
 			return true;
 	
 	return false;
@@ -1091,7 +1101,7 @@ void Transaction::releaseRecordLocks(voi
 	for (ptr = &firstRecord; (record = *ptr);)
 		if (record->state == recLock)
 			{
-			record->table->unlockRecord(record, false);
+			record->format->table->unlockRecord(record, false);
 			removeRecord(record);
 			}
 		else
@@ -1103,6 +1113,64 @@ void Transaction::print(void)
 	Log::debug("  %p Id %d, state %d, updates %d, wrtPend %d, states %d, dependencies %d, records %d\n",
 			this, transactionId, state, hasUpdates, writePending, 
 			numberStates, dependencies, firstRecord != NULL);
+}
+
+void Transaction::printBlocking(int level)
+{
+	int locks = 0;
+	int updates = 0;
+	int inserts = 0;
+	int deletes = 0;
+	RecordVersion *record;
+
+	for (record = firstRecord; record; record = record->nextInTrans)
+		if (record->state == recLock)
+			++locks;
+		else if (!record->hasRecord())
+			++deletes;
+		else if (record->priorVersion)
+			++updates;
+		else
+			++inserts;
+
+	Log::debug ("%*s Trans %d, thread %d, locks %d, inserts %d, deleted %d, updates %d\n", 
+				level * INDENT, "", transactionId,
+				thread->threadId, locks, inserts, deletes, updates);
+
+	++level;
+
+	Table *table = blockingRecord->format->table;
+	
+	if (blockingRecord)
+		Log::debug("%*s Blocking on %s.%s record %d\n",
+				   level * INDENT, "",
+				   table->name, table->schemaName,
+				   blockingRecord->recordNumber);
+
+	for (record = firstRecord; record; record = record->nextInTrans)
+		{
+		const char *what;
+
+		if (record->state == recLock)
+			what = "locked";
+		else if (!record->hasRecord())
+			what = "deleted";
+		else if (record->priorVersion)
+			what = "updated";
+		else
+			what = "inserted";
+
+		Table *table = record->format->table;
+		
+		Log::debug("%*s Record %s.%s number %d %s\n",
+				   level * INDENT, "",
+				   table->name, 
+				   table->schemaName,
+				   record->recordNumber,
+				   what);
+		}
+
+	database->transactionManager->printBlocking(this, level);
 }
 
 void Transaction::getInfo(InfoTable* infoTable)
diff -Nrup a/storage/falcon/Transaction.h b/storage/falcon/Transaction.h
--- a/storage/falcon/Transaction.h	2007-09-20 17:42:46 +02:00
+++ b/storage/falcon/Transaction.h	2007-09-25 07:14:42 +02:00
@@ -41,6 +41,7 @@ class Index;
 class Bitmap;
 class Record;
 class InfoTable;
+class Thread;
 
 // Transaction States
 
@@ -120,6 +121,12 @@ public:
 	void		thaw(DeferredIndex* deferredIndex);
 	void		print(void);
 	void		getInfo(InfoTable* infoTable);
+	void		fullyCommitted(void);
+	void		releaseCommittedTransaction(void);
+	void		commitNoUpdates(void);
+	void		validateDependencies(bool noDependencies);
+	void		releaseSavePoints(void);
+	void		printBlocking(int level);
 
 	inline bool isActive()
 		{
@@ -139,6 +146,8 @@ public:
 	SavePoint		*freeSavePoints;
 	SavePoint		localSavePoints[LOCAL_SAVE_POINTS];
 	DeferredIndex	*deferredIndexes;
+	Thread			*thread;
+	Record			*blockingRecord;
 	int				deferredIndexCount;
 	int				statesAllocated;
 	int				isolationLevel;
@@ -171,7 +180,6 @@ public:
 	volatile INTERLOCK_TYPE	dependencies;
 	volatile INTERLOCK_TYPE	useCount;
 	volatile INTERLOCK_TYPE	inList;
-	//volatile INTERLOCK_TYPE	cleanupNeeded;
 
 protected:
 	RecordVersion	*firstRecord;
@@ -179,12 +187,6 @@ protected:
 	RecordVersion	**recordPtr;
 
 	virtual ~Transaction();
-public:
-	void fullyCommitted(void);
-	void releaseCommittedTransaction(void);
-	void commitNoUpdates(void);
-	void validateDependencies(bool noDependencies);
-	void releaseSavePoints(void);
 };
 
 #endif // !defined(AFX_TRANSACTION_H__02AD6A4D_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
diff -Nrup a/storage/falcon/TransactionManager.cpp b/storage/falcon/TransactionManager.cpp
--- a/storage/falcon/TransactionManager.cpp	2007-09-20 17:42:46 +02:00
+++ b/storage/falcon/TransactionManager.cpp	2007-09-25 07:14:42 +02:00
@@ -25,6 +25,7 @@
 #include "Connection.h"
 #include "InfoTable.h"
 #include "Log.h"
+#include "LogLock.h"
 
 static const int EXTRA_TRANSACTIONS = 10;
 
@@ -426,4 +427,22 @@ void TransactionManager::removeTransacti
 				break;
 				}
 		}
+}
+
+void TransactionManager::printBlockage(void)
+{
+	LogLock logLock;
+	Sync sync (&activeTransactions.syncObject, "TransactionManager::printBlockage");
+	sync.lock (Shared);
+
+	for (Transaction *trans = activeTransactions.first; trans; trans = trans->next)
+		if (trans->state == Active && !trans->waitingFor)
+			trans->printBlocking(1);
+}
+
+void TransactionManager::printBlocking(Transaction* transaction, int level)
+{
+	for (Transaction *trans = activeTransactions.first; trans; trans = trans->next)
+		if (trans->state == Active && trans->waitingFor == transaction)
+			trans->printBlocking(level);
 }
diff -Nrup a/storage/falcon/TransactionManager.h b/storage/falcon/TransactionManager.h
--- a/storage/falcon/TransactionManager.h	2007-09-20 17:42:46 +02:00
+++ b/storage/falcon/TransactionManager.h	2007-09-25 07:14:42 +02:00
@@ -47,6 +47,8 @@ public:
 	void 			validateDependencies(void);
 	void			removeCommittedTransaction(Transaction* transaction);
 	void			removeTransaction(Transaction* transaction);
+	void			printBlockage(void);
+	void			printBlocking(Transaction* transaction, int level);
 	
 	TransId			transactionSequence;
 	Database		*database;
Thread
bk commit into 6.0 tree (hakank:1.2596)Hakan Kuecuekyilmaz25 Sep