/*!
@header FTGenericTransactionOptimizer
@abstract Module of FT
@availability OS X, GNUstep
@copyright 2004, 2005, 2006 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-------------------------------------------------------------------------
Modification history
24.07.05 ola initial version
23.08.06 ola license changed
-------------------------------------------------------------------------
*/
#include
#include
#include
#include
/********************************************** __FTAnalyseTransactionSteps */
@interface __FTAnalyseTransactionSteps : FTObject {
@private
FTTransactionImpl *transaction;
/**
* Maps nodeId's to arrays of FTGraphImplTransactions
* So this dictionary may be used to find out redundant
* FTGraphImplTransactions for each node
*/
NSMutableDictionary *nodeIdToArrayOfSteps;
}
- initForTransaction: (FTTransactionImpl *) transaction;
- (void) dealloc;
/**
* This method creates internal structures used to optimize
* the transactions.
* Called by initForTransaction.
*/
- buildIndex;
/**
* starts the optimization
*/
- (FTTransactionImpl *) optimize;
/*!
* @method removeDeleteUpdates
* @abstract Internal methods which removes all operations related to a node
* if there exists a delete operation for this node
* @result self
*/
- removeDeleteUpdates;
/**
* Called by optimize in order to remove redundant
* FTGraphImplTransactions for each node
*/
- removeRedundantGraphTransactions;
@end
@implementation __FTAnalyseTransactionSteps
- initForTransaction: (FTTransactionImpl *) aTransaction {
self = [super init];
self->transaction = [aTransaction retain];
self->nodeIdToArrayOfSteps = [[NSMutableDictionary alloc] init];
[self buildIndex];
return self;
}
- (void) dealloc {
[self->transaction release];
[self->nodeIdToArrayOfSteps release];
[super dealloc];
}
- buildIndex {
NSEnumerator *steps;
id currentStep;
steps = [[transaction transactionSteps] objectEnumerator];
while( (currentStep = [steps nextObject]) ) {
if( [currentStep isKindOfClass: [FTTransactionStepAndContext class]] ) {
id step;
FTTransactionContext *context;
step = [((FTTransactionStepAndContext *) currentStep) transactionStep];
context = [((FTTransactionStepAndContext *) currentStep)
transactionContext];
if( [step isKindOfClass: [FTGraphImplTransactions class]] ) {
/**
* Extract node and map node --> operation in order to find
* redundancies.
*/
FTNodeImpl *node = [((FTGraphImplTransactions *) step)
nodeFromContext: context];
if( nil != node ) {
/* find node in dictionary. If found, then add the step to the
* existing list. Otherwise create the list: */
NSMutableArray *stepsOfNode =
[self->nodeIdToArrayOfSteps objectForKey: [node nodeId]];
if( nil == stepsOfNode ) {
stepsOfNode = [[NSMutableArray alloc] init];
[self->nodeIdToArrayOfSteps
setObject: stepsOfNode
forKey: [node nodeId]];
[stepsOfNode release];
}
[stepsOfNode addObject: currentStep];
}
}
}
}
return self;
}
- (FTTransactionImpl *) optimize {
[self removeRedundantGraphTransactions];
[self removeDeleteUpdates];
return self->transaction;
}
- removeDeleteUpdates {
NSEnumerator *keyEnumerator;
id nextKey;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"__FTAnalyseTransactionSteps::removeDeleteUpdates" ];
}
keyEnumerator = [self->nodeIdToArrayOfSteps keyEnumerator];
while( (nextKey = [keyEnumerator nextObject]) ) {
NSArray *steps
= (NSArray *) [self->nodeIdToArrayOfSteps objectForKey: nextKey];
if( [steps count] > 1 ) {
int i;
BOOL deletionFound = NO;
for( i = 0; i < [steps count]; i++ ) {
FTTransactionStepAndContext *step
= (FTTransactionStepAndContext *) [steps objectAtIndex: i];
if( !deletionFound ) {
/* look for deletion operation: */
if( __FTGRAPHIMPL_TX_NODE_REMOVE
== [FTGraphImplTransactions
operationIdFromContext: [step transactionContext]] ) {
int j;
deletionFound = YES;
// now disable all previous visited operations
for( j = 0; j < i; j++ ) {
FTGraphImplTransactions *graphTransactionStep
= (FTGraphImplTransactions *) [step transactionStep];
[graphTransactionStep enableOperation: NO];
}
}
} else {
/* disable operation since a deletion operation has been
* detected before
*/
FTGraphImplTransactions *graphTransactionStep
= (FTGraphImplTransactions *) [step transactionStep];
[graphTransactionStep enableOperation: NO];
}
}
}
}
return self;
}
- removeRedundantGraphTransactions {
NSEnumerator *keyEnumerator;
id nextKey;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"__FTAnalyseTransactionSteps::removeRedundantGraphTransactions" ];
}
keyEnumerator = [self->nodeIdToArrayOfSteps keyEnumerator];
while( (nextKey = [keyEnumerator nextObject]) ) {
NSArray *steps
= (NSArray *) [self->nodeIdToArrayOfSteps objectForKey: nextKey];
if( [steps count] > 1 ) {
int i;
BOOL updateFound = NO;
for( i = 0; i < [steps count]; i++ ) {
FTTransactionStepAndContext *step
= (FTTransactionStepAndContext *) [steps objectAtIndex: i];
if( __FTGRAPHIMPL_TX_NODE_UPDATE
== [FTGraphImplTransactions
operationIdFromContext: [step transactionContext]] ) {
if( !updateFound ) {
updateFound = YES;
} else {
/**
* We don't need more then one update, so disable the current
* one:
*/
FTGraphImplTransactions *graphTransactionStep
= (FTGraphImplTransactions *) [step transactionStep];
[graphTransactionStep enableOperation: NO];
}
}
}
}
}
return self;
}
@end
/********************************************** __FTAnalyseTransactionSteps */
@implementation FTGenericTransactionOptimizer
- init {
self = [super init];
self->lock = [[NSLock alloc] init];
return self;
}
- (void) dealloc {
[self->lock release];
[super dealloc];
}
- (id ) optimizeTransaction: (id ) toOptimize {
if( ![toOptimize isKindOfClass: [FTTransactionImpl class]] ) {
return toOptimize;
}
[self->lock lock];
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"FTGenericTransactionOptimizer::optimizeTransaction: BEGIN" ];
}
NS_DURING
__FTAnalyseTransactionSteps * steps =
[[__FTAnalyseTransactionSteps alloc]
initForTransaction: (FTTransactionImpl *) toOptimize];
[steps optimize];
[steps release];
NS_HANDLER
NS_ENDHANDLER
if( [[FTLogging coreLog] isDebugEnabled] ) {
[[FTLogging coreLog]
trace: @"FTGenericTransactionOptimizer::optimizeTransaction: FINISHED" ];
}
[self->lock unlock];
return toOptimize;
}
- analyseTransaction {
return self;
}
@end