Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server: support compressed MySQL protocol #36780

Merged
merged 12 commits into from
May 12, 2023
4 changes: 2 additions & 2 deletions DEPS.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2517,8 +2517,8 @@ def go_deps():
name = "com_github_klauspost_compress",
build_file_proto_mode = "disable_global",
importpath = "github.com/klauspost/compress",
sum = "h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=",
version = "v1.15.13",
sum = "h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=",
version = "v1.16.5",
)
go_repository(
name = "com_github_klauspost_cpuid",
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ require (
github.com/jingyugao/rowserrcheck v1.1.1
github.com/joho/sqltocsv v0.0.0-20210428211105-a6d6801d59df
github.com/kisielk/errcheck v1.6.3
github.com/klauspost/compress v1.15.13
github.com/klauspost/compress v1.16.5
github.com/kyoh86/exportloopref v0.1.11
github.com/lestrrat-go/jwx/v2 v2.0.6
github.com/mgechev/revive v1.3.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
Expand Down
15 changes: 12 additions & 3 deletions parser/mysql/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const (
ClientLongFlag // CLIENT_LONG_FLAG
ClientConnectWithDB // CLIENT_CONNECT_WITH_DB
ClientNoSchema // CLIENT_NO_SCHEMA
ClientCompress // CLIENT_COMPRESS, Not supported: https://github.com/pingcap/tidb/issues/22605
ClientCompress // CLIENT_COMPRESS
ClientODBC // CLIENT_ODBC
ClientLocalFiles // CLIENT_LOCAL_FILES
ClientIgnoreSpace // CLIENT_IGNORE_SPACE
Expand All @@ -160,8 +160,8 @@ const (
ClientHandleExpiredPasswords // CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS, Not supported: https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_expired_passwords.html
ClientSessionTrack // CLIENT_SESSION_TRACK, Not supported: https://github.com/pingcap/tidb/issues/35309
ClientDeprecateEOF // CLIENT_DEPRECATE_EOF
// 1 << 25 == CLIENT_OPTIONAL_RESULTSET_METADATA
// 1 << 26 == CLIENT_ZSTD_COMPRESSION_ALGORITHM
ClientOptionalResultsetMetadata // CLIENT_OPTIONAL_RESULTSET_METADATA, Not supported: https://dev.mysql.com/doc/c-api/8.0/en/c-api-optional-metadata.html
ClientZstdCompressionAlgorithm // CLIENT_ZSTD_COMPRESSION_ALGORITHM
// 1 << 27 == CLIENT_QUERY_ATTRIBUTES
// 1 << 28 == MULTI_FACTOR_AUTHENTICATION
// 1 << 29 == CLIENT_CAPABILITY_EXTENSION
Expand Down Expand Up @@ -629,3 +629,12 @@ const (
CursorTypeForUpdate
CursorTypeScrollable
)

const (
// CompressionNone is no compression in use
CompressionNone = iota
// CompressionZlib is zlib/deflate
CompressionZlib
// CompressionZstd is Facebook's Zstandard
CompressionZstd
)
2 changes: 2 additions & 0 deletions server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ go_library(
"@com_github_blacktear23_go_proxyprotocol//:go-proxyprotocol",
"@com_github_burntsushi_toml//:toml",
"@com_github_gorilla_mux//:mux",
"@com_github_klauspost_compress//zstd",
"@com_github_pingcap_errors//:errors",
"@com_github_pingcap_failpoint//:failpoint",
"@com_github_pingcap_fn//:fn",
Expand Down Expand Up @@ -219,6 +220,7 @@ go_test(
"@com_github_docker_go_units//:go-units",
"@com_github_go_sql_driver_mysql//:mysql",
"@com_github_gorilla_mux//:mux",
"@com_github_klauspost_compress//zstd",
"@com_github_pingcap_errors//:errors",
"@com_github_pingcap_failpoint//:failpoint",
"@com_github_pingcap_kvproto//pkg/kvrpcpb",
Expand Down
21 changes: 19 additions & 2 deletions server/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import (
"time"
"unsafe"

"github.com/klauspost/compress/zstd"
"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/config"
Expand Down Expand Up @@ -279,6 +280,14 @@ func (cc *clientConn) handshake(ctx context.Context) error {
logutil.Logger(ctx).Debug("flush response to client failed", zap.Error(err))
return err
}

// With mysql --compression-algorithms=zlib,zstd both flags are set, the result is Zlib
if cc.capability&mysql.ClientCompress > 0 {
cc.pkt.SetCompressionAlgorithm(mysql.CompressionZlib)
} else if cc.capability&mysql.ClientZstdCompressionAlgorithm > 0 {
cc.pkt.SetCompressionAlgorithm(mysql.CompressionZstd)
}

return err
}

Expand Down Expand Up @@ -414,6 +423,7 @@ type handshakeResponse41 struct {
Auth []byte
AuthPlugin string
Attrs map[string]string
ZstdLevel zstd.EncoderLevel
}

// parseHandshakeResponseHeader parses the common header of SSLRequest and HandshakeResponse41.
Expand Down Expand Up @@ -502,18 +512,23 @@ func parseHandshakeResponseBody(ctx context.Context, packet *handshakeResponse41
// Defend some ill-formated packet, connection attribute is not important and can be ignored.
return nil
}
if num, null, off := parseLengthEncodedInt(data[offset:]); !null {
offset += off
if num, null, intOff := parseLengthEncodedInt(data[offset:]); !null {
offset += intOff // Length of variable length encoded integer itself in bytes
row := data[offset : offset+int(num)]
attrs, err := parseAttrs(row)
if err != nil {
logutil.Logger(ctx).Warn("parse attrs failed", zap.Error(err))
return nil
}
packet.Attrs = attrs
offset += int(num) // Length of attributes
}
}

if packet.Capability&mysql.ClientZstdCompressionAlgorithm > 0 {
packet.ZstdLevel = zstd.EncoderLevelFromZstd(int(data[offset]))
}

return nil
}

Expand Down Expand Up @@ -625,6 +640,7 @@ func (cc *clientConn) readOptionalSSLRequestAndHandshakeResponse(ctx context.Con
cc.dbname = resp.DBName
cc.collation = resp.Collation
cc.attrs = resp.Attrs
cc.pkt.zstdLevel = resp.ZstdLevel

err = cc.handleAuthPlugin(ctx, &resp)
if err != nil {
Expand Down Expand Up @@ -1163,6 +1179,7 @@ func (cc *clientConn) Run(ctx context.Context) {
}
cc.addMetrics(data[0], startTime, err)
cc.pkt.sequence = 0
cc.pkt.compressedSequence = 0
}
}

Expand Down