adium-1.4 3161:c959997fcffb: Delay list object notifications as ...

commits at adium.im commits at adium.im
Sat Oct 30 04:47:31 UTC 2010


details:	http://hg.adium.im/adium-1.4/rev/c959997fcffb
revision:	3161:c959997fcffb
author:		Evan Schoenberg
date:		Fri Oct 29 23:44:34 2010 -0500

Delay list object notifications as libpurple initializes; it can be expensive in terms of adding contacts from the permit and deny lists. Also, include a delayListObjectNotificationsUntilInactivity call as a few behaviors occur on the next runloop
Subject: adium-1.4 3162:cbd40f45797a: Several fixes related to listObjectAttributesChanged:

details:	http://hg.adium.im/adium-1.4/rev/cbd40f45797a
revision:	3162:cbd40f45797a
author:		Evan Schoenberg
date:		Fri Oct 29 23:47:23 2010 -0500

Several fixes related to listObjectAttributesChanged:
 * Fix an abysmal bug in which we were deliberately calling _performDelayedUpdates: when shouldDelayUpdates was YES instead of when it was NO
 * Add a ListObject_AttributeChangesComplete notification to let us distinguish a change for a particular object (which always notifies for that object) from a group of changes which should trigger a display update.
 * Add a grace period for delayListObjectNotificationsUntilInactivity; previously a 1 second delay was enough to make all delays stop, which was bad if we had a network halt during a connection as subsequent contacts would appear to sign on one-by-one, with all the costs that entails.  The grace period is 3 seconds.

diffs (247 lines):

diff -r a3fcb0d5b61e -r cbd40f45797a Frameworks/Adium Framework/Source/AIAbstractListController.h
--- a/Frameworks/Adium Framework/Source/AIAbstractListController.h	Fri Oct 29 22:36:16 2010 -0500
+++ b/Frameworks/Adium Framework/Source/AIAbstractListController.h	Fri Oct 29 23:47:23 2010 -0500
@@ -218,7 +218,7 @@
 - (void)updateLayoutFromPrefDict:(NSDictionary *)prefDict andThemeFromPrefDict:(NSDictionary *)themeDict;
 - (void)updateCellRelatedThemePreferencesFromDict:(NSDictionary *)prefDict;
 
-- (void)listObjectAttributesChanged:(NSNotification *)notification;
+- (void)listObjectAttributeChangesComplete:(NSNotification *)notification;
 - (void)contactListDesiredSizeChanged;
 - (void)updateTransparency;
 - (BOOL)useAliasesInContactListAsRequested;
