Source File
	buffer.go
Belonging Package
	github.com/go-sql-driver/mysql
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package//// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.//// This Source Code Form is subject to the terms of the Mozilla Public// License, v. 2.0. If a copy of the MPL was not distributed with this file,// You can obtain one at http://mozilla.org/MPL/2.0/.package mysqlimport ()const defaultBufSize = 4096const maxCachedBufSize = 256 * 1024// A buffer which is used for both reading and writing.// This is possible since communication on each connection is synchronous.// In other words, we can't write and read simultaneously on the same connection.// The buffer is similar to bufio.Reader / Writer but zero-copy-ish// Also highly optimized for this particular use case.// This buffer is backed by two byte slices in a double-buffering schemetype buffer struct {buf []byte // buf is a byte buffer who's length and capacity are equal.nc net.Connidx intlength inttimeout time.Durationdbuf [2][]byte // dbuf is an array with the two byte slices that back this bufferflipcnt uint // flipccnt is the current buffer counter for double-buffering}// newBuffer allocates and returns a new buffer.func newBuffer( net.Conn) buffer {:= make([]byte, defaultBufSize)return buffer{buf: ,nc: ,dbuf: [2][]byte{, nil},}}// flip replaces the active buffer with the background buffer// this is a delayed flip that simply increases the buffer counter;// the actual flip will be performed the next time we call `buffer.fill`func ( *buffer) () {.flipcnt += 1}// fill reads into the buffer until at least _need_ bytes are in itfunc ( *buffer) ( int) error {:= .length// fill data into its double-buffering target: if we've called// flip on this buffer, we'll be copying to the background buffer,// and then filling it with network data; otherwise we'll just move// the contents of the current buffer to the front before filling it:= .dbuf[.flipcnt&1]// grow buffer if necessary to fit the whole packet.if > len() {// Round up to the next multiple of the default size= make([]byte, ((/defaultBufSize)+1)*defaultBufSize)// if the allocated buffer is not too large, move it to backing storage// to prevent extra allocations on applications that perform large readsif len() <= maxCachedBufSize {.dbuf[.flipcnt&1] =}}// if we're filling the fg buffer, move the existing data to the start of it.// if we're filling the bg buffer, copy over the dataif > 0 {copy([:], .buf[.idx:])}.buf =.idx = 0for {if .timeout > 0 {if := .nc.SetReadDeadline(time.Now().Add(.timeout)); != nil {return}}, := .nc.Read(.buf[:])+=switch {case nil:if < {continue}.length =return nilcase io.EOF:if >= {.length =return nil}return io.ErrUnexpectedEOFdefault:return}}}// returns next N bytes from buffer.// The returned slice is only guaranteed to be valid until the next readfunc ( *buffer) ( int) ([]byte, error) {if .length < {// refillif := .fill(); != nil {return nil,}}:= .idx.idx +=.length -=return .buf[:.idx], nil}// takeBuffer returns a buffer with the requested size.// If possible, a slice from the existing buffer is returned.// Otherwise a bigger buffer is made.// Only one buffer (total) can be used at a time.func ( *buffer) ( int) ([]byte, error) {if .length > 0 {return nil, ErrBusyBuffer}// test (cheap) general case firstif <= cap(.buf) {return .buf[:], nil}if < maxPacketSize {.buf = make([]byte, )return .buf, nil}// buffer is larger than we want to store.return make([]byte, ), nil}// takeSmallBuffer is shortcut which can be used if length is// known to be smaller than defaultBufSize.// Only one buffer (total) can be used at a time.func ( *buffer) ( int) ([]byte, error) {if .length > 0 {return nil, ErrBusyBuffer}return .buf[:], nil}// takeCompleteBuffer returns the complete existing buffer.// This can be used if the necessary buffer size is unknown.// cap and len of the returned buffer will be equal.// Only one buffer (total) can be used at a time.func ( *buffer) () ([]byte, error) {if .length > 0 {return nil, ErrBusyBuffer}return .buf, nil}// store stores buf, an updated buffer, if its suitable to do so.func ( *buffer) ( []byte) error {if .length > 0 {return ErrBusyBuffer} else if cap() <= maxPacketSize && cap() > cap(.buf) {.buf = [:cap()]}return nil}
![]()  | 
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |