aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/objective-c/GRPCClient
diff options
context:
space:
mode:
Diffstat (limited to 'src/objective-c/GRPCClient')
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m58
-rw-r--r--src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.h61
-rw-r--r--src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m52
-rw-r--r--src/objective-c/GRPCClient/private/GRPCOpBatchLog.h59
-rw-r--r--src/objective-c/GRPCClient/private/GRPCOpBatchLog.m72
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.m8
6 files changed, 302 insertions, 8 deletions
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 44393f6b99..051138ea4d 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -36,6 +36,7 @@
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
+#import <RxLibrary/GRXImmediateSingleWriter.h>
#import "private/GRPCConnectivityMonitor.h"
#import "private/GRPCHost.h"
@@ -45,6 +46,11 @@
#import "private/NSDictionary+GRPC.h"
#import "private/NSError+GRPC.h"
+// At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA,
+// SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE,
+// and RECV_STATUS_ON_CLIENT.
+NSInteger kMaxClientBatch = 6;
+
NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey";
NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
static NSMutableDictionary *callFlags;
@@ -100,6 +106,13 @@ static NSMutableDictionary *callFlags;
GRPCCall *_retainSelf;
GRPCRequestHeaders *_requestHeaders;
+
+ // In the case that the call is a unary call (i.e. the writer to GRPCCall is of type
+ // GRXImmediateSingleWriter), GRPCCall will delay sending ops (not send them to C core
+ // immediately) and buffer them into a batch _unaryOpBatch. The batch is sent to C core when
+ // the SendClose op is added.
+ BOOL _unaryCall;
+ NSMutableArray *_unaryOpBatch;
}
@synthesize state = _state;
@@ -157,6 +170,11 @@ static NSMutableDictionary *callFlags;
_requestWriter = requestWriter;
_requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self];
+
+ if ([requestWriter isKindOfClass:[GRXImmediateSingleWriter class]]) {
+ _unaryCall = YES;
+ _unaryOpBatch = [NSMutableArray arrayWithCapacity:kMaxClientBatch];
+ }
}
return self;
}
@@ -165,6 +183,9 @@ static NSMutableDictionary *callFlags;
- (void)finishWithError:(NSError *)errorOrNil {
@synchronized(self) {
+ if (_state == GRXWriterStateFinished) {
+ return;
+ }
_state = GRXWriterStateFinished;
}
@@ -254,15 +275,22 @@ static NSMutableDictionary *callFlags;
- (void)sendHeaders:(NSDictionary *)headers {
// TODO(jcanizales): Add error handlers for async failures
- [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc] initWithMetadata:headers
- flags:[GRPCCall callFlagsForHost:_host path:_path]
- handler:nil]]];
+ GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] initWithMetadata:headers
+ flags:[GRPCCall callFlagsForHost:_host path:_path]
+ handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA
+ if (!_unaryCall) {
+ [_wrappedCall startBatchWithOperations:@[op]];
+ } else {
+ [_unaryOpBatch addObject:op];
+ }
}
#pragma mark GRXWriteable implementation
// Only called from the call queue. The error handler will be called from the
// network queue if the write didn't succeed.
+// If the call is a unary call, parameter \a errorHandler will be ignored and
+// the error handler of GRPCOpSendClose will be executed in case of error.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler {
__weak GRPCCall *weakSelf = self;
@@ -275,9 +303,17 @@ static NSMutableDictionary *callFlags;
}
}
};
- [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMessage alloc] initWithMessage:message
- handler:resumingHandler]]
- errorHandler:errorHandler];
+
+ GRPCOpSendMessage *op = [[GRPCOpSendMessage alloc] initWithMessage:message
+ handler:resumingHandler];
+ if (!_unaryCall) {
+ [_wrappedCall startBatchWithOperations:@[op]
+ errorHandler:errorHandler];
+ } else {
+ // Ignored errorHandler since it is the same as the one for GRPCOpSendClose.
+ // TODO (mxyan): unify the error handlers of all Ops into a single closure.
+ [_unaryOpBatch addObject:op];
+ }
}
- (void)writeValue:(id)value {
@@ -302,8 +338,14 @@ static NSMutableDictionary *callFlags;
// Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)())errorHandler {
- [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendClose alloc] init]]
- errorHandler:errorHandler];
+ if (!_unaryCall) {
+ [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendClose alloc] init]]
+ errorHandler:errorHandler];
+ } else {
+ [_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]];
+ [_wrappedCall startBatchWithOperations:_unaryOpBatch
+ errorHandler:errorHandler];
+ }
}
- (void)writesFinishedWithError:(NSError *)errorOrNil {
diff --git a/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.h b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.h
new file mode 100644
index 0000000000..29bd12f0cf
--- /dev/null
+++ b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef GRPC_TEST_OBJC
+
+#import "../GRPCCall.h"
+
+/**
+ * Methods used for gRPC internal tests. DO NOT USE.
+ */
+@interface GRPCCall (InternalTests)
+
+/**
+ * Enables logging of op batches. Memory consumption increases as more ops are logged.
+ *
+ * This function is for internal testing of gRPC only. It is not part of gRPC's public interface.
+ * Do not use in production. To enable, set the preprocessor flag GRPC_TEST_OBJC.
+ */
++ (void)enableOpBatchLog:(BOOL)enabled;
+
+/**
+ * Obtain the logged op batches. Invoking this method will clean the log.
+ *
+ * This function is for internal testing of gRPC only. It is not part of gRPC's public interface.
+ * Do not use in production. To enable, set the preprocessor flag GRPC_TEST_OBJC.
+ */
++ (NSArray *)obtainAndCleanOpBatchLog;
+
+@end
+
+#endif
diff --git a/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m
new file mode 100644
index 0000000000..6371df6739
--- /dev/null
+++ b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef GRPC_TEST_OBJC
+
+#import "GRPCCall+InternalTests.h"
+
+#import "../private/GRPCOpBatchLog.h"
+
+@implementation GRPCCall (InternalTests)
+
++ (void)enableOpBatchLog:(BOOL)enabled {
+ [GRPCOpBatchLog enableOpBatchLog:enabled];
+}
+
++ (NSArray *)obtainAndCleanOpBatchLog {
+ return [GRPCOpBatchLog obtainAndCleanOpBatchLog];
+}
+
+@end
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCOpBatchLog.h b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.h
new file mode 100644
index 0000000000..753c4cfee6
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifdef GRPC_TEST_OBJC
+
+/**
+ * Logs the op batches of a client. Used for testing.
+ */
+@interface GRPCOpBatchLog : NSObject
+
+/**
+ * Enables logging of op batches. Memory consumption increases as more ops are logged.
+ */
++ (void)enableOpBatchLog:(BOOL)enabled;
+
+/**
+ * Add an op batch to log.
+ */
++ (void)addOpBatchToLog:(NSArray *)batch;
+
+/**
+ * Obtain the logged op batches. Invoking this method will clean the log.
+ */
++ (NSArray *)obtainAndCleanOpBatchLog;
+
+@end
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCOpBatchLog.m b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.m
new file mode 100644
index 0000000000..4b40baf122
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.m
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef GRPC_TEST_OBJC
+
+#import "GRPCOpBatchLog.h"
+
+static NSMutableArray *opBatchLog = nil;
+
+@implementation GRPCOpBatchLog
+
++ (void)enableOpBatchLog:(BOOL)enabled {
+ @synchronized (opBatchLog) {
+ if (enabled) {
+ if (!opBatchLog) {
+ opBatchLog = [NSMutableArray array];
+ }
+ } else {
+ if (opBatchLog) {
+ opBatchLog = nil;
+ }
+ }
+ }
+}
+
++ (void)addOpBatchToLog:(NSArray *)batch {
+ @synchronized (opBatchLog) {
+ [opBatchLog addObject:batch];
+ }
+}
+
++ (NSArray *)obtainAndCleanOpBatchLog {
+ @synchronized (opBatchLog) {
+ NSArray *out = opBatchLog;
+ opBatchLog = [NSMutableArray array];
+ return out;
+ }
+}
+
+@end
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index 9f1901ab30..46e9fee7e1 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -44,6 +44,8 @@
#import "NSData+GRPC.h"
#import "NSError+GRPC.h"
+#import "GRPCOpBatchLog.h"
+
@implementation GRPCOperation {
@protected
// Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being
@@ -274,6 +276,12 @@
}
- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)())errorHandler {
+ // Keep logs of op batches when we are running tests. Disabled when in production for improved
+ // performance.
+#ifdef GRPC_TEST_OBJC
+ [GRPCOpBatchLog addOpBatchToLog:operations];
+#endif
+
size_t nops = operations.count;
grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op));
size_t i = 0;