diff -r a3fcb0d5b61e -r cbd40f45797a Frameworks/Adium Framework/Source/AIAbstractListController.m
--- a/Frameworks/Adium Framework/Source/AIAbstractListController.m	Fri Oct 29 22:36:16 2010 -0500
+++ b/Frameworks/Adium Framework/Source/AIAbstractListController.m	Fri Oct 29 23:47:23 2010 -0500
@@ -96,8 +96,8 @@
 										 object:nil];
 		
 		[[NSNotificationCenter defaultCenter] addObserver:self
-									   selector:@selector(listObjectAttributesChanged:)
-										   name:ListObject_AttributesChanged
+									   selector:@selector(listObjectAttributeChangesComplete:)
+										   name:ListObject_AttributeChangesComplete
 										 object:nil];
 		
 		[[NSNotificationCenter defaultCenter] addObserver:self
@@ -577,12 +577,12 @@
  *
  * Redisplay the object in question
  */
-- (void)listObjectAttributesChanged:(NSNotification *)notification
+- (void)listObjectAttributeChangesComplete:(NSNotification *)notification
 {
     AIListObject	*object = [notification object];
 
 	static int listObjectAttributesChangedNum = 0;
-	NSLog(@"listObjectAttributesChanged #%i: %@ [%@]",
+	NSLog(@"listObjectAttributeChangesComplete #%i: %@ [%@]",
 		  ++listObjectAttributesChangedNum,
 		  object, [[notification userInfo] objectForKey:@"Keys"]);
 
diff -r a3fcb0d5b61e -r cbd40f45797a Frameworks/Adium Framework/Source/AIContactControllerProtocol.h
--- a/Frameworks/Adium Framework/Source/AIContactControllerProtocol.h	Fri Oct 29 22:36:16 2010 -0500
+++ b/Frameworks/Adium Framework/Source/AIContactControllerProtocol.h	Fri Oct 29 23:47:23 2010 -0500
@@ -11,7 +11,13 @@
 @class AIListObject, AIListContact, AIChat;
 @protocol AIContainingObject;
 
+/* Posted for a single object whose attributes changed */
 #define ListObject_AttributesChanged			@"ListObject_AttributesChanged"
+
+/* Called when one or more ListObject_AttributesChanged notifications are done and all delays have cleared.
+ * We're ready to update the display at this point. */
+#define ListObject_AttributeChangesComplete			@"ListObject_AttributeChangesComplete"
+
 #define ListObject_StatusChanged				@"ListObject_StatusChanged"
 #define Contact_OrderChanged					@"Contact_OrderChanged"
 #define Contact_ListChanged						@"Contact_ListChanged"
diff -r a3fcb0d5b61e -r cbd40f45797a Frameworks/Adium Framework/Source/AIContactObserverManager.h
--- a/Frameworks/Adium Framework/Source/AIContactObserverManager.h	Fri Oct 29 22:36:16 2010 -0500
+++ b/Frameworks/Adium Framework/Source/AIContactObserverManager.h	Fri Oct 29 23:47:23 2010 -0500
@@ -26,6 +26,9 @@
 	NSMutableSet			*contactObservers;
 	NSMutableSet			*removedContactObservers;
 	NSTimer					*delayedUpdateTimer;
+	NSInteger				quietDelayedUpdatePeriodsRemaining;
+	
+	
 	NSInteger				delayedStatusChanges;
 	NSMutableSet			*delayedModifiedStatusKeys;
 	NSInteger				delayedAttributeChanges;
diff -r a3fcb0d5b61e -r cbd40f45797a Frameworks/Adium Framework/Source/AIContactObserverManager.m
--- a/Frameworks/Adium Framework/Source/AIContactObserverManager.m	Fri Oct 29 22:36:16 2010 -0500
+++ b/Frameworks/Adium Framework/Source/AIContactObserverManager.m	Fri Oct 29 23:47:23 2010 -0500
@@ -119,7 +119,7 @@
 {
 	if (delayedUpdateRequests > 0) {
 		delayedUpdateRequests--;
-		if ([self shouldDelayUpdates])
+		if (![self shouldDelayUpdates])
 			[self _performDelayedUpdates:nil];
 	}
 }
@@ -146,6 +146,9 @@
 		BOOL restoreDelayUntilInactivity = (self.delayedUpdateTimer != nil);
 		
 		[self.delayedUpdateTimer invalidate]; self.delayedUpdateTimer = nil;
+
+		NSLog(@"endListObjectNotificationsDelaysImmediately");
+
 		[self _performDelayedUpdates:nil];
 		
 		/* After immediately performing updates as requested, go back to delaying until inactivity if that was the
@@ -156,10 +159,13 @@
 	}
 }
 
+#define QUIET_DELAYED_UPDATE_PERIODS 3
+
 //Delay all list object notifications until a period of inactivity occurs.  This is useful for accounts that do not
 //know when they have finished connecting but still want to mute events.
 - (void)delayListObjectNotificationsUntilInactivity
 {
+	NSLog(@"*** Begin grouping delay ***");
     if (!delayedUpdateTimer) {
 		updatesAreDelayedUntilInactivity = YES;
 		self.delayedUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_CLUMP_INTERVAL
@@ -167,9 +173,12 @@
 																 selector:@selector(_performDelayedUpdates:)
 																 userInfo:nil
 																  repeats:YES];
+		quietDelayedUpdatePeriodsRemaining = QUIET_DELAYED_UPDATE_PERIODS; 
+
     } else {
 		//Reset the timer
 		[delayedUpdateTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:UPDATE_CLUMP_INTERVAL]];
+		quietDelayedUpdatePeriodsRemaining = QUIET_DELAYED_UPDATE_PERIODS;
 	}
 }
 
@@ -226,7 +235,8 @@
 //(When modifying display attributes in response to a status change, this is not necessary)
 - (void)listObjectAttributesChanged:(AIListObject *)inObject modifiedKeys:(NSSet *)inModifiedKeys
 {
-	if ([self shouldDelayUpdates]) {
+	BOOL shouldDelay = [self shouldDelayUpdates];
+	if (shouldDelay) {
 		delayedAttributeChanges++;
 		[delayedModifiedAttributeKeys unionSet:inModifiedKeys];
 	} else {
@@ -238,11 +248,20 @@
 
 	//Post an attributes changed message
 	[[NSNotificationCenter defaultCenter] postNotificationName:ListObject_AttributesChanged
-											  object:inObject
-											userInfo:(inModifiedKeys ?
-													  [NSDictionary dictionaryWithObject:inModifiedKeys
-																				  forKey:@"Keys"] :
-													  nil)];	
+														object:inObject
+													  userInfo:(inModifiedKeys ?
+																[NSDictionary dictionaryWithObject:inModifiedKeys
+																							forKey:@"Keys"] :
+																nil)];
+	 
+	if (!shouldDelay) {
+		NSLog(@"Immediate ListObject_AttributeChangesComplete for %@", inObject);
+		/* Note that we completed 1 or more delayed attribute changes */
+		[[NSNotificationCenter defaultCenter] postNotificationName:ListObject_AttributeChangesComplete
+															object:inObject
+														  userInfo:[NSDictionary dictionaryWithObject:inModifiedKeys
+																							   forKey:@"Keys"]];
+	}
 }
 
 //Performs any delayed list object/handle updates
@@ -251,7 +270,8 @@
 	BOOL	updatesOccured = (delayedStatusChanges || delayedAttributeChanges || delayedContactChanges);
 	
 	static int updatesDone = 0;
-	
+	NSLog(@"_performDelayedUpdates %p: %i", timer, ++updatesDone);
+
 	//Send out global attribute & status changed notifications (to cover any delayed updates)
 	if (updatesOccured) {
 		BOOL shouldSort = NO;
@@ -274,6 +294,13 @@
 				[[AISortController activeSortController] shouldSortForModifiedAttributeKeys:delayedModifiedAttributeKeys]) {
 				shouldSort = YES;
 			}
+			
+			/* Note that we completed 1 or more delayed attribute changes; the precise object isn't known */
+			[[NSNotificationCenter defaultCenter] postNotificationName:ListObject_AttributeChangesComplete
+																object:nil
+															  userInfo:[NSDictionary dictionaryWithObject:delayedModifiedAttributeKeys
+																								   forKey:@"Keys"]];
+			 
 			[delayedModifiedAttributeKeys removeAllObjects];
 			delayedAttributeChanges = 0;
 		}
