Skip to content

Commit

Permalink
Merge pull request Codeux-Software#307 from demosdemon/MessageQueue
Browse files Browse the repository at this point in the history
Redo Message Queue system, did not handle bouncer floods very well
  • Loading branch information
Michael Morris committed Aug 7, 2012
2 parents 5dd96be + 44204a8 commit a62ce8d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 158 deletions.
16 changes: 12 additions & 4 deletions Classes/Headers/IRCWorld.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@
@property (nonatomic, strong) NSDictionary *bundlesForUserInput;
@property (nonatomic, strong) NSDictionary *bundlesForServerInput;
@property (nonatomic, strong) NSDictionary *bundlesWithOutputRules;
@property (nonatomic, assign) dispatch_queue_t frontmostViewMessageQueue;
@property (nonatomic, assign) dispatch_queue_t backgroundViewMessageQueue;
@property (nonatomic, strong) NSOperationQueue *messageOperationQueue;

- (void)setup:(IRCWorldConfig *)seed;
- (void)setupTree;
Expand All @@ -91,8 +90,6 @@
- (void)terminate;
- (void)prepareForSleep;

- (void)runMessageQueueLoop:(TVCLogController *)sender;

- (IRCClient *)findClient:(NSString *)name;
- (IRCClient *)findClientById:(NSInteger)uid;
- (IRCChannel *)findChannelByClientId:(NSInteger)uid channelId:(NSInteger)cid;
Expand Down Expand Up @@ -150,4 +147,15 @@
- (void)destroyAllEvidence;

- (TVCLogController *)createLogWithClient:(IRCClient *)client channel:(IRCChannel *)channel;
@end

@interface TKMessageBlockOperation : NSOperation
@property (nonatomic, retain) TVCLogController *controller;
@property (nonatomic, assign) BOOL special;
+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block
forController:(TVCLogController *)controller
withSpecialPriority:(BOOL)special;
+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block
forController:(TVCLogController *)controller;
+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block;
@end
10 changes: 4 additions & 6 deletions Classes/Headers/TVCLogController.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ typedef id (^TVCLogMessageBlock)(void);
@property (nonatomic, assign) NSInteger lastVisitedHighlight;
@property (nonatomic, strong) NSMutableArray *highlightedLineNumbers;

@property (strong) NSMutableArray *normalMessageQueue; // Priority: Low
@property (strong) NSMutableArray *specialMessageQueue; // Priority: High
@property (assign) BOOL queueInProgress;

- (void)setUp;
- (void)restorePosition;
- (void)notifyDidBecomeVisible;
Expand All @@ -85,8 +81,6 @@ typedef id (^TVCLogMessageBlock)(void);
- (void)moveToTop;
- (void)moveToBottom;

- (void)runMessageQueueLoop; // Only Textual should call this.

- (void)setTopic:(NSString *)topic;

- (void)mark;
Expand All @@ -105,4 +99,8 @@ typedef id (^TVCLogMessageBlock)(void);
- (NSString *)renderedBodyForTranscriptLog:(TVCLogLine *)line;

- (void)logViewOnDoubleClick:(NSString *)e;

- (void)handleMessageBlock:(id)block isSpecial:(BOOL)special;
- (void)enqueueMessageBlock:(id)messageBlock fromSender:(TVCLogController *)sender isSpecial:(BOOL)special;
- (void)enqueueMessageBlock:(id)messageBlock fromSender:(TVCLogController *)sender;
@end
104 changes: 53 additions & 51 deletions Classes/IRC/IRCWorld.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ - (id)init
{
if ((self = [super init])) {
self.clients = [NSMutableArray new];

self.frontmostViewMessageQueue = dispatch_queue_create("frontmostViewMessageQueue", NULL);
self.backgroundViewMessageQueue = dispatch_queue_create("backgroundViewMessageQueue", NULL);

self.messageOperationQueue = [NSOperationQueue new];
self.messageOperationQueue.name = @"IRCWordMessageOperationQueue";
self.messageOperationQueue.maxConcurrentOperationCount = 1;
// Only 1 at a time or else we get a race condition and out of order messages
}

return self;
Expand All @@ -63,12 +65,6 @@ - (id)init
- (void)dealloc
{
[NSBundle deallocBundlesFromMemory:self];

dispatch_release(self.frontmostViewMessageQueue);
self.frontmostViewMessageQueue = nil;

dispatch_release(self.backgroundViewMessageQueue);
self.backgroundViewMessageQueue = nil;
}

- (void)setup:(IRCWorldConfig *)seed
Expand Down Expand Up @@ -151,47 +147,6 @@ - (void)setChannelMenuItem:(NSMenuItem *)item
self.channelMenu = [item.submenu copy];
}

