Skip to content

Commit a3edce6

Browse files
committed
eliminated an allocation on each connection by generating Accept-Encoding string only once
1 parent fe334a5 commit a3edce6

File tree

7 files changed

+23
-74
lines changed

7 files changed

+23
-74
lines changed

internal/codecutil/cache.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package codecutil
22

33
import (
4-
"iter"
4+
"strings"
55

66
"github.com/indigo-web/indigo/http/codec"
7-
"github.com/indigo-web/indigo/internal/strutil"
87
)
98

109
type Cache struct {
@@ -13,10 +12,9 @@ type Cache struct {
1312
instances []codec.Instance
1413
}
1514

16-
func NewCache(codecs []codec.Codec) Cache {
15+
func NewCache(codecs []codec.Codec, acceptString string) Cache {
1716
return Cache{
18-
// TODO: we're still allocating a string on every connection. Which we actually can avoid.
19-
accept: acceptEncodings(codecs),
17+
accept: acceptString,
2018
codecs: codecs,
2119
instances: make([]codec.Instance, len(codecs)),
2220
}
@@ -51,20 +49,18 @@ func (c Cache) AcceptEncoding() string {
5149
return c.accept
5250
}
5351

54-
func acceptEncodings(codecs []codec.Codec) string {
52+
func AcceptEncoding(codecs []codec.Codec) string {
5553
if len(codecs) == 0 {
5654
return "identity"
5755
}
5856

59-
return strutil.Join(traverseTokens(codecs), ", ")
60-
}
57+
var b strings.Builder
6158

62-
func traverseTokens(codecs []codec.Codec) iter.Seq[string] {
63-
return func(yield func(string) bool) {
64-
for _, c := range codecs {
65-
if !yield(c.Token()) {
66-
break
67-
}
68-
}
59+
b.WriteString(codecs[0].Token())
60+
for _, c := range codecs[1:] {
61+
b.WriteString(", ")
62+
b.WriteString(c.Token())
6963
}
64+
65+
return b.String()
7066
}

internal/httptest/parse/parse.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
func HTTP11Request(data string) (*http.Request, error) {
1313
client := dummy.NewMockClient([]byte(data))
1414
request := construct.Request(config.Default(), client)
15-
suit := http1.New(config.Default(), nil, client, request, codecutil.NewCache(nil))
15+
suit := http1.New(config.Default(), nil, client, request, codecutil.NewCache(nil, "identity"))
1616
request.Body = http.NewBody(suit)
1717

1818
for {

internal/protocol/http1/serializer_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
"github.com/stretchr/testify/require"
2727
)
2828

29-
var noCodecs = codecutil.NewCache(nil)
29+
var noCodecs = codecutil.NewCache(nil, "identity")
3030

3131
func BenchmarkSerializer(b *testing.B) {
3232
getRequest := func(cfg *config.Config, m method.Method) *http.Request {
@@ -37,7 +37,8 @@ func BenchmarkSerializer(b *testing.B) {
3737

3838
getSerializer := func(cfg *config.Config, m method.Method, codecs ...codec.Codec) *serializer {
3939
buff := make([]byte, 0, cfg.NET.WriteBufferSize.Default)
40-
return newSerializer(cfg, getRequest(cfg, method.GET), new(dummy.NopClient), codecutil.NewCache(codecs), buff)
40+
cache := codecutil.NewCache(codecs, codecutil.AcceptEncoding(codecs))
41+
return newSerializer(cfg, getRequest(cfg, method.GET), new(dummy.NopClient), cache, buff)
4142
}
4243

4344
getResponseWithHeaders := func(n int) *http.Response {
@@ -354,7 +355,7 @@ func TestSerializer(t *testing.T) {
354355

355356
t.Run("streams", func(t *testing.T) {
356357
request := newRequest(method.GET)
357-
codecs := codecutil.NewCache([]codec.Codec{codec.NewGZIP()})
358+
codecs := codecutil.NewCache([]codec.Codec{codec.NewGZIP()}, codec.NewGZIP().Token())
358359
s, w := getSerializer(nil, request, codecs)
359360

360361
testSized := func(t *testing.T, method string, contentLength int, body string, contentEncoding ...string) {

internal/protocol/http1/suit_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func getSuit(client transport.Client, codecs ...codec.Codec) (*Suit, *http.Reque
164164
cfg := config.Default()
165165
r := getInbuiltRouter()
166166
req := construct.Request(cfg, client)
167-
suit := New(cfg, r, client, req, codecutil.NewCache(codecs))
167+
suit := New(cfg, r, client, req, codecutil.NewCache(codecs, codecutil.AcceptEncoding(codecs)))
168168
req.Body = http.NewBody(suit)
169169

170170
return suit, req

internal/strutil/join.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

internal/strutil/join_test.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

transport.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ func TCP() Transport {
3333
return Transport{
3434
inner: transport.NewTCP(),
3535
spawnCallback: func(cfg *config.Config, r router.Router, c []codec.Codec) func(net.Conn) {
36+
acceptString := codecutil.AcceptEncoding(c)
37+
3638
return func(conn net.Conn) {
37-
serve.HTTP1(cfg, conn, 0, r, codecutil.NewCache(c))
39+
serve.HTTP1(cfg, conn, 0, r, codecutil.NewCache(c, acceptString))
3840
}
3941
},
4042
}
@@ -105,9 +107,11 @@ func newTLSTransport(cfg *tls.Config) Transport {
105107
return Transport{
106108
inner: transport.NewTLS(cfg),
107109
spawnCallback: func(cfg *config.Config, r router.Router, c []codec.Codec) func(net.Conn) {
110+
acceptString := codecutil.AcceptEncoding(c)
111+
108112
return func(conn net.Conn) {
109113
ver := conn.(*tls.Conn).ConnectionState().Version
110-
serve.HTTP1(cfg, conn, ver, r, codecutil.NewCache(c))
114+
serve.HTTP1(cfg, conn, ver, r, codecutil.NewCache(c, acceptString))
111115
}
112116
},
113117
}

0 commit comments

Comments
 (0)