@@ -287,10 +314,12 @@
     //If no more updates are left to process, disable the update timer
 	//If there are no delayed update requests, remove the hold
 	if (!delayedUpdateTimer || !updatesOccured) {
-		if (delayedUpdateTimer) {
+		if (delayedUpdateTimer && (quietDelayedUpdatePeriodsRemaining-- <= 0)) {
 			[delayedUpdateTimer invalidate];
 			self.delayedUpdateTimer = nil;
 			updatesAreDelayedUntilInactivity = NO;
+			
+			NSLog(@"The delayedUpdateTimer has EXPIRED");
 		}
     }
 
diff -r a3fcb0d5b61e -r cbd40f45797a Plugins/Purple Service/SLPurpleCocoaAdapter.m
--- a/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Fri Oct 29 22:36:16 2010 -0500
+++ b/Plugins/Purple Service/SLPurpleCocoaAdapter.m	Fri Oct 29 23:47:23 2010 -0500
@@ -31,6 +31,7 @@
 #import <Adium/AIContentTyping.h>
 #import <Adium/AIHTMLDecoder.h>
 #import <Adium/AIListContact.h>
+#import <Adium/AIContactObserverManager.h>
 #import <Adium/AIUserIcons.h>
 #import <AIUtilities/AIImageAdditions.h>
 
@@ -163,6 +164,11 @@
 
 - (void)initLibPurple
 {
+	/* Initializing libpurple may result in loading a ton of buddies if our permit and deny lists are large; that, in
+	 * turn, would create and update a ton of contacts.
+	 */
+	[[AIContactObserverManager sharedManager] delayListObjectNotifications];
+	
 	//Set the gaim user directory to be within this user's directory
 	if (![[NSUserDefaults standardUserDefaults] boolForKey:@"Adium 1.0.3 moved to libpurple"]) {
 		//Remove old icons cache
@@ -219,6 +225,14 @@
 								   selector:@selector(networkDidChange:)
 									   name:AINetworkDidChangeNotification
 									 object:nil];
+
+	/* For any behaviors which occur on the next run loop, provide a buffer time of continued expectation of 
+	 * heavy activity.
+	 */
+	[[AIContactObserverManager sharedManager] delayListObjectNotificationsUntilInactivity];
+	
+	[[AIContactObserverManager sharedManager] endListObjectNotificationsDelay];
+
 }
 
 #pragma mark Lookup functions
diff -r a3fcb0d5b61e -r cbd40f45797a Source/AIListController.m
--- a/Source/AIListController.m	Fri Oct 29 22:36:16 2010 -0500
+++ b/Source/AIListController.m	Fri Oct 29 23:47:23 2010 -0500
@@ -433,9 +433,9 @@
  *
  * Resize horizontally if desired and the display name changed
  */
-- (void)listObjectAttributesChanged:(NSNotification *)notification
+- (void)listObjectAttributeChangesComplete:(NSNotification *)notification
 {	
-	[super listObjectAttributesChanged:notification];
+	[super listObjectAttributeChangesComplete:notification];
 	
 	if (((AIListObject *)notification.object).isStranger)
 		return;




More information about the commits mailing list