/*! @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