Skip to content

Commit

Permalink
Refactor trailer Field for Improved Memory Efficiency and Performance (
Browse files Browse the repository at this point in the history
…#1928)

* refact: represent trailer filed by [][]byte instead of []argsKV

* fix: address golangci-lint warnings
  • Loading branch information
ksw2000 authored Jan 29, 2025
1 parent 6371638 commit c908d9c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 38 deletions.
7 changes: 0 additions & 7 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,13 +356,6 @@ func visitArgs(args []argsKV, f func(k, v []byte)) {
}
}

func visitArgsKey(args []argsKV, f func(k []byte)) {
for i, n := 0, len(args); i < n; i++ {
kv := &args[i]
f(kv.key)
}
}

func copyArgs(dst, src []argsKV) []argsKV {
if cap(dst) < len(src) {
tmp := make([]argsKV, len(src))
Expand Down
94 changes: 63 additions & 31 deletions header.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ type ResponseHeader struct {
contentEncoding []byte
server []byte
mulHeader [][]byte
trailer [][]byte

h []argsKV
trailer []argsKV
h []argsKV

cookies []argsKV
bufK []byte
Expand Down Expand Up @@ -72,9 +72,9 @@ type RequestHeader struct {
contentType []byte
userAgent []byte
mulHeader [][]byte
trailer [][]byte

h []argsKV
trailer []argsKV
h []argsKV

cookies []argsKV

Expand Down Expand Up @@ -542,7 +542,14 @@ func (h *ResponseHeader) AddTrailerBytes(trailer []byte) error {
}
h.bufK = append(h.bufK[:0], key...)
normalizeHeaderKey(h.bufK, h.disableNormalizing)
h.trailer = appendArgBytes(h.trailer, h.bufK, nil, argsNoValue)
if cap(h.trailer) > len(h.trailer) {
h.trailer = h.trailer[:len(h.trailer)+1]
h.trailer[len(h.trailer)-1] = append(h.trailer[len(h.trailer)-1][:0], h.bufK...)
} else {
key = make([]byte, len(h.bufK))
copy(key, h.bufK)
h.trailer = append(h.trailer, key)
}
}

return err
Expand Down Expand Up @@ -890,7 +897,14 @@ func (h *RequestHeader) AddTrailerBytes(trailer []byte) error {
}
h.bufK = append(h.bufK[:0], key...)
normalizeHeaderKey(h.bufK, h.disableNormalizing)
h.trailer = appendArgBytes(h.trailer, h.bufK, nil, argsNoValue)
if cap(h.trailer) > len(h.trailer) {
h.trailer = h.trailer[:len(h.trailer)+1]
h.trailer[len(h.trailer)-1] = append(h.trailer[len(h.trailer)-1][:0], h.bufK...)
} else {
key = make([]byte, len(h.bufK))
copy(key, h.bufK)
h.trailer = append(h.trailer, key)
}
}

return err
Expand Down Expand Up @@ -1162,7 +1176,7 @@ func (h *ResponseHeader) CopyTo(dst *ResponseHeader) {
dst.server = append(dst.server, h.server...)
dst.h = copyArgs(dst.h, h.h)
dst.cookies = copyArgs(dst.cookies, h.cookies)
dst.trailer = copyArgs(dst.trailer, h.trailer)
dst.trailer = copyTrailer(dst.trailer, h.trailer)
}

// CopyTo copies all the headers to dst.
Expand All @@ -1182,7 +1196,7 @@ func (h *RequestHeader) CopyTo(dst *RequestHeader) {
dst.host = append(dst.host, h.host...)
dst.contentType = append(dst.contentType, h.contentType...)
dst.userAgent = append(dst.userAgent, h.userAgent...)
dst.trailer = append(dst.trailer, h.trailer...)
dst.trailer = copyTrailer(dst.trailer, h.trailer)
dst.h = copyArgs(dst.h, h.h)
dst.cookies = copyArgs(dst.cookies, h.cookies)
dst.cookiesCollected = h.cookiesCollected
Expand Down Expand Up @@ -1215,7 +1229,7 @@ func (h *ResponseHeader) VisitAll(f func(key, value []byte)) {
})
}
if len(h.trailer) > 0 {
f(strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
f(strTrailer, appendTrailerBytes(nil, h.trailer, strCommaSpace))
}
visitArgs(h.h, f)
if h.ConnectionClose() {
Expand All @@ -1227,14 +1241,18 @@ func (h *ResponseHeader) VisitAll(f func(key, value []byte)) {
//
// f must not retain references to value after returning.
func (h *ResponseHeader) VisitAllTrailer(f func(value []byte)) {
visitArgsKey(h.trailer, f)
for i := range h.trailer {
f(h.trailer[i])
}
}

// VisitAllTrailer calls f for each request Trailer.
//
// f must not retain references to value after returning.
func (h *RequestHeader) VisitAllTrailer(f func(value []byte)) {
visitArgsKey(h.trailer, f)
for i := range h.trailer {
f(h.trailer[i])
}
}

// VisitAllCookie calls f for each response cookie.
Expand Down Expand Up @@ -1279,7 +1297,7 @@ func (h *RequestHeader) VisitAll(f func(key, value []byte)) {
f(strUserAgent, userAgent)
}
if len(h.trailer) > 0 {
f(strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
f(strTrailer, appendTrailerBytes(nil, h.trailer, strCommaSpace))
}

h.collectCookies()
Expand Down Expand Up @@ -1925,7 +1943,7 @@ func (h *ResponseHeader) peek(key []byte) []byte {
case HeaderSetCookie:
return appendResponseCookieBytes(nil, h.cookies)
case HeaderTrailer:
return appendArgsKeyBytes(nil, h.trailer, strCommaSpace)
return appendTrailerBytes(nil, h.trailer, strCommaSpace)
default:
return peekArgBytes(h.h, key)
}
Expand All @@ -1952,7 +1970,7 @@ func (h *RequestHeader) peek(key []byte) []byte {
}
return peekArgBytes(h.h, key)
case HeaderTrailer:
return appendArgsKeyBytes(nil, h.trailer, strCommaSpace)
return appendTrailerBytes(nil, h.trailer, strCommaSpace)
default:
return peekArgBytes(h.h, key)
}
Expand Down Expand Up @@ -1999,7 +2017,7 @@ func (h *RequestHeader) peekAll(key []byte) [][]byte {
h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
}
case HeaderTrailer:
h.mulHeader = append(h.mulHeader, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
h.mulHeader = append(h.mulHeader, appendTrailerBytes(nil, h.trailer, strCommaSpace))
default:
h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
}
Expand Down Expand Up @@ -2043,7 +2061,7 @@ func (h *ResponseHeader) peekAll(key []byte) [][]byte {
case HeaderSetCookie:
h.mulHeader = append(h.mulHeader, appendResponseCookieBytes(nil, h.cookies))
case HeaderTrailer:
h.mulHeader = append(h.mulHeader, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
h.mulHeader = append(h.mulHeader, appendTrailerBytes(nil, h.trailer, strCommaSpace))
default:
h.mulHeader = peekAllArgBytesToDst(h.mulHeader, h.h, key)
}
Expand All @@ -2069,8 +2087,7 @@ func (h *RequestHeader) PeekKeys() [][]byte {
// Any future calls to the Peek* will modify the returned value.
// Do not store references to returned value. Make copies instead.
func (h *RequestHeader) PeekTrailerKeys() [][]byte {
h.mulHeader = h.mulHeader[:0]
h.mulHeader = peekArgsKeys(h.mulHeader, h.trailer)
h.mulHeader = copyTrailer(h.mulHeader, h.trailer)
return h.mulHeader
}

Expand All @@ -2094,7 +2111,9 @@ func (h *ResponseHeader) PeekKeys() [][]byte {
// Do not store references to returned value. Make copies instead.
func (h *ResponseHeader) PeekTrailerKeys() [][]byte {
h.mulHeader = h.mulHeader[:0]
h.mulHeader = peekArgsKeys(h.mulHeader, h.trailer)
for i, n := 0, len(h.trailer); i < n; i++ {
h.mulHeader = append(h.mulHeader, h.trailer[i])
}
return h.mulHeader
}

Expand Down Expand Up @@ -2462,8 +2481,8 @@ func (h *ResponseHeader) writeTrailer(w *bufio.Writer) error {
func (h *ResponseHeader) TrailerHeader() []byte {
h.bufV = h.bufV[:0]
for _, t := range h.trailer {
value := h.peek(t.key)
h.bufV = appendHeaderLine(h.bufV, t.key, value)
value := h.peek(t)
h.bufV = appendHeaderLine(h.bufV, t, value)
}
h.bufV = append(h.bufV, strCRLF...)
return h.bufV
Expand Down Expand Up @@ -2523,7 +2542,7 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
// Exclude trailer from header
exclude := false
for _, t := range h.trailer {
if bytes.Equal(kv.key, t.key) {
if bytes.Equal(kv.key, t) {
exclude = true
break
}
Expand All @@ -2534,7 +2553,7 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
}

if len(h.trailer) > 0 {
dst = appendHeaderLine(dst, strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
dst = appendHeaderLine(dst, strTrailer, appendTrailerBytes(nil, h.trailer, strCommaSpace))
}

n := len(h.cookies)
Expand Down Expand Up @@ -2594,8 +2613,8 @@ func (h *RequestHeader) writeTrailer(w *bufio.Writer) error {
func (h *RequestHeader) TrailerHeader() []byte {
h.bufV = h.bufV[:0]
for _, t := range h.trailer {
value := h.peek(t.key)
h.bufV = appendHeaderLine(h.bufV, t.key, value)
value := h.peek(t)
h.bufV = appendHeaderLine(h.bufV, t, value)
}
h.bufV = append(h.bufV, strCRLF...)
return h.bufV
Expand Down Expand Up @@ -2656,7 +2675,7 @@ func (h *RequestHeader) AppendBytes(dst []byte) []byte {
// Exclude trailer from header
exclude := false
for _, t := range h.trailer {
if bytes.Equal(kv.key, t.key) {
if bytes.Equal(kv.key, t) {
exclude = true
break
}
Expand All @@ -2667,7 +2686,7 @@ func (h *RequestHeader) AppendBytes(dst []byte) []byte {
}

if len(h.trailer) > 0 {
dst = appendHeaderLine(dst, strTrailer, appendArgsKeyBytes(nil, h.trailer, strCommaSpace))
dst = appendHeaderLine(dst, strTrailer, appendTrailerBytes(nil, h.trailer, strCommaSpace))
}

// there is no need in h.collectCookies() here, since if cookies aren't collected yet,
Expand Down Expand Up @@ -3608,17 +3627,30 @@ func AppendNormalizedHeaderKeyBytes(dst, key []byte) []byte {
return AppendNormalizedHeaderKey(dst, b2s(key))
}

func appendArgsKeyBytes(dst []byte, args []argsKV, sep []byte) []byte {
for i, n := 0, len(args); i < n; i++ {
kv := &args[i]
dst = append(dst, kv.key...)
func appendTrailerBytes(dst []byte, trailer [][]byte, sep []byte) []byte {
for i, n := 0, len(trailer); i < n; i++ {
dst = append(dst, trailer[i]...)
if i+1 < n {
dst = append(dst, sep...)
}
}
return dst
}

func copyTrailer(dst, src [][]byte) [][]byte {
if cap(dst) > len(src) {
dst = dst[:len(src)]
} else {
dst = append(dst[:0], src...)
}

for i := range dst {
dst[i] = make([]byte, len(src[i]))
copy(dst[i], src[i])
}
return dst
}

var (
errNeedMore = errors.New("need more data: cannot find trailing lf")
errInvalidName = errors.New("invalid header name")
Expand Down

0 comments on commit c908d9c

Please sign in to comment.