2
0
Эх сурвалжийг харах

Update NIO version to 2.22.0 and NIOHTTP2 to 1.14.1. (#954)

Motivation:

SwiftNIO 2.21.0 inlcudes a fast-path for writing `Data` into a
`ByteBuffer`, and SwiftNIO HTTP/2 1.14.0 contains a `reserveCapacity`
for `HPACKHeaders`.

Modifications:

- Replace a few occurrences of `writeBytes` with the new
  `writeContiguousBytes` instead.
- Reserve the capacity upfront when constructing request headers
- Stop using a deprecated function

Result:

- Perf win when serializing and writing protobuf messages into a buffer
George Barnett 5 жил өмнө
parent
commit
640b0ef1d0

+ 4 - 4
Package.resolved

@@ -15,8 +15,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio.git",
         "state": {
           "branch": null,
-          "revision": "8a865bd15e69526cbdfcfd7c47698eb20b2ba951",
-          "version": "2.19.0"
+          "revision": "5fc24345f92ec4c274121776c215ab0aa1ed4d50",
+          "version": "2.22.0"
         }
       },
       {
@@ -24,8 +24,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio-http2.git",
         "state": {
           "branch": null,
-          "revision": "e9627350bdb85bde7e0dc69a29799e40961ced72",
-          "version": "1.13.0"
+          "revision": "1e68e51752be0b43c5a0ef35818c1dd24d13e77c",
+          "version": "1.14.1"
         }
       },
       {

+ 2 - 2
Package.swift

@@ -26,9 +26,9 @@ let package = Package(
   dependencies: [
     // GRPC dependencies:
     // Main SwiftNIO package
-    .package(url: "https://github.com/apple/swift-nio.git", from: "2.19.0"),
+    .package(url: "https://github.com/apple/swift-nio.git", from: "2.22.0"),
     // HTTP2 via SwiftNIO
-    .package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.13.0"),
+    .package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.14.1"),
     // TLS via SwiftNIO
     .package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.8.0"),
     // Support for Network.framework where possible.

+ 18 - 14
Sources/GRPC/GRPCClientStateMachine.swift

@@ -570,16 +570,20 @@ extension GRPCClientStateMachine.State {
     customMetadata: HPACKHeaders,
     compression: ClientMessageEncoding
   ) -> HPACKHeaders {
-    // Note: we don't currently set the 'grpc-encoding' header, if we do we will need to feed that
-    // encoded into the message writer.
-    var headers: HPACKHeaders = [
-      ":method": method,
-      ":path": path,
-      ":authority": host,
-      ":scheme": scheme,
-      "content-type": "application/grpc",
-      "te": "trailers", // Used to detect incompatible proxies, part of the gRPC specification.
-    ]
+    var headers = HPACKHeaders()
+    // The 10 is:
+    // - 6 which are required and added just below, and
+    // - 4 which are possibly added, depending on conditions.
+    headers.reserveCapacity(10 + customMetadata.count)
+
+    // Add the required headers.
+    headers.add(name: ":method", value: method)
+    headers.add(name: ":path", value: path)
+    headers.add(name: ":authority", value: host)
+    headers.add(name: ":scheme", value: scheme)
+    headers.add(name: "content-type", value: "application/grpc")
+    // Used to detect incompatible proxies, part of the gRPC specification.
+    headers.add(name: "te", value: "trailers")
 
     switch compression {
     case let .enabled(configuration):
@@ -604,14 +608,14 @@ extension GRPCClientStateMachine.State {
 
     // Add user-defined custom metadata: this should come after the call definition headers.
     // TODO: make header normalization user-configurable.
-    headers.add(contentsOf: customMetadata.map { name, value, indexing in
+    headers.add(contentsOf: customMetadata.lazy.map { name, value, indexing in
       (name.lowercased(), value, indexing)
     })
 
     // Add default user-agent value, if `customMetadata` didn't contain user-agent
-    if headers["user-agent"].isEmpty {
-      headers
-        .add(name: "user-agent", value: "grpc-swift-nio") // TODO: Add a more specific user-agent.
+    if !headers.contains(name: "user-agent") {
+      // TODO: Add a more specific user-agent.
+      headers.add(name: "user-agent", value: "grpc-swift-nio")
     }
 
     return headers

+ 2 - 2
Sources/GRPC/HTTP1ToGRPCServerCodec.swift

@@ -266,7 +266,7 @@ extension HTTP1ToGRPCServerCodec: ChannelInboundHandler {
         throw GRPCError.Base64DecodeError().captureContext()
       }
 
-      body.writeBytes(decodedData)
+      body.writeContiguousBytes(decodedData)
     }
 
     self.messageReader.append(buffer: &body)
@@ -455,7 +455,7 @@ extension HTTP1ToGRPCServerCodec: ChannelOutboundHandler {
         let encodedData = accumulatedData.base64EncodedString()
 
         // Reuse our first buffer.
-        responseTextBuffer.clear(minimumCapacity: UInt32(encodedData.utf8.count))
+        responseTextBuffer.clear(minimumCapacity: Int(encodedData.utf8.count))
         responseTextBuffer.writeString(encodedData)
 
         // After collecting all response for gRPC Web connections, send one final aggregated

+ 2 - 2
Sources/GRPC/Serialization.swift

@@ -48,11 +48,11 @@ internal struct ProtobufSerializer<Message: SwiftProtobuf.Message>: MessageSeria
     // prefixed message writer can re-use the leading 5 bytes without needing to allocate a new
     // buffer and copy over the serialized message.
     var buffer = allocator.buffer(capacity: serialized.count + 5)
-    buffer.writeBytes(Array(repeating: 0, count: 5))
+    buffer.writeRepeatingByte(0, count: 5)
     buffer.moveReaderIndex(forwardBy: 5)
 
     // Now write the serialized message.
-    buffer.writeBytes(serialized)
+    buffer.writeContiguousBytes(serialized)
 
     return buffer
   }

+ 1 - 1
Sources/GRPCPerformanceTests/Benchmarks/EmbeddedClientThroughput.swift

@@ -66,7 +66,7 @@ class EmbeddedClientThroughput: Benchmark {
     var buffer = ByteBufferAllocator().buffer(capacity: serializedResponse.count + 5)
     buffer.writeInteger(UInt8(0)) // compression byte
     buffer.writeInteger(UInt32(serializedResponse.count))
-    buffer.writeBytes(serializedResponse)
+    buffer.writeContiguousBytes(serializedResponse)
 
     self.responseDataChunks = []
     while buffer.readableBytes > 0,