blob: 101d249ecc0d08f7308f050feee6d672294a781d [file] [edit]
// Copyright 2026 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// Package zstd enables automatic Zstandard compression for MySQL connections
// with compression enabled. Import it for its side effects:
//
// import _ "github.com/go-sql-driver/mysql/zstd"
//
// This also registers the mysql database/sql driver. Connections use zstd when
// the server supports it and fall back to zlib otherwise. Compression remains
// disabled unless enabled through the DSN or mysql.EnableCompression.
package zstd
import (
"sync"
_ "github.com/go-sql-driver/mysql"
"github.com/go-sql-driver/mysql/internal/compression"
"github.com/klauspost/compress/zstd"
)
// Protocol packets have a three-byte uncompressed length. Bound both decoded
// output and the frame window; codec defaults allow much larger allocations.
const maxPacketSize = 1<<24 - 1
var encoderPool = sync.Pool{New: func() any {
encoder, err := zstd.NewWriter(nil,
zstd.WithEncoderConcurrency(1),
// Fixed level 3 balances compression ratio and speed, favoring speed.
// Importing this package alone does not enable compression.
zstd.WithEncoderLevel(zstd.EncoderLevelFromZstd(compression.ZstdLevel)),
)
if err != nil {
panic(err) // All options are fixed and valid.
}
return encoder
}}
var decoderPool = sync.Pool{New: func() any {
decoder, err := zstd.NewReader(nil,
zstd.WithDecoderConcurrency(1),
zstd.WithDecoderMaxMemory(maxPacketSize),
zstd.WithDecoderMaxWindow(1<<24),
zstd.WithDecodeAllCapLimit(true),
)
if err != nil {
panic(err) // All options are fixed and valid.
}
return decoder
}}
type codec struct{}
func (codec) Encode(src, dst []byte) []byte {
encoder := encoderPool.Get().(*zstd.Encoder)
dst = encoder.EncodeAll(src, dst)
encoderPool.Put(encoder)
return dst
}
func (codec) Decode(src, dst []byte) ([]byte, error) {
decoder := decoderPool.Get().(*zstd.Decoder)
dst, err := decoder.DecodeAll(src, dst)
decoderPool.Put(decoder)
return dst, err
}
func init() {
compression.Zstd = codec{}
}