You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/12/21 04:23:39 UTC

ios commit: CB-3359 Parse large JSON payloads on a background thread, and yield when executing multiple commands is taking too long.

Updated Branches:
  refs/heads/master d6fd0afdc -> 3c6ba75e6


CB-3359 Parse large JSON payloads on a background thread, and yield when executing multiple commands is taking too long.

This doesn't solve large payloads, but does help with locking up the
main thread.
It also prevents locking up the main thread when every exec callback
results in another call to exec().


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/3c6ba75e
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/3c6ba75e
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/3c6ba75e

Branch: refs/heads/master
Commit: 3c6ba75e6e00eb3e3647e27247a20aa7253781f1
Parents: d6fd0af
Author: Andrew Grieve <ag...@chromium.org>
Authored: Fri Dec 20 22:20:36 2013 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Dec 20 22:20:36 2013 -0500

----------------------------------------------------------------------
 CordovaLib/Classes/CDVCommandQueue.m | 63 ++++++++++++++++++++++++-------
 CordovaLib/Classes/CDVJSON.m         |  2 +-
 2 files changed, 50 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/3c6ba75e/CordovaLib/Classes/CDVCommandQueue.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandQueue.m b/CordovaLib/Classes/CDVCommandQueue.m
index 1491073..902dfa0 100644
--- a/CordovaLib/Classes/CDVCommandQueue.m
+++ b/CordovaLib/Classes/CDVCommandQueue.m
@@ -23,17 +23,25 @@
 #import "CDVViewController.h"
 #import "CDVCommandDelegateImpl.h"
 
+// Parse JS on the main thread if it's shorter than this.
+static const NSInteger JSON_SIZE_FOR_MAIN_THREAD = 4 * 1024; // Chosen arbitrarily.
+// Execute multiple commands in one go until this many seconds have passed.
+static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame.
+
 @interface CDVCommandQueue () {
     NSInteger _lastCommandQueueFlushRequestId;
     __weak CDVViewController* _viewController;
     NSMutableArray* _queue;
-    BOOL _currentlyExecuting;
+    NSTimeInterval _startExecutionTime;
 }
 @end
 
 @implementation CDVCommandQueue
 
-@synthesize currentlyExecuting = _currentlyExecuting;
+- (BOOL)currentlyExecuting
+{
+    return _startExecutionTime > 0;
+}
 
 - (id)initWithViewController:(CDVViewController*)viewController
 {
@@ -59,7 +67,19 @@
 - (void)enqueueCommandBatch:(NSString*)batchJSON
 {
     if ([batchJSON length] > 0) {
-        [_queue addObject:batchJSON];
+        NSMutableArray* commandBatchHolder = [[NSMutableArray alloc] init];
+        [_queue addObject:commandBatchHolder];
+        if ([batchJSON length] < JSON_SIZE_FOR_MAIN_THREAD) {
+            [commandBatchHolder addObject:[batchJSON JSONObject]];
+        } else {
+            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
+                    NSMutableArray* result = [batchJSON JSONObject];
+                    @synchronized(commandBatchHolder) {
+                        [commandBatchHolder addObject:result];
+                    }
+                    [self performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO];
+                });
+        }
     }
 }
 
@@ -100,19 +120,30 @@
 - (void)executePending
 {
     // Make us re-entrant-safe.
-    if (_currentlyExecuting) {
+    if (_startExecutionTime > 0) {
         return;
     }
     @try {
-        _currentlyExecuting = YES;
-
-        for (NSUInteger i = 0; i < [_queue count]; ++i) {
-            // Parse the returned JSON array.
-            NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject];
+        _startExecutionTime = [NSDate timeIntervalSinceReferenceDate];
+
+        while ([_queue count] > 0) {
+            NSMutableArray* commandBatchHolder = _queue[0];
+            NSMutableArray* commandBatch = nil;
+            @synchronized(commandBatchHolder) {
+                // If the next-up command is still being decoded, wait for it.
+                if ([commandBatchHolder count] == 0) {
+                    break;
+                }
+                commandBatch = commandBatchHolder[0];
+            }
 
-            // Iterate over and execute all of the commands.
-            for (NSArray* jsonEntry in commandBatch) {
+            while ([commandBatch count] > 0) {
                 @autoreleasepool {
+                    // Execute the commands one-at-a-time.
+                    NSArray* jsonEntry = [commandBatch dequeue];
+                    if ([commandBatch count] == 0) {
+                        [_queue removeObjectAtIndex:0];
+                    }
                     CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
                     CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);
 
@@ -128,13 +159,17 @@
 #endif
                     }
                 }
+
+                // Yield if we're taking too long.
+                if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) {
+                    [self performSelector:@selector(executePending) withObject:nil afterDelay:0];
+                    return;
+                }
             }
         }
-
-        [_queue removeAllObjects];
     } @finally
     {
-        _currentlyExecuting = NO;
+        _startExecutionTime = 0;
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/3c6ba75e/CordovaLib/Classes/CDVJSON.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVJSON.m b/CordovaLib/Classes/CDVJSON.m
index 78267e5..f42dfae 100644
--- a/CordovaLib/Classes/CDVJSON.m
+++ b/CordovaLib/Classes/CDVJSON.m
@@ -64,7 +64,7 @@
 {
     NSError* error = nil;
     id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
-                                                options:kNilOptions
+                                                options:NSJSONReadingMutableContainers
                                                   error:&error];
 
     if (error != nil) {