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

go-sql-driver / mysql / 11984367075

23 Nov 2024 05:07AM UTC coverage: 82.454% (-0.05%) from 82.508%
11984367075

Pull #1643

github

methane
stop double-buffering
Pull Request #1643: stop double-buffering

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

1 existing line in 1 file now uncovered.

3111 of 3773 relevant lines covered (82.45%)

1386796.03 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,035✔
34
        return buffer{
72,035✔
35
                cachedBuf: make([]byte, defaultBufSize),
72,035✔
36
                nc:        nc,
72,035✔
37
        }
72,035✔
38
}
72,035✔
39

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

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

171,699✔
50
        // grow buffer if necessary to fit the whole packet.
171,699✔
51
        if need > len(dest) {
171,955✔
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)
171,699✔
64
        copy(dest[:n], b.buf)
171,699✔
65

171,699✔
66
        for {
344,114✔
67
                if b.timeout > 0 {
172,415✔
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:])
172,415✔
74
                n += nn
172,415✔
75

172,415✔
76
                if err == nil && n < need {
173,131✔
77
                        continue
716✔
78
                }
79

80
                b.buf = dest[:n]
171,699✔
81

171,699✔
82
                if err == io.EOF {
171,699✔
NEW
83
                        if n < need {
×
NEW
84
                                err = io.ErrUnexpectedEOF
×
NEW
85
                        } else {
×
NEW
86
                                err = nil
×
NEW
87
                        }
×
88
                }
89
                return err
171,699✔
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,966,726✔
96
        if len(b.buf) < need {
34,138,425✔
97
                // refill
171,699✔
98
                if err := b.fill(need); err != nil {
196,963✔
99
                        return nil, err
25,264✔
100
                }
25,264✔
101
        }
102

103
        data := b.buf[:need]
33,941,462✔
104
        b.buf = b.buf[need:]
33,941,462✔
105
        return data, nil
33,941,462✔
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,581✔
113
        if b.busy() {
101,581✔
114
                return nil, ErrBusyBuffer
×
115
        }
×
116

117
        // test (cheap) general case first
118
        if length <= len(b.cachedBuf) {
203,002✔
119
                return b.cachedBuf[:length], nil
101,421✔
120
        }
101,421✔
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) {
31,096✔
135
        if b.busy() {
31,096✔
136
                return nil, ErrBusyBuffer
×
137
        }
×
138
        return b.cachedBuf[:length], nil
31,096✔
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