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

go-sql-driver / mysql / 12100938474

01 Dec 2024 01:08AM UTC coverage: 82.459% (-0.05%) from 82.513%
12100938474

push

github

web-flow
stop double-buffering (#1643)

Since we dropped Go 1.20 support, we do not need double buffering.

This pull request stop double buffering and simplify buffer
implementation a lot.

Fix #1435

31 of 37 new or added lines in 2 files covered. (83.78%)

1 existing line in 1 file now uncovered.

3112 of 3774 relevant lines covered (82.46%)

1386365.2 hits per line

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

80.0
/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
type buffer struct {
26
        buf       []byte // read buffer.
27
        cachedBuf []byte // buffer that will be reused. len(cachedBuf) <= maxCachedBufSize.
28
        nc        net.Conn
29
        timeout   time.Duration
30
}
31

32
// newBuffer allocates and returns a new buffer.
33
func newBuffer(nc net.Conn) buffer {
72,198✔
34
        return buffer{
72,198✔
35
                cachedBuf: make([]byte, defaultBufSize),
72,198✔
36
                nc:        nc,
72,198✔
37
        }
72,198✔
38
}
72,198✔
39

40
// busy returns true if the read buffer is not empty.
41
func (b *buffer) busy() bool {
181,737✔
42
        return len(b.buf) > 0
181,737✔
43
}
181,737✔
44

45
// fill reads into the read buffer until at least _need_ bytes are in it.
46
func (b *buffer) fill(need int) error {
169,640✔
47
        // we'll move the contents of the current buffer to dest before filling it.
169,640✔
48
        dest := b.cachedBuf
169,640✔
49

169,640✔
50
        // grow buffer if necessary to fit the whole packet.
169,640✔
51
        if need > len(dest) {
169,896✔
52
                // Round up to the next multiple of the default size
256✔
53
                dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
256✔
54

256✔
55
                // if the allocated buffer is not too large, move it to backing storage
256✔
56
                // to prevent extra allocations on applications that perform large reads
256✔
57
                if len(dest) <= maxCachedBufSize {
256✔
NEW
58
                        b.cachedBuf = dest
×
UNCOV
59
                }
×
60
        }
61

62
        // move the existing data to the start of the buffer.
63
        n := len(b.buf)
169,640✔
64
        copy(dest[:n], b.buf)
169,640✔
65

169,640✔
66
        for {
340,005✔
67
                if b.timeout > 0 {
170,365✔
68
                        if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
×
69
                                return err
×
70
                        }
×
71
                }
72

73
                nn, err := b.nc.Read(dest[n:])
170,365✔
74
                n += nn
170,365✔
75

170,365✔
76
                if err == nil && n < need {
171,090✔
77
                        continue
725✔
78
                }
79

80
                b.buf = dest[:n]
169,640✔
81

169,640✔
82
                if err == io.EOF {
169,640✔
NEW
83
                        if n < need {
×
NEW
84
                                err = io.ErrUnexpectedEOF
×
NEW
85
                        } else {
×
NEW
86
                                err = nil
×
NEW
87
                        }
×
88
                }
89
                return err
169,640✔
90
        }
91
}
92

93
// returns next N bytes from buffer.
94
// The returned slice is only guaranteed to be valid until the next read
95
func (b *buffer) readNext(need int) ([]byte, error) {
33,963,081✔
96
        if len(b.buf) < need {
34,132,721✔
97
                // refill
169,640✔
98
                if err := b.fill(need); err != nil {
194,451✔
99
                        return nil, err
24,811✔
100
                }
24,811✔
101
        }
102

103
        data := b.buf[:need]
33,938,270✔
104
        b.buf = b.buf[need:]
33,938,270✔
105
        return data, nil
33,938,270✔
106
}
107

108
// takeBuffer returns a buffer with the requested size.
109
// If possible, a slice from the existing buffer is returned.
110
// Otherwise a bigger buffer is made.
111
// Only one buffer (total) can be used at a time.
112
func (b *buffer) takeBuffer(length int) ([]byte, error) {
101,564✔
113
        if b.busy() {
101,564✔
114
                return nil, ErrBusyBuffer
×
115
        }
×
116

117
        // test (cheap) general case first
118
        if length <= len(b.cachedBuf) {
202,968✔
119
                return b.cachedBuf[:length], nil
101,404✔
120
        }
101,404✔
121

122
        if length < maxCachedBufSize {
256✔
123
                b.cachedBuf = make([]byte, length)
96✔
124
                return b.cachedBuf, nil
96✔
125
        }
96✔
126

127
        // buffer is larger than we want to store.
128
        return make([]byte, length), nil
64✔
129
}
130

131
// takeSmallBuffer is shortcut which can be used if length is
132
// known to be smaller than defaultBufSize.
133
// Only one buffer (total) can be used at a time.
134
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
30,408✔
135
        if b.busy() {
30,408✔
136
                return nil, ErrBusyBuffer
×
137
        }
×
138
        return b.cachedBuf[:length], nil
30,408✔
139
}
140

141
// takeCompleteBuffer returns the complete existing buffer.
142
// This can be used if the necessary buffer size is unknown.
143
// cap and len of the returned buffer will be equal.
144
// Only one buffer (total) can be used at a time.
145
func (b *buffer) takeCompleteBuffer() ([]byte, error) {
4,128✔
146
        if b.busy() {
4,128✔
147
                return nil, ErrBusyBuffer
×
148
        }
×
149
        return b.cachedBuf, nil
4,128✔
150
}
151

152
// store stores buf, an updated buffer, if its suitable to do so.
153
func (b *buffer) store(buf []byte) {
64✔
154
        if cap(buf) <= maxCachedBufSize && cap(buf) > cap(b.cachedBuf) {
128✔
155
                b.cachedBuf = buf[:cap(buf)]
64✔
156
        }
64✔
157
}
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