buffer.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
  2. //
  3. // Copyright 2013 Julien Schmidt. All rights reserved.
  4. // http://www.julienschmidt.com
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla Public
  7. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  8. // You can obtain one at http://mozilla.org/MPL/2.0/.
  9. package mysql
  10. import "io"
  11. const defaultBufSize = 4096
  12. // A read buffer similar to bufio.Reader but zero-copy-ish
  13. // Also highly optimized for this particular use case.
  14. type buffer struct {
  15. buf []byte
  16. rd io.Reader
  17. idx int
  18. length int
  19. }
  20. func newBuffer(rd io.Reader) *buffer {
  21. return &buffer{
  22. buf: make([]byte, defaultBufSize),
  23. rd: rd,
  24. }
  25. }
  26. // fill reads into the buffer until at least _need_ bytes are in it
  27. func (b *buffer) fill(need int) (err error) {
  28. // move existing data to the beginning
  29. if b.length > 0 && b.idx > 0 {
  30. copy(b.buf[0:b.length], b.buf[b.idx:])
  31. }
  32. // grow buffer if necessary
  33. if need > len(b.buf) {
  34. b.grow(need)
  35. }
  36. b.idx = 0
  37. var n int
  38. for {
  39. n, err = b.rd.Read(b.buf[b.length:])
  40. b.length += n
  41. if b.length < need && err == nil {
  42. continue
  43. }
  44. return // err
  45. }
  46. }
  47. // grow the buffer to at least the given size
  48. // credit for this code snippet goes to Maxim Khitrov
  49. // https://groups.google.com/forum/#!topic/golang-nuts/ETbw1ECDgRs
  50. func (b *buffer) grow(size int) {
  51. // If append would be too expensive, alloc a new slice
  52. if size > cap(b.buf)*2 {
  53. newBuf := make([]byte, size)
  54. copy(newBuf, b.buf)
  55. b.buf = newBuf
  56. return
  57. }
  58. for {
  59. b.buf = append(b.buf, 0)
  60. b.buf = b.buf[:cap(b.buf)]
  61. if cap(b.buf) < size {
  62. continue
  63. }
  64. return
  65. }
  66. }
  67. // returns next N bytes from buffer.
  68. // The returned slice is only guaranteed to be valid until the next read
  69. func (b *buffer) readNext(need int) (p []byte, err error) {
  70. if b.length < need {
  71. // refill
  72. err = b.fill(need) // err deferred
  73. }
  74. p = b.buf[b.idx : b.idx+need]
  75. b.idx += need
  76. b.length -= need
  77. return
  78. }