Browse Source

reduce websocket read allocations

See #2037
tags/v2.12.0-rc1
Shivaram Lingamneni 1 year ago
parent
commit
5eaf7b37e5
1 changed files with 32 additions and 12 deletions
  1. 32
    12
      irc/ircconn.go

+ 32
- 12
irc/ircconn.go View File

@@ -5,6 +5,7 @@ package irc
5 5
 
6 6
 import (
7 7
 	"bytes"
8
+	"io"
8 9
 	"net"
9 10
 	"unicode/utf8"
10 11
 
@@ -93,21 +94,25 @@ func (cc *IRCStreamConn) Close() (err error) {
93 94
 // IRCWSConn is an IRCConn over a websocket.
94 95
 type IRCWSConn struct {
95 96
 	conn   *websocket.Conn
97
+	buf    []byte
96 98
 	binary bool
97 99
 }
98 100
 
99
-func NewIRCWSConn(conn *websocket.Conn) IRCWSConn {
100
-	binary := conn.Subprotocol() == "binary.ircv3.net"
101
-	return IRCWSConn{conn: conn, binary: binary}
101
+func NewIRCWSConn(conn *websocket.Conn) *IRCWSConn {
102
+	return &IRCWSConn{
103
+		conn:   conn,
104
+		binary: conn.Subprotocol() == "binary.ircv3.net",
105
+		buf:    make([]byte, maxReadQBytes()),
106
+	}
102 107
 }
103 108
 
104
-func (wc IRCWSConn) UnderlyingConn() *utils.WrappedConn {
109
+func (wc *IRCWSConn) UnderlyingConn() *utils.WrappedConn {
105 110
 	// just assume that the type is OK
106 111
 	wConn, _ := wc.conn.UnderlyingConn().(*utils.WrappedConn)
107 112
 	return wConn
108 113
 }
109 114
 
110
-func (wc IRCWSConn) WriteLine(buf []byte) (err error) {
115
+func (wc *IRCWSConn) WriteLine(buf []byte) (err error) {
111 116
 	buf = bytes.TrimSuffix(buf, crlf)
112 117
 	// #1483: if we have websockets at all, then we're enforcing utf8
113 118
 	messageType := websocket.TextMessage
@@ -117,7 +122,7 @@ func (wc IRCWSConn) WriteLine(buf []byte) (err error) {
117 122
 	return wc.conn.WriteMessage(messageType, buf)
118 123
 }
119 124
 
120
-func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
125
+func (wc *IRCWSConn) WriteLines(buffers [][]byte) (err error) {
121 126
 	for _, buf := range buffers {
122 127
 		err = wc.WriteLine(buf)
123 128
 		if err != nil {
@@ -127,20 +132,35 @@ func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
127 132
 	return
128 133
 }
129 134
 
130
-func (wc IRCWSConn) ReadLine() (line []byte, err error) {
131
-	messageType, line, err := wc.conn.ReadMessage()
132
-	if err == nil {
135
+func (wc *IRCWSConn) ReadLine() (line []byte, err error) {
136
+	messageType, reader, err := wc.conn.NextReader()
137
+	switch err {
138
+	case nil:
139
+		// OK
140
+	case websocket.ErrReadLimit:
141
+		return line, ircreader.ErrReadQ
142
+	default:
143
+		return line, err
144
+	}
145
+
146
+	n, err := io.ReadFull(reader, wc.buf)
147
+	line = wc.buf[:n]
148
+	switch err {
149
+	case io.ErrUnexpectedEOF, io.EOF:
150
+		// these are OK. io.ErrUnexpectedEOF is the good case:
151
+		// it means we read the full message and it consumed less than the full wc.buf
133 152
 		if messageType == websocket.BinaryMessage && !utf8.Valid(line) {
134 153
 			return line, errInvalidUtf8
135 154
 		}
136 155
 		return line, nil
137
-	} else if err == websocket.ErrReadLimit {
156
+	case nil, websocket.ErrReadLimit:
157
+		// nil means we filled wc.buf without exhausting the reader:
138 158
 		return line, ircreader.ErrReadQ
139
-	} else {
159
+	default:
140 160
 		return line, err
141 161
 	}
142 162
 }
143 163
 
144
-func (wc IRCWSConn) Close() (err error) {
164
+func (wc *IRCWSConn) Close() (err error) {
145 165
 	return wc.conn.Close()
146 166
 }

Loading…
Cancel
Save