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

Revert "Optimize Patricia tree"

This reverts commit 3bbbe9847675a1300cce193d9efe458b9f0bdd23.

Fixes race conditions in matchers. Impact on benchmarks:

name               old time/op    new time/op    delta
CMuxConnHTTP1-4       664ns ±19%     754ns ±59%     ~            (p=0.796 n=9+10)
CMuxConnHTTP2-4       745ns ±16%     822ns ±26%     ~            (p=0.252 n=9+10)
CMuxConnHTTP1n2-4     930ns ±28%     926ns ±19%     ~           (p=0.912 n=10+10)
CMuxConnHTTP2n1-4    1.18µs ±52%    0.92µs ±14%     ~           (p=0.469 n=10+10)

name               old alloc/op   new alloc/op   delta
CMuxConnHTTP1-4        256B ± 0%      260B ± 0%   +1.56%        (p=0.000 n=10+10)
CMuxConnHTTP2-4        288B ± 0%      288B ± 0%     ~     (all samples are equal)
CMuxConnHTTP1n2-4      288B ± 0%      290B ± 0%   +0.69%        (p=0.000 n=10+10)
CMuxConnHTTP2n1-4      288B ± 0%      292B ± 0%   +1.39%        (p=0.000 n=10+10)

name               old allocs/op  new allocs/op  delta
CMuxConnHTTP1-4        3.00 ± 0%      5.00 ± 0%  +66.67%        (p=0.000 n=10+10)
CMuxConnHTTP2-4        4.00 ± 0%      4.00 ± 0%     ~     (all samples are equal)
CMuxConnHTTP1n2-4      4.00 ± 0%      6.00 ± 0%  +50.00%        (p=0.000 n=10+10)
CMuxConnHTTP2n1-4      4.00 ± 0%      6.00 ± 0%  +50.00%        (p=0.000 n=10+10)
This commit is contained in:
Tamir Duberstein 2016-07-12 12:26:50 -04:00
parent 9421819d79
commit 02b84e9be9
No known key found for this signature in database
GPG Key ID: 1C1E98CC8E17BB89

View File

@ -17,30 +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
}
} }
func newPatriciaTree(bs ...[]byte) *patriciaTree { func newPatriciaTree(b ...[]byte) *patriciaTree {
max := 0 return &patriciaTree{
for _, b := range bs { root: newNode(b),
if max < len(b) {
max = len(b)
}
} }
t := patriciaTree{root: newNode(bs)}
t.mu.buf = make([]byte, max+1)
return &t
} }
func newPatriciaTreeString(strs ...string) *patriciaTree { func newPatriciaTreeString(strs ...string) *patriciaTree {
@ -48,23 +36,17 @@ func newPatriciaTreeString(strs ...string) *patriciaTree {
for i, s := range strs { for i, s := range strs {
b[i] = []byte(s) b[i] = []byte(s)
} }
return newPatriciaTree(b...) return &patriciaTree{
root: newNode(b),
}
} }
func (t *patriciaTree) matchPrefix(r io.Reader) bool { func (t *patriciaTree) matchPrefix(r io.Reader) bool {
t.mu.Lock() return t.root.match(r, 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 {
t.mu.Lock() return t.root.match(r, 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 {
@ -154,30 +136,52 @@ func splitPrefix(bss [][]byte) (prefix []byte, rest [][]byte) {
return prefix, rest return prefix, rest
} }
func (n *ptNode) match(b []byte, prefix bool) bool { func readBytes(r io.Reader, n int) (b []byte, err error) {
l := len(n.prefix) b = make([]byte, n)
if l > 0 { o := 0
if l > len(b) { for o < n {
l = len(b) nr, err := r.Read(b[o:])
if err != nil && err != io.EOF {
return b, err
} }
if !bytes.Equal(b[:l], n.prefix) {
o += nr
if err == io.EOF {
break
}
}
return b[:o], nil
}
func (n *ptNode) match(r io.Reader, prefix bool) bool {
if l := len(n.prefix); l > 0 {
b, err := readBytes(r, l)
if err != nil || len(b) != l || !bytes.Equal(b, n.prefix) {
return false return false
} }
} }
if n.terminal && (prefix || len(n.prefix) == len(b)) { if prefix && n.terminal {
return true return true
} }
nextN, ok := n.next[b[l]] b := make([]byte, 1)
if !ok { for {
return false nr, err := r.Read(b)
if nr != 0 {
break
}
if err == io.EOF {
return n.terminal
}
if err != nil {
return false
}
} }
if l == len(b) { nextN, ok := n.next[b[0]]
b = b[l:l] return ok && nextN.match(r, prefix)
} else {
b = b[l+1:]
}
return nextN.match(b, prefix)
} }