2
0
mirror of https://github.com/soheilhy/cmux.git synced 2024-11-14 11:31:28 +08:00

Add locking to patricia tree

Fixes race conditions in matchers. Impact on benchmarks:

name               old time/op    new time/op    delta
CMuxConnHTTP1-4       664ns ±19%     849ns ± 6%  +27.91%         (p=0.000 n=9+10)
CMuxConnHTTP2-4       745ns ±16%     699ns ± 9%     ~            (p=0.075 n=9+10)
CMuxConnHTTP1n2-4     930ns ±28%    1079ns ± 4%  +16.00%         (p=0.022 n=10+9)
CMuxConnHTTP2n1-4    1.18µs ±52%    0.98µs ±13%     ~           (p=1.000 n=10+10)

name               old alloc/op   new alloc/op   delta
CMuxConnHTTP1-4        256B ± 0%      256B ± 0%     ~     (all samples are equal)
CMuxConnHTTP2-4        288B ± 0%      288B ± 0%     ~     (all samples are equal)
CMuxConnHTTP1n2-4      288B ± 0%      288B ± 0%     ~     (all samples are equal)
CMuxConnHTTP2n1-4      288B ± 0%      288B ± 0%     ~     (all samples are equal)

name               old allocs/op  new allocs/op  delta
CMuxConnHTTP1-4        3.00 ± 0%      3.00 ± 0%     ~     (all samples are equal)
CMuxConnHTTP2-4        4.00 ± 0%      4.00 ± 0%     ~     (all samples are equal)
CMuxConnHTTP1n2-4      4.00 ± 0%      4.00 ± 0%     ~     (all samples are equal)
CMuxConnHTTP2n1-4      4.00 ± 0%      4.00 ± 0%     ~     (all samples are equal)
This commit is contained in:
Tamir Duberstein 2016-07-12 12:19:27 -04:00
parent f4d9321cb4
commit 9421819d79
No known key found for this signature in database
GPG Key ID: 1C1E98CC8E17BB89

View File

@ -17,14 +17,18 @@ package cmux
import ( import (
"bytes" "bytes"
"io" "io"
"sync"
) )
// patriciaTree is a simple patricia tree that handles []byte instead of string // patriciaTree is a simple patricia tree that handles []byte instead of string
// and cannot be changed after instantiation. // and cannot be changed after instantiation.
type patriciaTree struct { type patriciaTree struct {
root *ptNode root *ptNode
mu struct {
sync.Mutex
buf []byte // preallocated buffer to read data while matching buf []byte // preallocated buffer to read data while matching
} }
}
func newPatriciaTree(bs ...[]byte) *patriciaTree { func newPatriciaTree(bs ...[]byte) *patriciaTree {
max := 0 max := 0
@ -33,10 +37,10 @@ func newPatriciaTree(bs ...[]byte) *patriciaTree {
max = len(b) max = len(b)
} }
} }
return &patriciaTree{ t := patriciaTree{root: newNode(bs)}
root: newNode(bs), t.mu.buf = make([]byte, max+1)
buf: make([]byte, max+1),
} return &t
} }
func newPatriciaTreeString(strs ...string) *patriciaTree { func newPatriciaTreeString(strs ...string) *patriciaTree {
@ -48,13 +52,19 @@ func newPatriciaTreeString(strs ...string) *patriciaTree {
} }
func (t *patriciaTree) matchPrefix(r io.Reader) bool { func (t *patriciaTree) matchPrefix(r io.Reader) bool {
n, _ := io.ReadFull(r, t.buf) t.mu.Lock()
return t.root.match(t.buf[:n], true) defer t.mu.Unlock()
n, _ := io.ReadFull(r, t.mu.buf)
return t.root.match(t.mu.buf[:n], true)
} }
func (t *patriciaTree) match(r io.Reader) bool { func (t *patriciaTree) match(r io.Reader) bool {
n, _ := io.ReadFull(r, t.buf) t.mu.Lock()
return t.root.match(t.buf[:n], false) defer t.mu.Unlock()
n, _ := io.ReadFull(r, t.mu.buf)
return t.root.match(t.mu.buf[:n], false)
} }
type ptNode struct { type ptNode struct {