blob: 794ac30998ca2ee3dfc0b38bade08dc9a8a268a2 [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
Julien Schmidt5b799952014-06-03 13:46:2827func newBuffer(rd io.Reader) buffer {
Julien Schmidt04653f22013-06-03 20:34:2228 var b [defaultBufSize]byte
Julien Schmidt5b799952014-06-03 13:46:2829 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 Schmidt4fe7e922013-10-25 16:15:2736func (b *buffer) fill(need int) 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 Schmidte2532ba2013-06-02 01:40:5454 for {
Julien Schmidt4fe7e922013-10-25 16:15:2755 n, err := b.rd.Read(b.buf[b.length:])
Julien Schmidtccad9562013-03-01 19:31:4356 b.length += n
Julien Schmidt74a64522013-03-03 17:41:1357
Julien Schmidt4fe7e922013-10-25 16:15:2758 if err == nil {
59 if b.length < need {
60 continue
61 }
62 return nil
Julien Schmidt74a64522013-03-03 17:41:1363 }
Julien Schmidt4fe7e922013-10-25 16:15:2764 if b.length >= need && err == io.EOF {
65 return nil
66 }
67 return err
Julien Schmidtccad9562013-03-01 19:31:4368 }
Julien Schmidtccad9562013-03-01 19:31:4369}
70
Julien Schmidt96a4f132013-04-21 12:57:5871// returns next N bytes from buffer.
72// The returned slice is only guaranteed to be valid until the next read
Julien Schmidt4fe7e922013-10-25 16:15:2773func (b *buffer) readNext(need int) ([]byte, error) {
Julien Schmidta6020692013-04-24 14:40:0874 if b.length < need {
75 // refill
Julien Schmidt4fe7e922013-10-25 16:15:2776 if err := b.fill(need); err != nil {
77 return nil, err
Arne Hormann035e9852013-07-11 08:14:2378 }
Julien Schmidtccad9562013-03-01 19:31:4379 }
Julien Schmidta6020692013-04-24 14:40:0880
Julien Schmidt620bcdd2013-10-25 18:29:2281 offset := b.idx
Julien Schmidta6020692013-04-24 14:40:0882 b.idx += need
83 b.length -= need
Julien Schmidt620bcdd2013-10-25 18:29:2284 return b.buf[offset:b.idx], nil
Julien Schmidtccad9562013-03-01 19:31:4385}
Julien Schmidtddf24e62013-10-22 08:54:5586
87// returns a buffer with the requested size.
88// If possible, a slice from the existing buffer is returned.
89// Otherwise a bigger buffer is made.
90// Only one buffer (total) can be used at a time.
Julien Schmidt8751b722013-10-23 15:32:4491func (b *buffer) takeBuffer(length int) []byte {
Julien Schmidtddf24e62013-10-22 08:54:5592 if b.length > 0 {
93 return nil
94 }
95
96 // test (cheap) general case first
97 if length <= defaultBufSize || length <= cap(b.buf) {
98 return b.buf[:length]
99 }
100
101 if length < maxPacketSize {
102 b.buf = make([]byte, length)
103 return b.buf
104 }
105 return make([]byte, length)
106}
107
108// shortcut which can be used if the requested buffer is guaranteed to be
109// smaller than defaultBufSize
110// Only one buffer (total) can be used at a time.
Julien Schmidt8751b722013-10-23 15:32:44111func (b *buffer) takeSmallBuffer(length int) []byte {
Julien Schmidtddf24e62013-10-22 08:54:55112 if b.length == 0 {
113 return b.buf[:length]
114 }
115 return nil
116}
117
118// takeCompleteBuffer returns the complete existing buffer.
119// This can be used if the necessary buffer size is unknown.
120// Only one buffer (total) can be used at a time.
121func (b *buffer) takeCompleteBuffer() []byte {
122 if b.length == 0 {
123 return b.buf
124 }
125 return nil
126}