github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-sql-driver/mysql/buffer.go (about) 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 19 // A buffer which is used for both reading and writing. 20 // This is possible since communication on each connection is synchronous. 21 // In other words, we can't write and read simultaneously on the same connection. 22 // The buffer is similar to bufio.Reader / Writer but zero-copy-ish 23 // Also highly optimized for this particular use case. 24 type buffer struct { 25 buf []byte 26 nc net.Conn 27 idx int 28 length int 29 timeout time.Duration 30 } 31 32 func newBuffer(nc net.Conn) buffer { 33 var b [defaultBufSize]byte 34 return buffer{ 35 buf: b[:], 36 nc: nc, 37 } 38 } 39 40 // fill reads into the buffer until at least _need_ bytes are in it 41 func (b *buffer) fill(need int) error { 42 n := b.length 43 44 // move existing data to the beginning 45 if n > 0 && b.idx > 0 { 46 copy(b.buf[0:n], b.buf[b.idx:]) 47 } 48 49 // grow buffer if necessary 50 // TODO: let the buffer shrink again at some point 51 // Maybe keep the org buf slice and swap back? 52 if need > len(b.buf) { 53 // Round up to the next multiple of the default size 54 newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) 55 copy(newBuf, b.buf) 56 b.buf = newBuf 57 } 58 59 b.idx = 0 60 61 for { 62 if b.timeout > 0 { 63 if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { 64 return err 65 } 66 } 67 68 nn, err := b.nc.Read(b.buf[n:]) 69 n += nn 70 71 switch err { 72 case nil: 73 if n < need { 74 continue 75 } 76 b.length = n 77 return nil 78 79 case io.EOF: 80 if n >= need { 81 b.length = n 82 return nil 83 } 84 return io.ErrUnexpectedEOF 85 86 default: 87 return err 88 } 89 } 90 } 91 92 // returns next N bytes from buffer. 93 // The returned slice is only guaranteed to be valid until the next read 94 func (b *buffer) readNext(need int) ([]byte, error) { 95 if b.length < need { 96 // refill 97 if err := b.fill(need); err != nil { 98 return nil, err 99 } 100 } 101 102 offset := b.idx 103 b.idx += need 104 b.length -= need 105 return b.buf[offset:b.idx], nil 106 } 107 108 // 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 { 113 if b.length > 0 { 114 return nil 115 } 116 117 // test (cheap) general case first 118 if length <= defaultBufSize || length <= cap(b.buf) { 119 return b.buf[:length] 120 } 121 122 if length < maxPacketSize { 123 b.buf = make([]byte, length) 124 return b.buf 125 } 126 return make([]byte, length) 127 } 128 129 // shortcut which can be used if the requested buffer is guaranteed to be 130 // smaller than defaultBufSize 131 // Only one buffer (total) can be used at a time. 132 func (b *buffer) takeSmallBuffer(length int) []byte { 133 if b.length == 0 { 134 return b.buf[:length] 135 } 136 return nil 137 } 138 139 // takeCompleteBuffer returns the complete existing buffer. 140 // This can be used if the necessary buffer size is unknown. 141 // Only one buffer (total) can be used at a time. 142 func (b *buffer) takeCompleteBuffer() []byte { 143 if b.length == 0 { 144 return b.buf 145 } 146 return nil 147 }