#pragma mark -
#pragma mark View Run Loop

- (void)fireMessageQueue:(TVCLogController *)log
{
if (log.normalMessageQueue.count >= 25 ||
log.specialMessageQueue.count >= 25) {

static dispatch_once_t once;

/* Not 100% sure dispatch_once is
designed to do something like this. */
dispatch_once(&once, ^{
[log runMessageQueueLoop];
});
} else {
[log runMessageQueueLoop];
}
}

- (void)runMessageQueueLoop:(TVCLogController *)sender
{
if (sender.queueInProgress) {
return; // Do not even add to queue if its already running…
}

TVCLogController *active = self.selected.log;

if (PointerIsNotEmpty(active)) {
if (NSDissimilarObjects(sender, self.selected.log)) {
dispatch_async(self.backgroundViewMessageQueue, ^{
[self fireMessageQueue:sender];
});
} else {
dispatch_async(self.frontmostViewMessageQueue, ^{
[self fireMessageQueue:sender];
});
}
}
}

#pragma mark -
#pragma mark Properties

Expand Down Expand Up @@ -1398,4 +1353,51 @@ - (void)serverListKeyDown:(NSEvent *)e
[self logKeyDown:e];
}

@end
@end

@implementation TKMessageBlockOperation
+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block
forController:(TVCLogController *)controller
withSpecialPriority:(BOOL)special
{
TKMessageBlockOperation * retval = [TKMessageBlockOperation new];
retval.completionBlock = block;
retval.controller = controller;
retval.special = special;
retval.queuePriority = retval.priority;
return retval;
}

+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block
forController:(TVCLogController *)controller
{ return [self operationWithBlock:block forController:controller withSpecialPriority:NO]; }

+ (TKMessageBlockOperation *) operationWithBlock:(void(^)(void))block
{ return [self operationWithBlock:block forController:nil withSpecialPriority:NO]; }

- (id) init
{
if (self = [super init]) {
self.special = NO;
}
return self;
}

- (NSOperationQueuePriority) priority
{
if (!self.controller) return NSOperationQueuePriorityVeryHigh;
id target = self.controller.channel ?: self.controller.client;
id selected = self.controller.world.selected;
NSOperationQueuePriority retval = NSOperationQueuePriorityLow;

if ((target || selected) && target == selected) retval += 4L;
if (self.special) retval += 4L;
return retval;
}

- (BOOL) isReady
{
if (!self.controller) return YES;
return ([self.controller.view isLoading] == NO);
}
@end
138 changes: 41 additions & 97 deletions Classes/Views/Channel View/TVCLogController.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ - (id)init
self.bottom = YES;
self.maxLines = 300;

self.normalMessageQueue = [NSMutableArray new];
self.specialMessageQueue = [NSMutableArray new];
self.highlightedLineNumbers = [NSMutableArray new];

[[WebPreferences standardPreferences] setCacheModel:WebCacheModelDocumentViewer];
Expand Down Expand Up @@ -127,86 +125,6 @@ - (void)setUp
self.view.shouldUpdateWhileOffscreen = NO;

[self loadAlternateHTML:[self initialDocument:nil]];

self.queueInProgress = NO;
}

#pragma mark -

- (void)runMessageQueueLoop
{
self.queueInProgress = YES;

[self runMessageQueueLoop:self.specialMessageQueue honorLoopDelay:NO];
[self runMessageQueueLoop:self.normalMessageQueue honorLoopDelay:YES];

self.queueInProgress = NO;
}

