blob: ed13fa28345f9dca806a3c911b32f09c4b0e273f [file] [log] [blame]
Julien Schmidtccad9562013-03-01 19:31:431// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2//
Julien Schmidtff970042013-09-13 18:36:043// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
Julien Schmidtccad9562013-03-01 19:31:434//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this file,
7// You can obtain one at http://mozilla.org/MPL/2.0/.
8
9package mysql
10
Julien Schmidta6020692013-04-24 14:40:0811import "io"
Julien Schmidtccad9562013-03-01 19:31:4312
Julien Schmidta6020692013-04-24 14:40:0813const defaultBufSize = 4096
Julien Schmidtccad9562013-03-01 19:31:4314
Julien Schmidtddf24e62013-10-22 08:54:5515// A buffer which is used for both reading and writing.
16// This is possible since communication on each connection is synchronous.
17// In other words, we can't write and read simultaneously on the same connection.
18// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
Julien Schmidte2532ba2013-06-02 01:40:5419// Also highly optimized for this particular use case.
Julien Schmidtccad9562013-03-01 19:31:4320type buffer struct {
21 buf []byte
22 rd io.Reader
23 idx int
24 length int
25}
26
27func newBuffer(rd io.Reader) *buffer {
Julien Schmidt04653f22013-06-03 20:34:2228 var b [defaultBufSize]byte
Julien Schmidtccad9562013-03-01 19:31:4329 return &buffer{
Julien Schmidt04653f22013-06-03 20:34:2230 buf: b[:],
Julien Schmidtccad9562013-03-01 19:31:4331 rd: rd,
32 }
33}
34
Julien Schmidtc2dde2d2013-04-21 13:16:4435// fill reads into the buffer until at least _need_ bytes are in it
Julien Schmidtccad9562013-03-01 19:31:4336func (b *buffer) fill(need int) (err error) {
Julien Schmidtc2dde2d2013-04-21 13:16:4437 // move existing data to the beginning
38 if b.length > 0 && b.idx > 0 {
39 copy(b.buf[0:b.length], b.buf[b.idx:])
40 }
41
Julien Schmidta6020692013-04-24 14:40:0842 // grow buffer if necessary
Julien Schmidtddf24e62013-10-22 08:54:5543 // TODO: let the buffer shrink again at some point
44 // Maybe keep the org buf slice and swap back?
Julien Schmidta6020692013-04-24 14:40:0845 if need > len(b.buf) {
Julien Schmidtddf24e62013-10-22 08:54:5546 // Round up to the next multiple of the default size
47 newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
Julien Schmidt04653f22013-06-03 20:34:2248 copy(newBuf, b.buf)
49 b.buf = newBuf
Julien Schmidta6020692013-04-24 14:40:0850 }
51
Julien Schmidtccad9562013-03-01 19:31:4352 b.idx = 0
Julien Schmidtccad9562013-03-01 19:31:4353
Julien Schmidtd1deaee2013-03-06 02:06:5054 var n int
Julien Schmidte2532ba2013-06-02 01:40:5455 for {
Julien Schmidtccad9562013-03-01 19:31:4356 n, err = b.rd.Read(b.buf[b.length:])
57 b.length += n
Julien Schmidt74a64522013-03-03 17:41:1358
Julien Schmidte2532ba2013-06-02 01:40:5459 if b.length < need && err == nil {
Julien Schmidt74a64522013-03-03 17:41:1360 continue
61 }
62 return // err
Julien Schmidtccad9562013-03-01 19:31:4363 }
Julien Schmidtb494bac2013-06-02 13:53:1964 return
Julien Schmidtccad9562013-03-01 19:31:4365}
66
Julien Schmidt96a4f132013-04-21 12:57:5867// returns next N bytes from buffer.
68// The returned slice is only guaranteed to be valid until the next read
69func (b *buffer) readNext(need int) (p []byte, err error) {
Julien Schmidta6020692013-04-24 14:40:0870 if b.length < need {
71 // refill
72 err = b.fill(need) // err deferred
Arne Hormann035e9852013-07-11 08:14:2373 if err == io.EOF && b.length >= need {
74 err = nil
75 }
Julien Schmidtccad9562013-03-01 19:31:4376 }
Julien Schmidta6020692013-04-24 14:40:0877
78 p = b.buf[b.idx : b.idx+need]
79 b.idx += need
80 b.length -= need
Julien Schmidtccad9562013-03-01 19:31:4381 return
82}
Julien Schmidtddf24e62013-10-22 08:54:5583
84// returns a buffer with the requested size.
85// If possible, a slice from the existing buffer is returned.
86// Otherwise a bigger buffer is made.
87// Only one buffer (total) can be used at a time.
Julien Schmidt8751b722013-10-23 15:32:4488func (b *buffer) takeBuffer(length int) []byte {
Julien Schmidtddf24e62013-10-22 08:54:5589 if b.length > 0 {
90 return nil
91 }
92
93 // test (cheap) general case first
94 if length <= defaultBufSize || length <= cap(b.buf) {
95 return b.buf[:length]
96 }
97
98 if length < maxPacketSize {
99 b.buf = make([]byte, length)
100 return b.buf
101 }
102 return make([]byte, length)
103}
104
105// shortcut which can be used if the requested buffer is guaranteed to be
106// smaller than defaultBufSize
107// Only one buffer (total) can be used at a time.
Julien Schmidt8751b722013-10-23 15:32:44108func (b *buffer) takeSmallBuffer(length int) []byte {
Julien Schmidtddf24e62013-10-22 08:54:55109 if b.length == 0 {
110 return b.buf[:length]
111 }
112 return nil
113}
114
115// takeCompleteBuffer returns the complete existing buffer.
116// This can be used if the necessary buffer size is unknown.
117// Only one buffer (total) can be used at a time.
118func (b *buffer) takeCompleteBuffer() []byte {
119 if b.length == 0 {
120 return b.buf
121 }
122 return nil
123}