/* This source code is provided "as is" and without warranty, express */ /* or implied. */ #import #import #import #import "Movie.h" #import "Actor.h" #import "Director.h" void usage(void) { NSLog(@"Usage: LeakTester -batchsize -runs -trials -hang WARNING!!!! THIS PROGRAM REMOVES ALL EXISTING DATA IN THE TABLES USED"); } void logReport(NSString *modelPath, int batchsize, int runs, int trials) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; EOModel *model; model = [[[EOModel alloc] initWithContentsOfFile:modelPath] autorelease]; NSLog(@"%@, batchsize = %i, runs = %i, trials = %i", [model adaptorName], batchsize, runs, trials); [pool release]; } void clearTables(NSString *modelPath) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; EOModel *model; EOAdaptor *adaptor; EOAdaptorContext *context; EOAdaptorChannel *channel; EOSQLExpression *expression; model = [[[EOModel alloc] initWithContentsOfFile:modelPath] autorelease]; adaptor = [EOAdaptor adaptorWithModel:model]; context = [adaptor createAdaptorContext]; channel = [context createAdaptorChannel]; NSLog(@"Dumping old data from tables..."); [channel openChannel]; expression = [[adaptor expressionClass] expressionForString:@"delete from LKMOVIE"]; [channel evaluateExpression:expression]; expression = [[adaptor expressionClass] expressionForString:@"delete from LKACTOR"]; [channel evaluateExpression:expression]; expression = [[adaptor expressionClass] expressionForString:@"delete from LKDIRECTOR"]; [channel evaluateExpression:expression]; // Informix complains if we do a COMMIT here; OK for Sybase and Oracle. // expression = [[adaptor expressionClass] expressionForString:@"commit"]; // [channel evaluateExpression:expression]; [channel closeChannel]; [pool release]; } void doit(NSString *modelPath, int batchsize, int runs) { NSAutoreleasePool *pool, *pool0, *pool1, *pool2; EOEditingContext *editingContext = [EOEditingContext new]; // context with defaultCoordinator Movie *movie; Movie *lastMovie; NSArray *movies; NSArray *actors; NSArray *lastActors; Actor *actor; Director *director; int i; int j; int priKey; int m; // For apps with models stored in the main bundle, the following is // unnecessary, since the defaultGroup will be automatically built from // the contents of the main bundle and and any referenced frameworks. pool = [[NSAutoreleasePool alloc] init]; [EOModelGroup setDefaultGroup:[[EOModelGroup new] autorelease]]; [[EOModelGroup defaultGroup] addModelWithFile:modelPath]; pool0 = [[NSAutoreleasePool alloc] init]; // Create and insert root set NSLog(@"Inserting root set..."); priKey = 0; for ( i = 0 ; i < runs ; i++ ) { pool1 = [[NSAutoreleasePool alloc] init]; for ( j = 0 ; j < batchsize ; j++ ) { priKey++; movie = [[[Movie alloc] init] autorelease]; [movie setMovieId:[NSDecimalNumber decimalNumberWithMantissa:priKey exponent:0 isNegative:NO]]; [movie setTitle:[NSString stringWithFormat:@"Movie_%i",priKey]]; [editingContext insertObject:movie]; } [editingContext saveChanges]; [[editingContext rootObjectStore] invalidateAllObjects]; [[editingContext undoManager] forgetAll]; [pool1 release]; } [pool0 release]; priKey = 0; for ( i = 0 ; i < runs ; i++ ) { pool1 = [[NSAutoreleasePool alloc] init]; pool2 = [[NSAutoreleasePool alloc] init]; NSLog(@"Fetching Movies batch and adding objects for run #%i...",i); movies = [editingContext objectsWithFetchSpecification:[EOFetchSpecification fetchSpecificationWithEntityName:@"Movie" qualifier:[EOQualifier qualifierWithQualifierFormat:@"(movieId > %d) AND (movieId <= %d)", i*batchsize, (i+1)*batchsize] sortOrderings:nil]]; for ( j = 0 ; j < [movies count] ; j++ ) { movie = [movies objectAtIndex:j]; priKey++; director = [[movie director] self]; // Just to tickle the fault director = [[Director alloc] init]; [editingContext insertObject:director]; [director setDirectorId:[NSDecimalNumber decimalNumberWithMantissa:priKey exponent:0 isNegative:NO]]; [director setName:[NSString stringWithFormat:@"First_%i",priKey]]; [movie addObject:director toBothSidesOfRelationshipWithKey:@"director"]; [director release]; for ( m = 0 ; m < batchsize ; m++ ) { priKey++; actor = [[Actor alloc] init]; [editingContext insertObject:actor]; [actor setActorId:[NSDecimalNumber decimalNumberWithMantissa:priKey exponent:0 isNegative:NO]]; [actor setName:[NSString stringWithFormat:@"First_%i",priKey]]; [movie addObject:actor toBothSidesOfRelationshipWithKey:@"actors"]; [actor release]; } } NSLog(@"Saving..."); [editingContext saveChanges]; [editingContext invalidateAllObjects]; [[editingContext rootObjectStore] invalidateAllObjects]; [[editingContext undoManager] forgetAll]; [pool2 release]; [pool1 release]; } for ( i = 0 ; i < runs ; i++ ) { pool1 = [[NSAutoreleasePool alloc] init]; pool2 = [[NSAutoreleasePool alloc] init]; NSLog(@"Fetching Movies batch and mutating for run #%i...",i); movies = [editingContext objectsWithFetchSpecification:[EOFetchSpecification fetchSpecificationWithEntityName:@"Movie" qualifier:[EOQualifier qualifierWithQualifierFormat:@"(movieId > %d) AND (movieId <= %d)", i*batchsize, (i+1)*batchsize] sortOrderings:nil]]; for ( j = 0 ; j < [movies count] ; j++ ) { movie = [movies objectAtIndex:j]; priKey++; director = [[movie director] self]; // Just to tickle the fault director = [[Director alloc] init]; [editingContext insertObject:director]; [director setDirectorId:[NSDecimalNumber decimalNumberWithMantissa:priKey exponent:0 isNegative:NO]]; [director setName:[NSString stringWithFormat:@"First_%i",priKey]]; [movie addObject:director toBothSidesOfRelationshipWithKey:@"director"]; [director release]; if ( j % 2 ) { actors = [[movie actors] shallowCopy]; lastMovie = [movies objectAtIndex:j-1]; lastActors = [[lastMovie actors] shallowCopy]; for ( m = 0 ; m < [actors count] ; m++ ) { [movie removeFromActors:[actors objectAtIndex:m]]; } for ( m = 0 ; m < [lastActors count] ; m++ ) { [movie addToActors:[lastActors objectAtIndex:m]]; } for ( m = 0 ; m < [lastActors count] ; m++ ) { [lastMovie removeFromActors:[lastActors objectAtIndex:m]]; } for ( m = 0 ; m < [actors count] ; m++ ) { [lastMovie addToActors:[actors objectAtIndex:m]]; } [actors release]; [lastActors release]; } } NSLog(@"Saving mutations..."); [editingContext saveChanges]; [editingContext invalidateAllObjects]; [[editingContext rootObjectStore] invalidateAllObjects]; [[editingContext undoManager] forgetAll]; [pool2 release]; [pool1 release]; } [EOModelGroup setDefaultGroup: nil]; [pool release]; [editingContext release]; } void main (int argc, const char *argv[]) { NSAutoreleasePool * pool; BOOL hang; int batchsize, runs, trials; NSString *modelPath; int trial; pool = [[NSAutoreleasePool alloc] init]; hang = [[NSUserDefaults standardUserDefaults] boolForKey:@"hang"]; batchsize = [[NSUserDefaults standardUserDefaults] integerForKey:@"batchsize"]; if (!batchsize) batchsize = 1; runs = [[NSUserDefaults standardUserDefaults] integerForKey:@"runs"]; if (!runs) runs = 1; trials = [[NSUserDefaults standardUserDefaults] integerForKey:@"trials"]; if (!trials) trials = 1; modelPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"LeakTester.eomodeld"]; logReport(modelPath, batchsize, runs, trials); for (trial = 0; trial < trials; trial++) { NSLog(@"Trial %i beginning...", trial); clearTables(modelPath); doit(modelPath, batchsize, runs); NSLog(@"Trial %i done.", trial); } logReport(modelPath, batchsize, runs, trials); [pool release]; if (hang) { NSLog(@"Hit RETURN to exit..."); getchar(); } NSLog(@"Done."); exit(0); // insure the process exit status is 0 }