2
0
mirror of https://github.com/soheilhy/cmux.git synced 2024-09-19 18:45:48 +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 (
"bytes"
"io"
"sync"
)
// patriciaTree is a simple patricia tree that handles []byte instead of string
// and cannot be changed after instantiation.
type patriciaTree struct {
root *ptNode
mu struct {
sync.Mutex
buf []byte // preallocated buffer to read data while matching
}
}
func newPatriciaTree(bs ...[]byte) *patriciaTree {
max := 0
for _, b := range bs {
if max < len(b) {
max = len(b)
}
func newPatriciaTree(b ...[]byte) *patriciaTree {
return &patriciaTree{
root: newNode(b),
}
t := patriciaTree{root: newNode(bs)}
t.mu.buf = make([]byte, max+1)
return &t
}
func newPatriciaTreeString(strs ...string) *patriciaTree {
@ -48,23 +36,17 @@ func newPatriciaTreeString(strs ...string) *patriciaTree {
for i, s := range strs {
b[i] = []byte(s)
}
return newPatriciaTree(b...)
return &patriciaTree{
root: newNode(b),
}
}
func (t *patriciaTree) matchPrefix(r io.Reader) bool {
t.mu.Lock()
defer t.mu.Unlock()
n, _ := io.ReadFull(r, t.mu.buf)
return t.root.match(t.mu.buf[:n], true)
return t.root.match(r, true)
}
func (t *patriciaTree) match(r io.Reader) bool {
t.mu.Lock()
defer t.mu.Unlock()
n, _ := io.ReadFull(r, t.mu.buf)
return t.root.match(t.mu.buf[:n], false)
return t.root.match(r, false)
}
type ptNode struct {
@ -154,30 +136,52 @@ func splitPrefix(bss [][]byte) (prefix []byte, rest [][]byte) {
return prefix, rest
}
func (n *ptNode) match(b []byte, prefix bool) bool {
l := len(n.prefix)
if l > 0 {
if l > len(b) {
l = len(b)
func readBytes(r io.Reader, n int) (b []byte, err error) {
b = make([]byte, n)
o := 0
for o < n {
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
}
}
if n.terminal && (prefix || len(n.prefix) == len(b)) {
if prefix && n.terminal {
return true
}
nextN, ok := n.next[b[l]]
if !ok {
return false
b := make([]byte, 1)
for {
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) {
b = b[l:l]
} else {
b = b[l+1:]
}
return nextN.match(b, prefix)
nextN, ok := n.next[b[0]]
return ok && nextN.match(r, prefix)
}