• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-sql-driver / mysql / 3601392501

pending completion
3601392501

push

github

GitHub
update changelog for Version 1.7 (#1376)

2932 of 3584 relevant lines covered (81.81%)

1490385.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.33
/buffer.go
1
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2
//
3
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
4
//
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

9
package mysql
10

11
import (
12
        "io"
13
        "net"
14
        "time"
15
)
16

17
const defaultBufSize = 4096
18
const maxCachedBufSize = 256 * 1024
19

20
// A buffer which is used for both reading and writing.
21
// This is possible since communication on each connection is synchronous.
22
// In other words, we can't write and read simultaneously on the same connection.
23
// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
24
// Also highly optimized for this particular use case.
25
// This buffer is backed by two byte slices in a double-buffering scheme
26
type buffer struct {
27
        buf     []byte // buf is a byte buffer who's length and capacity are equal.
28
        nc      net.Conn
29
        idx     int
30
        length  int
31
        timeout time.Duration
32
        dbuf    [2][]byte // dbuf is an array with the two byte slices that back this buffer
33
        flipcnt uint      // flipccnt is the current buffer counter for double-buffering
34
}
35

36
// newBuffer allocates and returns a new buffer.
37
func newBuffer(nc net.Conn) buffer {
12,199✔
38
        fg := make([]byte, defaultBufSize)
12,199✔
39
        return buffer{
12,199✔
40
                buf:  fg,
12,199✔
41
                nc:   nc,
12,199✔
42
                dbuf: [2][]byte{fg, nil},
12,199✔
43
        }
12,199✔
44
}
12,199✔
45

46
// flip replaces the active buffer with the background buffer
47
// this is a delayed flip that simply increases the buffer counter;
48
// the actual flip will be performed the next time we call `buffer.fill`
49
func (b *buffer) flip() {
9,699✔
50
        b.flipcnt += 1
9,699✔
51
}
9,699✔
52

53
// fill reads into the buffer until at least _need_ bytes are in it
54
func (b *buffer) fill(need int) error {
620,080✔
55
        n := b.length
620,080✔
56
        // fill data into its double-buffering target: if we've called
620,080✔
57
        // flip on this buffer, we'll be copying to the background buffer,
620,080✔
58
        // and then filling it with network data; otherwise we'll just move
620,080✔
59
        // the contents of the current buffer to the front before filling it
620,080✔
60
        dest := b.dbuf[b.flipcnt&1]
620,080✔
61

620,080✔
62
        // grow buffer if necessary to fit the whole packet.
620,080✔
63
        if need > len(dest) {
624,164✔
64
                // Round up to the next multiple of the default size
4,084✔
65
                dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
4,084✔
66

4,084✔
67
                // if the allocated buffer is not too large, move it to backing storage
4,084✔
68
                // to prevent extra allocations on applications that perform large reads
4,084✔
69
                if len(dest) <= maxCachedBufSize {
7,898✔
70
                        b.dbuf[b.flipcnt&1] = dest
3,814✔
71
                }
3,814✔
72
        }
73

74
        // if we're filling the fg buffer, move the existing data to the start of it.
75
        // if we're filling the bg buffer, copy over the data
76
        if n > 0 {
740,916✔
77
                copy(dest[:n], b.buf[b.idx:])
120,823✔
78
        }
120,823✔
79

80
        b.buf = dest
620,093✔
81
        b.idx = 0
620,093✔
82

620,093✔
83
        for {
1,249,048✔
84
                if b.timeout > 0 {
628,955✔
85
                        if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
×
86
                                return err
×
87
                        }
×
88
                }
89

90
                nn, err := b.nc.Read(b.buf[n:])
628,988✔
91
                n += nn
628,988✔
92

628,988✔
93
                switch err {
628,988✔
94
                case nil:
628,451✔
95
                        if n < need {
637,931✔
96
                                continue
9,480✔
97
                        }
98
                        b.length = n
619,001✔
99
                        return nil
619,001✔
100

101
                case io.EOF:
×
102
                        if n >= need {
×
103
                                b.length = n
×
104
                                return nil
×
105
                        }
×
106
                        return io.ErrUnexpectedEOF
×
107

108
                default:
444✔
109
                        return err
444✔
110
                }
111
        }
112
}
113

114
// returns next N bytes from buffer.
115
// The returned slice is only guaranteed to be valid until the next read
116
func (b *buffer) readNext(need int) ([]byte, error) {
43,613,348✔
117
        if b.length < need {
44,233,593✔
118
                // refill
620,245✔
119
                if err := b.fill(need); err != nil {
620,689✔
120
                        return nil, err
444✔
121
                }
444✔
122
        }
123

124
        offset := b.idx
43,611,987✔
125
        b.idx += need
43,611,987✔
126
        b.length -= need
43,611,987✔
127
        return b.buf[offset:b.idx], nil
43,611,987✔
128
}
129

130
// takeBuffer returns a buffer with the requested size.
131
// If possible, a slice from the existing buffer is returned.
132
// Otherwise a bigger buffer is made.
133
// Only one buffer (total) can be used at a time.
134
func (b *buffer) takeBuffer(length int) ([]byte, error) {
465,265✔
135
        if b.length > 0 {
465,265✔
136
                return nil, ErrBusyBuffer
×
137
        }
×
138

139
        // test (cheap) general case first
140
        if length <= cap(b.buf) {
930,191✔
141
                return b.buf[:length], nil
464,975✔
142
        }
464,975✔
143

144
        if length < maxPacketSize {
405✔
145
                b.buf = make([]byte, length)
162✔
146
                return b.buf, nil
162✔
147
        }
162✔
148

149
        // buffer is larger than we want to store.
150
        return make([]byte, length), nil
81✔
151
}
152

153
// takeSmallBuffer is shortcut which can be used if length is
154
// known to be smaller than defaultBufSize.
155
// Only one buffer (total) can be used at a time.
156
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
25,782✔
157
        if b.length > 0 {
25,782✔
158
                return nil, ErrBusyBuffer
×
159
        }
×
160
        return b.buf[:length], nil
25,782✔
161
}
162

163
// takeCompleteBuffer returns the complete existing buffer.
164
// This can be used if the necessary buffer size is unknown.
165
// cap and len of the returned buffer will be equal.
166
// Only one buffer (total) can be used at a time.
167
func (b *buffer) takeCompleteBuffer() ([]byte, error) {
6,534✔
168
        if b.length > 0 {
6,534✔
169
                return nil, ErrBusyBuffer
×
170
        }
×
171
        return b.buf, nil
6,534✔
172
}
173

174
// store stores buf, an updated buffer, if its suitable to do so.
175
func (b *buffer) store(buf []byte) error {
81✔
176
        if b.length > 0 {
81✔
177
                return ErrBusyBuffer
×
178
        } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
162✔
179
                b.buf = buf[:cap(buf)]
81✔
180
        }
81✔
181
        return nil
81✔
182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc