Author: ericwa
Date: Sat Mar 29 23:04:46 2014
New Revision: 10660
URL: http://svn.gna.org/viewcvs/etoile?rev=10660&view=rev
Log:
COEditingContext: detect recursive calls to commit methods
Modified:
trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.h
trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.m
trunk/Etoile/Frameworks/CoreObject/Tests/Core/TestEditingContext.m
trunk/Etoile/Frameworks/CoreObject/Tests/TestCommon.m
Modified: trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.h
URL:
http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.h?rev=10660&r1=10659&r2=10660&view=diff
==============================================================================
--- trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.h (original)
+++ trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.h Sat Mar 29
23:04:46 2014
@@ -133,6 +133,8 @@
BOOL _isRecordingUndo;
COCommandGroup *_currentEditGroup;
CORevisionCache *_revisionCache;
+ /** Detect illegal recursive calls to commit */
+ BOOL _inCommit;
}
Modified: trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.m
URL:
http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.m?rev=10660&r1=10659&r2=10660&view=diff
==============================================================================
--- trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.m (original)
+++ trunk/Etoile/Frameworks/CoreObject/Core/COEditingContext.m Sat Mar 29
23:04:46 2014
@@ -524,81 +524,95 @@
withUndoTrack: (COUndoTrack *)track
error: (NSError **)anError
{
- [self validateMetadata: metadata];
-
- // TODO: We could organize validation errors by persistent root. Each
- // persistent root might result in a validation error that contains a
- // suberror per inner object, then each suberror could in turn contain
- // a suberror per validation result. For now, we just aggregate errors
per
- // inner object.
- if ([self validateChangedObjectsForContext: self error: anError] == NO)
- return NO;
-
- /* Commit persistent root changes (deleted persistent roots included) */
-
- COStoreTransaction *transaction = [[COStoreTransaction alloc] init];
- [self recordBeginUndoGroupWithMetadata: metadata];
-
- for (COPersistentRoot *persistentRoot in persistentRoots)
- {
- [persistentRoot saveCommitWithMetadata: metadata transaction:
transaction];
- }
-
- /* Add persistent root deletions to the transaction */
-
- for (COPersistentRoot *persistentRoot in persistentRoots)
- {
- ETUUID *uuid = [persistentRoot UUID];
-
- if ([_persistentRootsPendingDeletion containsObject:
persistentRoot])
- {
- [transaction deletePersistentRoot: uuid];
- [self recordPersistentRootDeletion: persistentRoot];
- }
- else if ([_persistentRootsPendingUndeletion containsObject:
persistentRoot])
- {
- [transaction undeletePersistentRoot: uuid];
- [self recordPersistentRootUndeletion: persistentRoot];
- }
- }
-
- /* Update transaction IDs (can't add to the transaction after this) */
-
- for (ETUUID *uuid in [transaction persistentRootUUIDs])
- {
- COPersistentRoot *persistentRoot = [self persistentRootForUUID:
uuid];
-
- persistentRoot.lastTransactionID = [transaction
setOldTransactionID: persistentRoot.lastTransactionID
-
forPersistentRoot: uuid];
- }
-
- /* Update _persistentRootsPendingDeletion and
_persistentRootsPendingUndeletion and unload
- persistent roots. */
-
- for (COPersistentRoot *persistentRoot in persistentRoots)
- {
- if ([_persistentRootsPendingDeletion containsObject:
persistentRoot])
- {
- [_persistentRootsPendingDeletion removeObject: persistentRoot];
-
- [self unloadPersistentRoot: persistentRoot];
- }
- else if ([_persistentRootsPendingUndeletion containsObject:
persistentRoot])
- {
- [_persistentRootsPendingUndeletion removeObject: persistentRoot];
- }
- }
-
+ if (_inCommit)
+ {
+ [NSException raise: NSGenericException
+ format: @"%@ called recursively",
NSStringFromSelector(_cmd)];
+ }
+
+ @try
+ {
+ _inCommit = YES;
+ [self validateMetadata: metadata];
+
+ // TODO: We could organize validation errors by persistent
root. Each
+ // persistent root might result in a validation error that
contains a
+ // suberror per inner object, then each suberror could in turn
contain
+ // a suberror per validation result. For now, we just aggregate
errors per
+ // inner object.
+ if ([self validateChangedObjectsForContext: self error:
anError] == NO)
+ return NO;
+
+ /* Commit persistent root changes (deleted persistent roots
included) */
+
+ COStoreTransaction *transaction = [[COStoreTransaction alloc]
init];
+ [self recordBeginUndoGroupWithMetadata: metadata];
+
+ for (COPersistentRoot *persistentRoot in persistentRoots)
+ {
+ [persistentRoot saveCommitWithMetadata: metadata
transaction: transaction];
+ }
+
+ /* Add persistent root deletions to the transaction */
+
+ for (COPersistentRoot *persistentRoot in persistentRoots)
+ {
+ ETUUID *uuid = [persistentRoot UUID];
+
+ if ([_persistentRootsPendingDeletion containsObject:
persistentRoot])
+ {
+ [transaction deletePersistentRoot: uuid];
+ [self recordPersistentRootDeletion:
persistentRoot];
+ }
+ else if ([_persistentRootsPendingUndeletion
containsObject: persistentRoot])
+ {
+ [transaction undeletePersistentRoot: uuid];
+ [self recordPersistentRootUndeletion:
persistentRoot];
+ }
+ }
+
+ /* Update transaction IDs (can't add to the transaction after
this) */
+
+ for (ETUUID *uuid in [transaction persistentRootUUIDs])
+ {
+ COPersistentRoot *persistentRoot = [self
persistentRootForUUID: uuid];
+
+ persistentRoot.lastTransactionID = [transaction
setOldTransactionID: persistentRoot.lastTransactionID
+
forPersistentRoot: uuid];
+ }
+
+ /* Update _persistentRootsPendingDeletion and
_persistentRootsPendingUndeletion and unload
+ persistent roots. */
+
+ for (COPersistentRoot *persistentRoot in persistentRoots)
+ {
+ if ([_persistentRootsPendingDeletion containsObject:
persistentRoot])
+ {
+ [_persistentRootsPendingDeletion removeObject:
persistentRoot];
- ETAssert([_store commitStoreTransaction: transaction]);
- COCommandGroup *command = [self recordEndUndoGroupWithUndoTrack: track];
-
- /* For a commit triggered by undo/redo on a COUndoTrack, the command is
nil */
- [self didCommitWithCommand: command persistentRoots: persistentRoots];
-
- if (anError != NULL)
- {
- *anError = nil;
+ [self unloadPersistentRoot: persistentRoot];
+ }
+ else if ([_persistentRootsPendingUndeletion
containsObject: persistentRoot])
+ {
+ [_persistentRootsPendingUndeletion
removeObject: persistentRoot];
+ }
+ }
+
+
+ ETAssert([_store commitStoreTransaction: transaction]);
+ COCommandGroup *command = [self
recordEndUndoGroupWithUndoTrack: track];
+
+ /* For a commit triggered by undo/redo on a COUndoTrack, the
command is nil */
+ [self didCommitWithCommand: command persistentRoots:
persistentRoots];
+
+ if (anError != NULL)
+ {
+ *anError = nil;
+ }
+ }
+ @finally
+ {
+ _inCommit = NO;
}
return YES;
}
Modified: trunk/Etoile/Frameworks/CoreObject/Tests/Core/TestEditingContext.m
URL:
http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Frameworks/CoreObject/Tests/Core/TestEditingContext.m?rev=10660&r1=10659&r2=10660&view=diff
==============================================================================
--- trunk/Etoile/Frameworks/CoreObject/Tests/Core/TestEditingContext.m
(original)
+++ trunk/Etoile/Frameworks/CoreObject/Tests/Core/TestEditingContext.m Sat Mar
29 23:04:46 2014
@@ -280,4 +280,27 @@
UKRaisesException([r2cxt2 parentRevision]);
}
+- (void) testCommitWithinCommitNotificationIllegal
+{
+ __block BOOL receivedNotification = NO;
+ __block BOOL insideCommit = NO;
+
+ [[NSNotificationCenter defaultCenter] addObserverForName:
COEditingContextDidChangeNotification
+
object: ctx
+
queue: nil
+
usingBlock: ^(NSNotification *notif) {
+
receivedNotification = YES;
+
UKTrue(insideCommit);
+
UKRaisesException([ctx commit]);
+
}];
+
+ COPersistentRoot *persistentRoot = [ctx
insertNewPersistentRootWithEntityName: @"Anonymous.OutlineItem"];
+
+ insideCommit = YES;
+ [ctx commit];
+ insideCommit = NO;
+
+ UKTrue(receivedNotification);
+}
+
@end
Modified: trunk/Etoile/Frameworks/CoreObject/Tests/TestCommon.m
URL:
http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Frameworks/CoreObject/Tests/TestCommon.m?rev=10660&r1=10659&r2=10660&view=diff
==============================================================================
--- trunk/Etoile/Frameworks/CoreObject/Tests/TestCommon.m (original)
+++ trunk/Etoile/Frameworks/CoreObject/Tests/TestCommon.m Sat Mar 29
23:04:46 2014
@@ -227,7 +227,7 @@
{
[FMDatabase logOpenDatabases];
- const int expectedOpenDatabases = 3;
+ const int expectedOpenDatabases = 4;
if ([FMDatabase countOfOpenDatabases] > expectedOpenDatabases)
{
NSLog(@"ERROR: Expected only %d SQLite database
connections to still be open.", expectedOpenDatabases);
_______________________________________________
Etoile-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/etoile-cvs