Skip to content

Commit 70c4fbb

Browse files
GODRIVER-3533 Optimize value reader and writer
1 parent 7791095 commit 70c4fbb

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

bson/marshal.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ func Marshal(val interface{}) ([]byte, error) {
7474
}
7575
}()
7676
sw.Reset()
77-
vw := NewDocumentWriter(sw)
77+
78+
vw := getValueWriter(sw)
79+
defer putValueWriter(vw)
80+
7881
enc := encPool.Get().(*Encoder)
7982
defer encPool.Put(enc)
8083
enc.Reset(vw)

bson/unmarshal.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ type ValueUnmarshaler interface {
4343
// pointer, the pointer is set to nil without calling UnmarshalBSONValue.
4444
func Unmarshal(data []byte, val interface{}) error {
4545
vr := newDocumentReader(bytes.NewReader(data))
46+
defer releaseDocumentReader(vr)
47+
4648
if l, err := vr.peekLength(); err != nil {
4749
return err
4850
} else if int(l) != len(data) {

bson/value_reader.go

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"fmt"
1414
"io"
1515
"math"
16+
"sync"
1617
)
1718

1819
var _ ValueReader = &valueReader{}
@@ -29,13 +30,30 @@ type vrState struct {
2930
end int64
3031
}
3132

33+
var bufioReaderPool = sync.Pool{
34+
New: func() interface{} {
35+
return bufio.NewReader(nil)
36+
},
37+
}
38+
39+
var vrPool = sync.Pool{
40+
New: func() interface{} {
41+
return &valueReader{
42+
stack: make([]vrState, 1, 5),
43+
}
44+
},
45+
}
46+
3247
// valueReader is for reading BSON values.
3348
type valueReader struct {
34-
r *bufio.Reader
35-
offset int64
49+
r *bufio.Reader
50+
ra io.ReaderAt // The underlying reader
3651

37-
stack []vrState
38-
frame int64
52+
poolReader bool // Set if r is from bufioReaderPool
53+
54+
offset int64
55+
stack []vrState
56+
frame int64
3957
}
4058

4159
// NewDocumentReader returns a ValueReader using b for the underlying BSON
@@ -57,14 +75,33 @@ func newValueReader(t Type, r io.Reader) ValueReader {
5775
}
5876

5977
func newDocumentReader(r io.Reader) *valueReader {
60-
stack := make([]vrState, 1, 5)
61-
stack[0] = vrState{
62-
mode: mTopLevel,
63-
}
64-
return &valueReader{
65-
r: bufio.NewReader(r),
66-
stack: stack,
78+
vr := vrPool.Get().(*valueReader)
79+
80+
vr.offset = 0
81+
vr.frame = 0
82+
vr.poolReader = true
83+
84+
vr.stack = vr.stack[:1]
85+
vr.stack[0].mode = mTopLevel
86+
87+
br := bufioReaderPool.Get().(*bufio.Reader)
88+
br.Reset(r)
89+
vr.r = br
90+
91+
return vr
92+
}
93+
94+
func releaseDocumentReader(vr *valueReader) {
95+
if !vr.poolReader {
96+
return
6797
}
98+
99+
bufioReaderPool.Put(vr.r)
100+
vr.r = nil
101+
vr.poolReader = false
102+
103+
vr.ra = nil
104+
vrPool.Put(vr)
68105
}
69106

70107
func (vr *valueReader) advanceFrame() {
@@ -253,14 +290,18 @@ func (vr *valueReader) appendNextElement(dst []byte) ([]byte, error) {
253290
return nil, err
254291
}
255292

256-
buf := make([]byte, length)
257-
_, err = io.ReadFull(vr.r, buf)
293+
buf, err := vr.r.Peek(int(length))
258294
if err != nil {
259295
return nil, err
260296
}
297+
261298
dst = append(dst, buf...)
262-
vr.offset += int64(len(buf))
263-
return dst, err
299+
if _, err = vr.r.Discard(int(length)); err != nil {
300+
return nil, err
301+
}
302+
303+
vr.offset += int64(length)
304+
return dst, nil
264305
}
265306

266307
func (vr *valueReader) readValueBytes(dst []byte) (Type, []byte, error) {

bson/value_writer.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ var vwPool = sync.Pool{
2626
},
2727
}
2828

29+
func getValueWriter(w io.Writer) *valueWriter {
30+
vw := vwPool.Get().(*valueWriter)
31+
32+
vw.reset(vw.buf)
33+
vw.buf = vw.buf[:0]
34+
vw.w = w
35+
36+
return vw
37+
}
38+
2939
func putValueWriter(vw *valueWriter) {
3040
if vw != nil {
3141
vw.w = nil // don't leak the writer

0 commit comments

Comments
 (0)