- (void)runMessageQueueLoop:(NSMutableArray *)messageQueue honorLoopDelay:(BOOL)delayLoop
{
NSMutableString *result;

if (delayLoop == NO) {
result = [NSMutableString string];
}

while (NSObjectIsNotEmpty(messageQueue)) {
dispatch_async(dispatch_get_main_queue(), ^{
if (NSObjectIsNotEmpty(messageQueue)) {
if ([self.view isLoading] == NO) {
// Internally, TVCLogMessageBlock should only return a
// BOOL as NSValue or NSString absolute value.

BOOL rrslt = NO;

// ---- //

id stslt = ((TVCLogMessageBlock)messageQueue[0])();

// ---- //

if ([stslt isKindOfClass:NSString.class]) {
if (PointerIsNotEmpty(stslt)) {
if (delayLoop == NO) {
[result appendString:stslt];
} else {
[self appendToDocumentBody:stslt];
}

rrslt = YES;
}
} else {
rrslt = [stslt boolValue];
}

// ---- //

if (rrslt) {
[messageQueue removeObjectAtIndex:0];
}
}
}
});

// ---- //

if (delayLoop) {
if (self.channel) {
[NSThread sleepForTimeInterval:[TPCPreferences viewLoopChannelDelay]];
} else {
[NSThread sleepForTimeInterval:[TPCPreferences viewLoopConsoleDelay]];
}
}
}

// ---- //

if (delayLoop == NO && NSObjectIsNotEmpty(result)) {
dispatch_async(dispatch_get_main_queue(), ^{
[self appendToDocumentBody:result];
});
}
}

#pragma mark -
Expand Down Expand Up @@ -331,9 +249,7 @@ - (void)setTopic:(NSString *)topic
return @(YES);
} copy];

[self.normalMessageQueue safeAddObject:messageBlock];

[self.world runMessageQueueLoop:self];
[self enqueueMessageBlock:messageBlock fromSender:self];
}

#pragma mark -
Expand Down Expand Up @@ -438,10 +354,7 @@ - (void)mark

return @(YES);
} copy];

[self.normalMessageQueue safeAddObject:messageBlock];

[self.world runMessageQueueLoop:self];
[self enqueueMessageBlock:messageBlock fromSender:self];
}

- (void)unmark
Expand All @@ -464,10 +377,7 @@ - (void)unmark

return @(YES);
} copy];

[self.normalMessageQueue safeAddObject:messageBlock];

[self.world runMessageQueueLoop:self];
[self enqueueMessageBlock:messageBlock fromSender:self];
}

- (void)goToMark
Expand Down Expand Up @@ -989,16 +899,50 @@ - (void)writeLine:(id)line

return nil;
} copy];
[self enqueueMessageBlock:messageBlock fromSender:self isSpecial:isSpecial];
}

- (void)enqueueMessageBlock:(id)messageBlock fromSender:(TVCLogController *)sender
{ [self enqueueMessageBlock:messageBlock fromSender:sender isSpecial:NO]; }

- (void)enqueueMessageBlock:(id)messageBlock fromSender:(TVCLogController *)sender isSpecial:(BOOL)special
{
[self.world.messageOperationQueue addOperation:[TKMessageBlockOperation operationWithBlock:^{
[sender handleMessageBlock:messageBlock isSpecial:special];
} forController:sender withSpecialPriority:special]];
}

- (void) handleMessageBlock:(id)messageBlock isSpecial:(BOOL)special
{
// Internally, TVCLogMessageBlock should only return a
// BOOL as NSValue or NSString absolute value.

BOOL rrslt = NO;

// ---- //

if (isSpecial) {
[self.specialMessageQueue safeAddObject:messageBlock];
__block id stslt = nil;

dispatch_sync(dispatch_get_main_queue(), ^{
stslt = ((TVCLogMessageBlock)messageBlock)();
});

// ---- //

if ([stslt isKindOfClass:NSString.class]) {
if (PointerIsNotEmpty(stslt)) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self appendToDocumentBody:stslt];
}];
rrslt = YES;
}
} else {
[self.normalMessageQueue safeAddObject:messageBlock];
rrslt = [stslt boolValue];
}

[self.world runMessageQueueLoop:self];
// ---- //

if (!rrslt) [self enqueueMessageBlock:messageBlock fromSender:self isSpecial:special];
}

#pragma mark -
Expand Down

0 comments on commit a62ce8d

Please sign in to comment.