Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Commit

Permalink
Cache mapping of methods to protocol handlers (connectrpc#525)
Browse files Browse the repository at this point in the history
Remove allocation of an array for each request by mapping the handlers
by methods. Follows pattern of caching allow method and content types.

```
                │  allocs/op  │  allocs/op   vs base           │
Connect/unary-8   247.0 ± ∞ ¹   243.0 ± ∞ ¹  ~ (p=1.000 n=1) ²
```
  • Loading branch information
emcfarlane committed Jun 20, 2023
1 parent 3d7bd74 commit 513111c
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 12 deletions.
18 changes: 6 additions & 12 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import (
type Handler struct {
spec Spec
implementation StreamingHandlerFunc
protocolHandlers []protocolHandler
allowMethod string // Allow header
acceptPost string // Accept-Post header
protocolHandlers map[string][]protocolHandler // Method to protocol handlers
allowMethod string // Allow header
acceptPost string // Accept-Post header
}

// NewUnaryHandler constructs a [Handler] for a request-response procedure.
Expand Down Expand Up @@ -91,7 +91,7 @@ func NewUnaryHandler[Req, Res any](
return &Handler{
spec: config.newSpec(StreamTypeUnary),
implementation: implementation,
protocolHandlers: protocolHandlers,
protocolHandlers: mappedMethodHandlers(protocolHandlers),
allowMethod: sortedAllowMethodValue(protocolHandlers),
acceptPost: sortedAcceptPostValue(protocolHandlers),
}
Expand Down Expand Up @@ -190,13 +190,7 @@ func (h *Handler) ServeHTTP(responseWriter http.ResponseWriter, request *http.Re
return
}

var protocolHandlers []protocolHandler
for _, handler := range h.protocolHandlers {
if _, ok := handler.Methods()[request.Method]; ok {
protocolHandlers = append(protocolHandlers, handler)
}
}

protocolHandlers := h.protocolHandlers[request.Method]
if len(protocolHandlers) == 0 {
responseWriter.Header().Set("Allow", h.allowMethod)
responseWriter.WriteHeader(http.StatusMethodNotAllowed)
Expand Down Expand Up @@ -332,7 +326,7 @@ func newStreamHandler(
return &Handler{
spec: config.newSpec(streamType),
implementation: implementation,
protocolHandlers: protocolHandlers,
protocolHandlers: mappedMethodHandlers(protocolHandlers),
allowMethod: sortedAllowMethodValue(protocolHandlers),
acceptPost: sortedAcceptPostValue(protocolHandlers),
}
Expand Down
10 changes: 10 additions & 0 deletions protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,16 @@ func wrapClientConnWithCodedErrors(conn streamingClientConn) streamingClientConn
}
}

func mappedMethodHandlers(handlers []protocolHandler) map[string][]protocolHandler {
methodHandlers := make(map[string][]protocolHandler)
for _, handler := range handlers {
for method := range handler.Methods() {
methodHandlers[method] = append(methodHandlers[method], handler)
}
}
return methodHandlers
}

func sortedAcceptPostValue(handlers []protocolHandler) string {
contentTypes := make(map[string]struct{})
for _, handler := range handlers {
Expand Down

0 comments on commit 513111c

Please sign in to comment.