Skip to content

Commit 50952d7

Browse files
committed
compress.go: Rewrite compression docs
1 parent d22d1f3 commit 50952d7

File tree

3 files changed

+54
-25
lines changed

3 files changed

+54
-25
lines changed

compress.go

+26-24
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,45 @@ import (
99
"sync"
1010
)
1111

12-
// CompressionMode represents the modes available to the deflate extension.
12+
// CompressionMode represents the modes available to the permessage-deflate extension.
1313
// See https://tools.ietf.org/html/rfc7692
1414
//
15-
// Works in all browsers except Safari which does not implement the deflate extension.
15+
// Works in all modern browsers except Safari which does not implement the permessage-deflate extension.
16+
//
17+
// Compression is only used if the peer supports the mode selected.
1618
type CompressionMode int
1719

1820
const (
19-
// CompressionDisabled disables the deflate extension.
20-
//
21-
// Use this if you are using a predominantly binary protocol with very
22-
// little duplication in between messages or CPU and memory are more
23-
// important than bandwidth.
21+
// CompressionDisabled disables the negotiation of the permessage-deflate extension.
2422
//
25-
// This is the default.
23+
// This is the default. Do not enable compression without benchmarking for your particular use case first.
2624
CompressionDisabled CompressionMode = iota
2725

28-
// CompressionContextTakeover uses a 32 kB sliding window and flate.Writer per connection.
29-
// It reuses the sliding window from previous messages.
30-
// As most WebSocket protocols are repetitive, this can be very efficient.
31-
// It carries an overhead of 32 kB + 1.2 MB for every connection compared to CompressionNoContextTakeover.
26+
// CompressionNoContextTakeover compresses each message greater than 512 bytes. Each message is compressed with
27+
// a new 1.2 MB flate.Writer pulled from a sync.Pool. Each message is read with a 40 KB flate.Reader pulled from
28+
// a sync.Pool.
3229
//
33-
// Sometime in the future it will carry 65 kB overhead instead once https://github.com/golang/go/issues/36919
34-
// is fixed.
30+
// This means less efficient compression as the sliding window from previous messages will not be used but the
31+
// memory overhead will be lower as there will be no fixed cost for the flate.Writer nor the 32 KB sliding window.
32+
// Especially if the connections are long lived and seldom written to.
3533
//
36-
// If the peer negotiates NoContextTakeover on the client or server side, it will be
37-
// used instead as this is required by the RFC.
38-
CompressionContextTakeover
34+
// Thus, it uses less memory than CompressionContextTakeover but compresses less efficiently.
35+
//
36+
// If the peer does not support CompressionNoContextTakeover then we will fall back to CompressionDisabled.
37+
CompressionNoContextTakeover
3938

40-
// CompressionNoContextTakeover grabs a new flate.Reader and flate.Writer as needed
41-
// for every message. This applies to both server and client side.
39+
// CompressionContextTakeover compresses each message greater than 128 bytes reusing the 32 KB sliding window from
40+
// previous messages. i.e compression context across messages is preserved.
4241
//
43-
// This means less efficient compression as the sliding window from previous messages
44-
// will not be used but the memory overhead will be lower if the connections
45-
// are long lived and seldom used.
42+
// As most WebSocket protocols are text based and repetitive, this compression mode can be very efficient.
4643
//
47-
// The message will only be compressed if greater than 512 bytes.
48-
CompressionNoContextTakeover
44+
// The memory overhead is a fixed 32 KB sliding window, a fixed 1.2 MB flate.Writer and a sync.Pool of 40 KB flate.Reader's
45+
// that are used when reading and then returned.
46+
//
47+
// Thus, it uses more memory than CompressionNoContextTakeover but compresses more efficiently.
48+
//
49+
// If the peer does not support CompressionContextTakeover then we will fall back to CompressionNoContextTakeover.
50+
CompressionContextTakeover
4951
)
5052

5153
func (m CompressionMode) opts() *compressionOptions {

compress_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
package websocket
55

66
import (
7+
"bytes"
8+
"compress/flate"
9+
"io"
710
"strings"
811
"testing"
912

@@ -33,3 +36,27 @@ func Test_slidingWindow(t *testing.T) {
3336
})
3437
}
3538
}
39+
40+
func BenchmarkFlateWriter(b *testing.B) {
41+
b.ReportAllocs()
42+
for i := 0; i < b.N; i++ {
43+
w, _ := flate.NewWriter(io.Discard, flate.BestSpeed)
44+
// We have to write a byte to get the writer to allocate to its full extent.
45+
w.Write([]byte{'a'})
46+
w.Flush()
47+
}
48+
}
49+
50+
func BenchmarkFlateReader(b *testing.B) {
51+
b.ReportAllocs()
52+
53+
var buf bytes.Buffer
54+
w, _ := flate.NewWriter(&buf, flate.BestSpeed)
55+
w.Write([]byte{'a'})
56+
w.Flush()
57+
58+
for i := 0; i < b.N; i++ {
59+
r := flate.NewReader(bytes.NewReader(buf.Bytes()))
60+
io.ReadAll(r)
61+
}
62+
}

write.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, err
3838
//
3939
// See the Writer method if you want to stream a message.
4040
//
41-
// If compression is disabled or the threshold is not met, then it
41+
// If compression is disabled or the compression threshold is not met, then it
4242
// will write the message in a single frame.
4343
func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error {
4444
_, err := c.write(ctx, typ, p)

0 commit comments

Comments
 (0)