good morning!!!!
Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
W
websocket
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Harbor Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
github
nhooyr
websocket
Commits
1dbc1412
Unverified
Commit
1dbc1412
authored
Oct 14, 2023
by
Anmol Sethi
Browse files
Options
Downloads
Patches
Plain Diff
write: Zero alloc writes with Writer
Closes #354
parent
a975390c
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
.gitignore
+0
-1
0 additions, 1 deletion
.gitignore
ci/bench.sh
+2
-2
2 additions, 2 deletions
ci/bench.sh
conn.go
+4
-5
4 additions, 5 deletions
conn.go
write.go
+25
-37
25 additions, 37 deletions
write.go
with
31 additions
and
45 deletions
.gitignore
deleted
100644 → 0
+
0
−
1
View file @
a975390c
websocket.test
This diff is collapsed.
Click to expand it.
ci/bench.sh
+
2
−
2
View file @
1dbc1412
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
set
-eu
set
-eu
cd
--
"
$(
dirname
"
$0
"
)
/.."
cd
--
"
$(
dirname
"
$0
"
)
/.."
go
test
--run
=
^
$
--bench
=
.
"
$@
"
./..
.
go
test
--run
=
^
$
--bench
=
.
--benchmem
--memprofile
ci/out/prof.mem
--cpuprofile
ci/out/prof.cpu
-o
ci/out/websocket.test
"
$@
"
.
(
(
cd
./internal/thirdparty
cd
./internal/thirdparty
go
test
--run
=
^
$
--bench
=
.
"
$@
"
./..
.
go
test
--run
=
^
$
--bench
=
.
--benchmem
--memprofile
../../ci/out/prof-thirdparty.mem
--cpuprofile
../../ci/out/prof-thirdparty.cpu
-o
../../ci/out/thirdparty.test
"
$@
"
.
)
)
This diff is collapsed.
Click to expand it.
conn.go
+
4
−
5
View file @
1dbc1412
...
@@ -63,7 +63,7 @@ type Conn struct {
...
@@ -63,7 +63,7 @@ type Conn struct {
readCloseFrameErr
error
readCloseFrameErr
error
// Write state.
// Write state.
msgWriter
State
*
msgWriter
State
msgWriter
*
msgWriter
writeFrameMu
*
mu
writeFrameMu
*
mu
writeBuf
[]
byte
writeBuf
[]
byte
writeHeaderBuf
[
8
]
byte
writeHeaderBuf
[
8
]
byte
...
@@ -113,14 +113,14 @@ func newConn(cfg connConfig) *Conn {
...
@@ -113,14 +113,14 @@ func newConn(cfg connConfig) *Conn {
c
.
msgReader
=
newMsgReader
(
c
)
c
.
msgReader
=
newMsgReader
(
c
)
c
.
msgWriter
State
=
newMsgWriter
State
(
c
)
c
.
msgWriter
=
newMsgWriter
(
c
)
if
c
.
client
{
if
c
.
client
{
c
.
writeBuf
=
extractBufioWriterBuf
(
c
.
bw
,
c
.
rwc
)
c
.
writeBuf
=
extractBufioWriterBuf
(
c
.
bw
,
c
.
rwc
)
}
}
if
c
.
flate
()
&&
c
.
flateThreshold
==
0
{
if
c
.
flate
()
&&
c
.
flateThreshold
==
0
{
c
.
flateThreshold
=
128
c
.
flateThreshold
=
128
if
!
c
.
msgWriter
State
.
flateContextTakeover
()
{
if
!
c
.
msgWriter
.
flateContextTakeover
()
{
c
.
flateThreshold
=
512
c
.
flateThreshold
=
512
}
}
}
}
...
@@ -157,8 +157,7 @@ func (c *Conn) close(err error) {
...
@@ -157,8 +157,7 @@ func (c *Conn) close(err error) {
c
.
rwc
.
Close
()
c
.
rwc
.
Close
()
go
func
()
{
go
func
()
{
c
.
msgWriterState
.
close
()
c
.
msgWriter
.
close
()
c
.
msgReader
.
close
()
c
.
msgReader
.
close
()
}()
}()
}
}
...
...
This diff is collapsed.
Click to expand it.
write.go
+
25
−
37
View file @
1dbc1412
...
@@ -49,30 +49,11 @@ func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error {
...
@@ -49,30 +49,11 @@ func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error {
}
}
type
msgWriter
struct
{
type
msgWriter
struct
{
mw
*
msgWriterState
closed
bool
}
func
(
mw
*
msgWriter
)
Write
(
p
[]
byte
)
(
int
,
error
)
{
if
mw
.
closed
{
return
0
,
errors
.
New
(
"cannot use closed writer"
)
}
return
mw
.
mw
.
Write
(
p
)
}
func
(
mw
*
msgWriter
)
Close
()
error
{
if
mw
.
closed
{
return
errors
.
New
(
"cannot use closed writer"
)
}
mw
.
closed
=
true
return
mw
.
mw
.
Close
()
}
type
msgWriterState
struct
{
c
*
Conn
c
*
Conn
mu
*
mu
mu
*
mu
writeMu
*
mu
writeMu
*
mu
closed
bool
ctx
context
.
Context
ctx
context
.
Context
opcode
opcode
opcode
opcode
...
@@ -82,8 +63,8 @@ type msgWriterState struct {
...
@@ -82,8 +63,8 @@ type msgWriterState struct {
flateWriter
*
flate
.
Writer
flateWriter
*
flate
.
Writer
}
}
func
newMsgWriter
State
(
c
*
Conn
)
*
msgWriter
State
{
func
newMsgWriter
(
c
*
Conn
)
*
msgWriter
{
mw
:=
&
msgWriter
State
{
mw
:=
&
msgWriter
{
c
:
c
,
c
:
c
,
mu
:
newMu
(
c
),
mu
:
newMu
(
c
),
writeMu
:
newMu
(
c
),
writeMu
:
newMu
(
c
),
...
@@ -91,7 +72,7 @@ func newMsgWriterState(c *Conn) *msgWriterState {
...
@@ -91,7 +72,7 @@ func newMsgWriterState(c *Conn) *msgWriterState {
return
mw
return
mw
}
}
func
(
mw
*
msgWriter
State
)
ensureFlate
()
{
func
(
mw
*
msgWriter
)
ensureFlate
()
{
if
mw
.
trimWriter
==
nil
{
if
mw
.
trimWriter
==
nil
{
mw
.
trimWriter
=
&
trimLastFourBytesWriter
{
mw
.
trimWriter
=
&
trimLastFourBytesWriter
{
w
:
util
.
WriterFunc
(
mw
.
write
),
w
:
util
.
WriterFunc
(
mw
.
write
),
...
@@ -104,7 +85,7 @@ func (mw *msgWriterState) ensureFlate() {
...
@@ -104,7 +85,7 @@ func (mw *msgWriterState) ensureFlate() {
mw
.
flate
=
true
mw
.
flate
=
true
}
}
func
(
mw
*
msgWriter
State
)
flateContextTakeover
()
bool
{
func
(
mw
*
msgWriter
)
flateContextTakeover
()
bool
{
if
mw
.
c
.
client
{
if
mw
.
c
.
client
{
return
!
mw
.
c
.
copts
.
clientNoContextTakeover
return
!
mw
.
c
.
copts
.
clientNoContextTakeover
}
}
...
@@ -112,14 +93,11 @@ func (mw *msgWriterState) flateContextTakeover() bool {
...
@@ -112,14 +93,11 @@ func (mw *msgWriterState) flateContextTakeover() bool {
}
}
func
(
c
*
Conn
)
writer
(
ctx
context
.
Context
,
typ
MessageType
)
(
io
.
WriteCloser
,
error
)
{
func
(
c
*
Conn
)
writer
(
ctx
context
.
Context
,
typ
MessageType
)
(
io
.
WriteCloser
,
error
)
{
err
:=
c
.
msgWriter
State
.
reset
(
ctx
,
typ
)
err
:=
c
.
msgWriter
.
reset
(
ctx
,
typ
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
msgWriter
{
return
c
.
msgWriter
,
nil
mw
:
c
.
msgWriterState
,
closed
:
false
,
},
nil
}
}
func
(
c
*
Conn
)
write
(
ctx
context
.
Context
,
typ
MessageType
,
p
[]
byte
)
(
int
,
error
)
{
func
(
c
*
Conn
)
write
(
ctx
context
.
Context
,
typ
MessageType
,
p
[]
byte
)
(
int
,
error
)
{
...
@@ -129,8 +107,8 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) (int, error
...
@@ -129,8 +107,8 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) (int, error
}
}
if
!
c
.
flate
()
{
if
!
c
.
flate
()
{
defer
c
.
msgWriter
State
.
mu
.
unlock
()
defer
c
.
msgWriter
.
mu
.
unlock
()
return
c
.
writeFrame
(
ctx
,
true
,
false
,
c
.
msgWriter
State
.
opcode
,
p
)
return
c
.
writeFrame
(
ctx
,
true
,
false
,
c
.
msgWriter
.
opcode
,
p
)
}
}
n
,
err
:=
mw
.
Write
(
p
)
n
,
err
:=
mw
.
Write
(
p
)
...
@@ -142,7 +120,7 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) (int, error
...
@@ -142,7 +120,7 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) (int, error
return
n
,
err
return
n
,
err
}
}
func
(
mw
*
msgWriter
State
)
reset
(
ctx
context
.
Context
,
typ
MessageType
)
error
{
func
(
mw
*
msgWriter
)
reset
(
ctx
context
.
Context
,
typ
MessageType
)
error
{
err
:=
mw
.
mu
.
lock
(
ctx
)
err
:=
mw
.
mu
.
lock
(
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -151,13 +129,14 @@ func (mw *msgWriterState) reset(ctx context.Context, typ MessageType) error {
...
@@ -151,13 +129,14 @@ func (mw *msgWriterState) reset(ctx context.Context, typ MessageType) error {
mw
.
ctx
=
ctx
mw
.
ctx
=
ctx
mw
.
opcode
=
opcode
(
typ
)
mw
.
opcode
=
opcode
(
typ
)
mw
.
flate
=
false
mw
.
flate
=
false
mw
.
closed
=
false
mw
.
trimWriter
.
reset
()
mw
.
trimWriter
.
reset
()
return
nil
return
nil
}
}
func
(
mw
*
msgWriter
State
)
putFlateWriter
()
{
func
(
mw
*
msgWriter
)
putFlateWriter
()
{
if
mw
.
flateWriter
!=
nil
{
if
mw
.
flateWriter
!=
nil
{
putFlateWriter
(
mw
.
flateWriter
)
putFlateWriter
(
mw
.
flateWriter
)
mw
.
flateWriter
=
nil
mw
.
flateWriter
=
nil
...
@@ -165,7 +144,11 @@ func (mw *msgWriterState) putFlateWriter() {
...
@@ -165,7 +144,11 @@ func (mw *msgWriterState) putFlateWriter() {
}
}
// Write writes the given bytes to the WebSocket connection.
// Write writes the given bytes to the WebSocket connection.
func
(
mw
*
msgWriterState
)
Write
(
p
[]
byte
)
(
_
int
,
err
error
)
{
func
(
mw
*
msgWriter
)
Write
(
p
[]
byte
)
(
_
int
,
err
error
)
{
if
mw
.
closed
{
return
0
,
errors
.
New
(
"cannot use closed writer"
)
}
err
=
mw
.
writeMu
.
lock
(
mw
.
ctx
)
err
=
mw
.
writeMu
.
lock
(
mw
.
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
fmt
.
Errorf
(
"failed to write: %w"
,
err
)
return
0
,
fmt
.
Errorf
(
"failed to write: %w"
,
err
)
...
@@ -194,7 +177,7 @@ func (mw *msgWriterState) Write(p []byte) (_ int, err error) {
...
@@ -194,7 +177,7 @@ func (mw *msgWriterState) Write(p []byte) (_ int, err error) {
return
mw
.
write
(
p
)
return
mw
.
write
(
p
)
}
}
func
(
mw
*
msgWriter
State
)
write
(
p
[]
byte
)
(
int
,
error
)
{
func
(
mw
*
msgWriter
)
write
(
p
[]
byte
)
(
int
,
error
)
{
n
,
err
:=
mw
.
c
.
writeFrame
(
mw
.
ctx
,
false
,
mw
.
flate
,
mw
.
opcode
,
p
)
n
,
err
:=
mw
.
c
.
writeFrame
(
mw
.
ctx
,
false
,
mw
.
flate
,
mw
.
opcode
,
p
)
if
err
!=
nil
{
if
err
!=
nil
{
return
n
,
fmt
.
Errorf
(
"failed to write data frame: %w"
,
err
)
return
n
,
fmt
.
Errorf
(
"failed to write data frame: %w"
,
err
)
...
@@ -204,9 +187,14 @@ func (mw *msgWriterState) write(p []byte) (int, error) {
...
@@ -204,9 +187,14 @@ func (mw *msgWriterState) write(p []byte) (int, error) {
}
}
// Close flushes the frame to the connection.
// Close flushes the frame to the connection.
func
(
mw
*
msgWriter
State
)
Close
()
(
err
error
)
{
func
(
mw
*
msgWriter
)
Close
()
(
err
error
)
{
defer
errd
.
Wrap
(
&
err
,
"failed to close writer"
)
defer
errd
.
Wrap
(
&
err
,
"failed to close writer"
)
if
mw
.
closed
{
return
errors
.
New
(
"writer already closed"
)
}
mw
.
closed
=
true
err
=
mw
.
writeMu
.
lock
(
mw
.
ctx
)
err
=
mw
.
writeMu
.
lock
(
mw
.
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -232,7 +220,7 @@ func (mw *msgWriterState) Close() (err error) {
...
@@ -232,7 +220,7 @@ func (mw *msgWriterState) Close() (err error) {
return
nil
return
nil
}
}
func
(
mw
*
msgWriter
State
)
close
()
{
func
(
mw
*
msgWriter
)
close
()
{
if
mw
.
c
.
client
{
if
mw
.
c
.
client
{
mw
.
c
.
writeFrameMu
.
forceLock
()
mw
.
c
.
writeFrameMu
.
forceLock
()
putBufioWriter
(
mw
.
c
.
bw
)
putBufioWriter
(
mw
.
c
.
bw
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment