Skip to content

Commit

Permalink
Update NIO version to 2.22.0 and NIOHTTP2 to 1.14.1. (#954)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
glbrntt authored Aug 27, 2020
1 parent cc1f91f commit 640b0ef
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 25 deletions.
8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
"revision": "8a865bd15e69526cbdfcfd7c47698eb20b2ba951",
"version": "2.19.0"
"revision": "5fc24345f92ec4c274121776c215ab0aa1ed4d50",
"version": "2.22.0"
}
},
{
"package": "swift-nio-http2",
"repositoryURL": "https://github.com/apple/swift-nio-http2.git",
"state": {
"branch": null,
"revision": "e9627350bdb85bde7e0dc69a29799e40961ced72",
"version": "1.13.0"
"revision": "1e68e51752be0b43c5a0ef35818c1dd24d13e77c",
"version": "1.14.1"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
32 changes: 18 additions & 14 deletions Sources/GRPC/GRPCClientStateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Sources/GRPC/HTTP1ToGRPCServerCodec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ extension HTTP1ToGRPCServerCodec: ChannelInboundHandler {
throw GRPCError.Base64DecodeError().captureContext()
}

body.writeBytes(decodedData)
body.writeContiguousBytes(decodedData)
}

self.messageReader.append(buffer: &body)
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Sources/GRPC/Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 640b0ef

Please sign in to comment.