func (c *Conn) readOnePacket() ([]byte, error) {
	r := c.getReader()
	length, err := c.readHeaderFrom(r)
	if err != nil {
		return nil, err
	}
	if length == 0 {
		return nil, nil
	}
	data := make([]byte, length)
	if _, err := io.ReadFull(r, data); err != nil {
		return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err)
	}
	return data, nil
}
readOnePacket reads a single packet into a newly allocated buffer.
package mysql
import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"github.com/nooncall/shazam/util/bucketpool"
	"github.com/nooncall/shazam/util/sync2"
)
const (
	connBufferSize = 128
	MaxPacketSize = (1 << 24) - 1
)
const (
	ephemeralUnused = iota
	ephemeralWrite
	ephemeralRead
)
type Conn struct {
	conn net.Conn
	ConnectionID uint32
	closed sync2.AtomicBool
	bufferedReader *bufio.Reader
	bufferedWriter *bufio.Writer
	sequence       uint8
	currentEphemeralPolicy int
	currentEphemeralBuffer *[]byte
}
var bufPool = bucketpool.New(connBufferSize, MaxPacketSize)
var writersPool = sync.Pool{New: func() interface{} { return bufio.NewWriterSize(nil, connBufferSize) }}
func NewConn(conn net.Conn) *Conn {
	return &Conn{
		conn:           conn,
		closed:         sync2.NewAtomicBool(false),
		bufferedReader: bufio.NewReaderSize(conn, connBufferSize),
	}
}
func (c *Conn) StartWriterBuffering() {
	c.bufferedWriter = writersPool.Get().(*bufio.Writer)
	c.bufferedWriter.Reset(c.conn)
}
func (c *Conn) Flush() error {
	if c.bufferedWriter == nil {
		return nil
	}
	defer func() {
		c.bufferedWriter.Reset(nil)
		writersPool.Put(c.bufferedWriter)
		c.bufferedWriter = nil
	}()
	return c.bufferedWriter.Flush()
}
func (c *Conn) getWriter() io.Writer {
	if c.bufferedWriter != nil {
		return c.bufferedWriter
	}
	return c.conn
}
func (c *Conn) getReader() io.Reader {
	if c.bufferedReader != nil {
		return c.bufferedReader
	}
	return c.conn
}
func (c *Conn) readHeaderFrom(r io.Reader) (int, error) {
	var header [4]byte
	if _, err := io.ReadFull(r, header[:]); err != nil {
		if err == io.EOF {
			return 0, err
		}
		if strings.HasSuffix(err.Error(), "read: connection reset by peer") {
			return 0, io.EOF
		}
		return 0, fmt.Errorf("io.ReadFull(header size) failed: %v", err)
	}
	sequence := uint8(header[3])
	if sequence != c.sequence {
		return 0, fmt.Errorf("invalid sequence, expected %v got %v", c.sequence, sequence)
	}
	c.sequence++
	return int(uint32(header[0]) | uint32(header[1])<<8 | uint32(header[2])<<16), nil
}
func (c *Conn) ReadEphemeralPacket() ([]byte, error) {
	if c.currentEphemeralPolicy != ephemeralUnused {
		panic(fmt.Errorf("ReadEphemeralPacket: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy))
	}
	r := c.getReader()
	length, err := c.readHeaderFrom(r)
	if err != nil {
		return nil, err
	}
	c.currentEphemeralPolicy = ephemeralRead
	if length == 0 {
		return nil, nil
	}
	if length < MaxPacketSize {
		c.currentEphemeralBuffer = bufPool.Get(length)
		if _, err := io.ReadFull(r, *c.currentEphemeralBuffer); err != nil {
			return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err)
		}
		return *c.currentEphemeralBuffer, nil
	}
	data := make([]byte, length)
	if _, err := io.ReadFull(r, data); err != nil {
		return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err)
	}
	for {
		next, err := c.readOnePacket()
		if err != nil {
			return nil, err
		}
		if len(next) == 0 {
			break
		}
		data = append(data, next...)
		if len(next) < MaxPacketSize {
			break
		}
	}
	return data, nil
}
func (c *Conn) ReadEphemeralPacketDirect() ([]byte, error) {
	if c.currentEphemeralPolicy != ephemeralUnused {
		panic(fmt.Errorf("ReadEphemeralPacketDirect: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy))
	}
	var r io.Reader = c.conn
	length, err := c.readHeaderFrom(r)
	if err != nil {
		return nil, err
	}
	c.currentEphemeralPolicy = ephemeralRead
	if length == 0 {
		return nil, nil
	}
	if length < MaxPacketSize {
		c.currentEphemeralBuffer = bufPool.Get(length)
		if _, err := io.ReadFull(r, *c.currentEphemeralBuffer); err != nil {
			return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err)
		}
		return *c.currentEphemeralBuffer, nil
	}
	return nil, fmt.Errorf("ReadEphemeralPacketDirect doesn't support more than one packet")
}
func (c *Conn) RecycleReadPacket() {
	if c.currentEphemeralPolicy != ephemeralRead {
		panic(fmt.Errorf("trying to call RecycleReadPacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy))
	}
	if c.currentEphemeralBuffer != nil {
		bufPool.Put(c.currentEphemeralBuffer)
		c.currentEphemeralBuffer = nil
	}
	c.currentEphemeralPolicy = ephemeralUnused
}