2019-05-22 21:23:23 +00:00
|
|
|
package handshake
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2021-03-02 19:18:32 +00:00
|
|
|
"fmt"
|
2019-05-22 21:23:23 +00:00
|
|
|
"io"
|
|
|
|
"net"
|
2021-03-02 19:18:32 +00:00
|
|
|
"time"
|
2019-05-22 21:23:23 +00:00
|
|
|
|
2019-07-23 16:54:50 +00:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding/zstd"
|
2019-05-22 21:23:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type bufferedWriter interface {
|
|
|
|
Write(p []byte) (int, error)
|
|
|
|
Flush() error
|
|
|
|
}
|
|
|
|
|
|
|
|
// BufferedConn is a net.Conn with Flush suport.
|
|
|
|
type BufferedConn struct {
|
|
|
|
net.Conn
|
|
|
|
|
|
|
|
br io.Reader
|
|
|
|
bw bufferedWriter
|
|
|
|
}
|
|
|
|
|
|
|
|
const bufferSize = 64 * 1024
|
|
|
|
|
|
|
|
// newBufferedConn returns buffered connection with the given compression level.
|
|
|
|
func newBufferedConn(c net.Conn, compressionLevel int, isReadCompressed bool) *BufferedConn {
|
|
|
|
bc := &BufferedConn{
|
|
|
|
Conn: c,
|
|
|
|
}
|
|
|
|
if compressionLevel <= 0 {
|
|
|
|
bc.bw = bufio.NewWriterSize(c, bufferSize)
|
|
|
|
} else {
|
2019-07-23 16:54:50 +00:00
|
|
|
bc.bw = zstd.NewWriterLevel(c, compressionLevel)
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
|
|
|
if !isReadCompressed {
|
|
|
|
bc.br = bufio.NewReaderSize(c, bufferSize)
|
|
|
|
} else {
|
2019-07-23 16:54:50 +00:00
|
|
|
bc.br = zstd.NewReader(c)
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
|
|
|
return bc
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read reads up to len(p) from bc to p.
|
|
|
|
func (bc *BufferedConn) Read(p []byte) (int, error) {
|
2021-03-02 19:18:32 +00:00
|
|
|
startTime := time.Now()
|
|
|
|
n, err := bc.br.Read(p)
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("cannot read data in %.3f seconds: %w", time.Since(startTime).Seconds(), err)
|
|
|
|
}
|
|
|
|
return n, err
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write writes p to bc.
|
|
|
|
//
|
|
|
|
// Do not forget to call Flush if needed.
|
|
|
|
func (bc *BufferedConn) Write(p []byte) (int, error) {
|
2021-03-02 19:18:32 +00:00
|
|
|
startTime := time.Now()
|
|
|
|
n, err := bc.bw.Write(p)
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("cannot write data in %.3f seconds: %w", time.Since(startTime).Seconds(), err)
|
|
|
|
}
|
|
|
|
return n, err
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes bc.
|
|
|
|
func (bc *BufferedConn) Close() error {
|
|
|
|
// Close the Conn at first. It is expected that all the required data
|
|
|
|
// is already flushed to the Conn.
|
|
|
|
err := bc.Conn.Close()
|
|
|
|
bc.Conn = nil
|
|
|
|
|
2019-07-23 16:54:50 +00:00
|
|
|
if zr, ok := bc.br.(*zstd.Reader); ok {
|
2019-05-22 21:23:23 +00:00
|
|
|
zr.Release()
|
|
|
|
}
|
|
|
|
bc.br = nil
|
|
|
|
|
2019-07-23 16:54:50 +00:00
|
|
|
if zw, ok := bc.bw.(*zstd.Writer); ok {
|
2019-05-22 21:23:23 +00:00
|
|
|
// Do not call zw.Close(), since we already closed the underlying conn.
|
|
|
|
zw.Release()
|
|
|
|
}
|
|
|
|
bc.bw = nil
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flush flushes internal write buffers to the underlying conn.
|
|
|
|
func (bc *BufferedConn) Flush() error {
|
|
|
|
return bc.bw.Flush()
|
|
|
|
}
|