Reduce allocations in WebSocket compression

Signed-off-by: Neil Twigg <neil@nats.io>
This commit is contained in:
Neil Twigg
2023-10-04 12:15:05 +01:00
parent dbe700d192
commit 6b65452bc7
2 changed files with 32 additions and 32 deletions

View File

@@ -346,20 +346,23 @@ func nbPoolGet(sz int) []byte {
} }
} }
func nbPoolPut(b []byte) { func nbPoolPut(in []byte) {
switch cap(b) { ca := cap(in)
case nbPoolSizeSmall: for in = in[:ca]; ca >= nbPoolSizeSmall; ca = cap(in) {
b := (*[nbPoolSizeSmall]byte)(b[0:nbPoolSizeSmall]) switch {
nbPoolSmall.Put(b) case ca >= nbPoolSizeLarge:
case nbPoolSizeMedium: b := (*[nbPoolSizeLarge]byte)(in[0:nbPoolSizeLarge:nbPoolSizeLarge])
b := (*[nbPoolSizeMedium]byte)(b[0:nbPoolSizeMedium]) nbPoolLarge.Put(b)
nbPoolMedium.Put(b) in = in[nbPoolSizeLarge:]
case nbPoolSizeLarge: case ca >= nbPoolSizeMedium:
b := (*[nbPoolSizeLarge]byte)(b[0:nbPoolSizeLarge]) b := (*[nbPoolSizeMedium]byte)(in[0:nbPoolSizeMedium:nbPoolSizeMedium])
nbPoolLarge.Put(b) nbPoolMedium.Put(b)
default: in = in[nbPoolSizeMedium:]
// Ignore frames that are the wrong size, this might happen case ca >= nbPoolSizeSmall:
// with WebSocket/MQTT messages as they are framed b := (*[nbPoolSizeSmall]byte)(in[0:nbPoolSizeSmall:nbPoolSizeSmall])
nbPoolSmall.Put(b)
in = in[nbPoolSizeSmall:]
}
} }
} }

View File

@@ -115,6 +115,7 @@ type websocket struct {
nocompfrag bool // No fragment for compressed frames nocompfrag bool // No fragment for compressed frames
maskread bool maskread bool
maskwrite bool maskwrite bool
compressor *flate.Writer
cookieJwt string cookieJwt string
clientIP string clientIP string
} }
@@ -1295,7 +1296,13 @@ func (c *client) wsCollapsePtoNB() (net.Buffers, int64) {
mfs = 0 mfs = 0
} }
buf := bytes.NewBuffer(nbPoolGet(usz)) buf := bytes.NewBuffer(nbPoolGet(usz))
cp, _ := flate.NewWriter(buf, flate.BestSpeed) cp := c.ws.compressor
if cp == nil {
c.ws.compressor, _ = flate.NewWriter(buf, flate.BestSpeed)
cp = c.ws.compressor
} else {
cp.Reset(buf)
}
var csz int var csz int
for _, b := range nb { for _, b := range nb {
cp.Write(b) cp.Write(b)
@@ -1323,9 +1330,7 @@ func (c *client) wsCollapsePtoNB() (net.Buffers, int64) {
if mask { if mask {
wsMaskBuf(key, p[:lp]) wsMaskBuf(key, p[:lp])
} }
new := nbPoolGet(wsFrameSizeForBrowsers) bufs = append(bufs, fh[:n], p[:lp])
lp = copy(new[:wsFrameSizeForBrowsers], p[:lp])
bufs = append(bufs, fh[:n], new[:lp])
csz += n + lp csz += n + lp
p = p[lp:] p = p[lp:]
} }
@@ -1335,16 +1340,9 @@ func (c *client) wsCollapsePtoNB() (net.Buffers, int64) {
if mask { if mask {
wsMaskBuf(key, p) wsMaskBuf(key, p)
} }
bufs = append(bufs, h) bufs = append(bufs, h, p)
for len(p) > 0 {
new := nbPoolGet(len(p))
n := copy(new[:cap(new)], p)
bufs = append(bufs, new[:n])
p = p[n:]
}
csz = len(h) + ol csz = len(h) + ol
} }
nbPoolPut(b) // No longer needed as we copied from above.
// Add to pb the compressed data size (including headers), but // Add to pb the compressed data size (including headers), but
// remove the original uncompressed data size that was added // remove the original uncompressed data size that was added
// during the queueing. // during the queueing.
@@ -1355,14 +1353,15 @@ func (c *client) wsCollapsePtoNB() (net.Buffers, int64) {
if mfs > 0 { if mfs > 0 {
// We are limiting the frame size. // We are limiting the frame size.
startFrame := func() int { startFrame := func() int {
bufs = append(bufs, nbPoolGet(wsMaxFrameHeaderSize)[:wsMaxFrameHeaderSize]) bufs = append(bufs, nbPoolGet(wsMaxFrameHeaderSize))
return len(bufs) - 1 return len(bufs) - 1
} }
endFrame := func(idx, size int) { endFrame := func(idx, size int) {
bufs[idx] = bufs[idx][:wsMaxFrameHeaderSize]
n, key := wsFillFrameHeader(bufs[idx], mask, wsFirstFrame, wsFinalFrame, wsUncompressedFrame, wsBinaryMessage, size) n, key := wsFillFrameHeader(bufs[idx], mask, wsFirstFrame, wsFinalFrame, wsUncompressedFrame, wsBinaryMessage, size)
bufs[idx] = bufs[idx][:n]
c.out.pb += int64(n) c.out.pb += int64(n)
c.ws.fs += int64(n + size) c.ws.fs += int64(n + size)
bufs[idx] = bufs[idx][:n]
if mask { if mask {
wsMaskBufs(key, bufs[idx+1:]) wsMaskBufs(key, bufs[idx+1:])
} }
@@ -1388,10 +1387,8 @@ func (c *client) wsCollapsePtoNB() (net.Buffers, int64) {
if endStart { if endStart {
fhIdx = startFrame() fhIdx = startFrame()
} }
new := nbPoolGet(total) bufs = append(bufs, b[:total])
n := copy(new[:cap(new)], b[:total]) b = b[total:]
bufs = append(bufs, new[:n])
b = b[n:]
} }
} }
if total > 0 { if total > 0 {