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

go-sql-driver / mysql / 11956769898

21 Nov 2024 03:48PM UTC coverage: 82.508% (+0.09%) from 82.418%
11956769898

push

github

web-flow
Reduce "busy buffer" logs (#1641)

Reduce the use of `errBadConnNoWrite` to improve maintainability.

ResetSession() and IsValid() checks if the buffer is busy. This reduces
the risk of busy buffer error during connection in use. In principle,
the risk of this is zero. So I removed errBadConnNoWrite when checking
the busy buffer.

After this change, only `writePacke()` returns errBadConnNoWrite.

Additionally, I do not send COM_QUIT when readPacket() encounter read error.
It caused "busy buffer" error too and hide real errors.

12 of 22 new or added lines in 3 files covered. (54.55%)

7 existing lines in 2 files now uncovered.

3132 of 3796 relevant lines covered (82.51%)

1387894.38 hits per line

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

83.84
/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 {
71,917✔
38
        fg := make([]byte, defaultBufSize)
71,917✔
39
        return buffer{
71,917✔
40
                buf:  fg,
71,917✔
41
                nc:   nc,
71,917✔
42
                dbuf: [2][]byte{fg, nil},
71,917✔
43
        }
71,917✔
44
}
71,917✔
45

46
// busy returns true if the buffer contains some read data.
47
func (b *buffer) busy() bool {
43,164✔
48
        return b.length > 0
43,164✔
49
}
43,164✔
50

51
// flip replaces the active buffer with the background buffer
52
// this is a delayed flip that simply increases the buffer counter;
53
// the actual flip will be performed the next time we call `buffer.fill`
54
func (b *buffer) flip() {
5,940✔
55
        b.flipcnt += 1
5,940✔
56
}
5,940✔
57

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

255,121✔
67
        // grow buffer if necessary to fit the whole packet.
255,121✔
68
        if need > len(dest) {
257,233✔
69
                // Round up to the next multiple of the default size
2,112✔
70
                dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
2,112✔
71

2,112✔
72
                // if the allocated buffer is not too large, move it to backing storage
2,112✔
73
                // to prevent extra allocations on applications that perform large reads
2,112✔
74
                if len(dest) <= maxCachedBufSize {
3,968✔
75
                        b.dbuf[b.flipcnt&1] = dest
1,856✔
76
                }
1,856✔
77
        }
78

79
        // if we're filling the fg buffer, move the existing data to the start of it.
80
        // if we're filling the bg buffer, copy over the data
81
        if n > 0 {
348,273✔
82
                copy(dest[:n], b.buf[b.idx:])
93,152✔
83
        }
93,152✔
84

85
        b.buf = dest
255,121✔
86
        b.idx = 0
255,121✔
87

255,121✔
88
        for {
510,952✔
89
                if b.timeout > 0 {
255,831✔
90
                        if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
×
91
                                return err
×
92
                        }
×
93
                }
94

95
                nn, err := b.nc.Read(b.buf[n:])
255,831✔
96
                n += nn
255,831✔
97

255,831✔
98
                switch err {
255,831✔
99
                case nil:
229,956✔
100
                        if n < need {
230,666✔
101
                                continue
710✔
102
                        }
103
                        b.length = n
229,246✔
104
                        return nil
229,246✔
105

106
                case io.EOF:
×
107
                        if n >= need {
×
108
                                b.length = n
×
109
                                return nil
×
110
                        }
×
111
                        return io.ErrUnexpectedEOF
×
112

113
                default:
25,875✔
114
                        return err
25,875✔
115
                }
116
        }
117
}
118

119
// returns next N bytes from buffer.
120
// The returned slice is only guaranteed to be valid until the next read
121
func (b *buffer) readNext(need int) ([]byte, error) {
33,953,733✔
122
        if b.length < need {
34,208,854✔
123
                // refill
255,121✔
124
                if err := b.fill(need); err != nil {
280,996✔
125
                        return nil, err
25,875✔
126
                }
25,875✔
127
        }
128

129
        offset := b.idx
33,927,858✔
130
        b.idx += need
33,927,858✔
131
        b.length -= need
33,927,858✔
132
        return b.buf[offset:b.idx], nil
33,927,858✔
133
}
134

135
// takeBuffer returns a buffer with the requested size.
136
// If possible, a slice from the existing buffer is returned.
137
// Otherwise a bigger buffer is made.
138
// Only one buffer (total) can be used at a time.
139
func (b *buffer) takeBuffer(length int) ([]byte, error) {
101,259✔
140
        if b.length > 0 {
101,259✔
141
                return nil, ErrBusyBuffer
×
142
        }
×
143

144
        // test (cheap) general case first
145
        if length <= cap(b.buf) {
202,358✔
146
                return b.buf[:length], nil
101,099✔
147
        }
101,099✔
148

149
        if length < maxPacketSize {
256✔
150
                b.buf = make([]byte, length)
96✔
151
                return b.buf, nil
96✔
152
        }
96✔
153

154
        // buffer is larger than we want to store.
155
        return make([]byte, length), nil
64✔
156
}
157

158
// takeSmallBuffer is shortcut which can be used if length is
159
// known to be smaller than defaultBufSize.
160
// Only one buffer (total) can be used at a time.
161
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
25,290✔
162
        if b.length > 0 {
25,290✔
UNCOV
163
                return nil, ErrBusyBuffer
×
UNCOV
164
        }
×
165
        return b.buf[:length], nil
25,290✔
166
}
167

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

179
// store stores buf, an updated buffer, if its suitable to do so.
180
func (b *buffer) store(buf []byte) error {
64✔
181
        if b.length > 0 {
64✔
182
                return ErrBusyBuffer
×
183
        } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
128✔
184
                b.buf = buf[:cap(buf)]
64✔
185
        }
64✔
186
        return nil
64✔
187
}
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

© 2026 Coveralls, Inc