From 975fbcb07b9285309864318d64e02fa9c33f1511 Mon Sep 17 00:00:00 2001 From: Jackson Owens Date: Thu, 22 Jun 2023 16:03:00 -0400 Subject: [PATCH] *,sstable: upgrade zstd to v1.5.6 Upgrade zstd to v1.5.6. Due to changes in the mechanics of zstd.Decompress function, this required a change to using a new zstd.DecompressInto entrypoint that guarantees it'll deserialize into the provided destination buffer, never allocating a new buffer. Close #1706. --- go.mod | 2 +- go.sum | 4 ++-- sstable/compression.go | 13 +++++++------ sstable/compression_cgo.go | 10 +++++----- sstable/compression_nocgo.go | 10 +++++----- sstable/suffix_rewriter.go | 5 +++-- sstable/testdata/h.zstd-compression.sst | Bin 11826 -> 11802 bytes 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 43452c16d8..744538a732 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/cockroachdb/pebble require ( - github.com/DataDog/zstd v1.4.5 + github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0 github.com/HdrHistogram/hdrhistogram-go v1.1.2 github.com/cespare/xxhash/v2 v2.2.0 github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f diff --git a/go.sum b/go.sum index c5c1dcf926..92aae6dab0 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0 h1:ye3LRgDs6Og7SKC1wBQH8oMaGczhCRpPpnU74l4rma8= +github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= diff --git a/sstable/compression.go b/sstable/compression.go index 4dd5bea4bc..47b02b8322 100644 --- a/sstable/compression.go +++ b/sstable/compression.go @@ -33,23 +33,24 @@ func decompressedLen(blockType blockType, b []byte) (int, int, error) { } } -func decompressInto(blockType blockType, compressed []byte, buf []byte) ([]byte, error) { +func decompressInto(blockType blockType, compressed []byte, buf []byte) error { var result []byte var err error switch blockType { case snappyCompressionBlockType: result, err = snappy.Decode(buf, compressed) case zstdCompressionBlockType: - result, err = decodeZstd(buf, compressed) + err = decodeZstd(buf, compressed) + result = buf } if err != nil { - return nil, base.MarkCorruptionError(err) + return base.MarkCorruptionError(err) } if len(result) != 0 && (len(result) != len(buf) || &result[0] != &buf[0]) { - return nil, base.CorruptionErrorf("pebble/table: decompressed into unexpected buffer: %p != %p", + return base.CorruptionErrorf("pebble/table: decompressed into unexpected buffer: %p != %p", errors.Safe(result), errors.Safe(buf)) } - return result, nil + return nil } // decompressBlock decompresses an SST block, with space allocated from a cache. @@ -68,7 +69,7 @@ func decompressBlock(cache *cache.Cache, blockType blockType, b []byte) (*cache. // Allocate sufficient space from the cache. decoded := cache.Alloc(decodedLen) decodedBuf := decoded.Buf() - if _, err := decompressInto(blockType, b, decodedBuf); err != nil { + if err := decompressInto(blockType, b, decodedBuf); err != nil { cache.Free(decoded) return nil, err } diff --git a/sstable/compression_cgo.go b/sstable/compression_cgo.go index ad7d844201..40e9c7e006 100644 --- a/sstable/compression_cgo.go +++ b/sstable/compression_cgo.go @@ -13,11 +13,11 @@ import ( "github.com/DataDog/zstd" ) -// decodeZstd decompresses b with the Zstandard algorithm. -// It reuses the preallocated capacity of decodedBuf if it is sufficient. -// On success, it returns the decoded byte slice. -func decodeZstd(decodedBuf, b []byte) ([]byte, error) { - return zstd.Decompress(decodedBuf, b) +// decodeZstd decompresses src with the Zstandard algorithm. The destination +// buffer must already be sufficiently sized, otherwise decodeZstd may error. +func decodeZstd(dst, src []byte) error { + _, err := zstd.DecompressInto(dst, src) + return err } // encodeZstd compresses b with the Zstandard algorithm at default compression diff --git a/sstable/compression_nocgo.go b/sstable/compression_nocgo.go index 42c34fb7f0..889ef7d591 100644 --- a/sstable/compression_nocgo.go +++ b/sstable/compression_nocgo.go @@ -9,13 +9,13 @@ package sstable import "github.com/klauspost/compress/zstd" -// decodeZstd decompresses b with the Zstandard algorithm. -// It reuses the preallocated capacity of decodedBuf if it is sufficient. -// On success, it returns the decoded byte slice. -func decodeZstd(decodedBuf, b []byte) ([]byte, error) { +// decodeZstd decompresses src with the Zstandard algorithm. The destination +// buffer must already be sufficiently sized, otherwise decodeZstd may error. +func decodeZstd(dst, src []byte) error { decoder, _ := zstd.NewReader(nil) defer decoder.Close() - return decoder.DecodeAll(b, decodedBuf[:0]) + _, err := decoder.DecodeAll(src, dst[:0]) + return err } // encodeZstd compresses b with the Zstandard algorithm at default compression diff --git a/sstable/suffix_rewriter.go b/sstable/suffix_rewriter.go index 9672deda46..4228e557b6 100644 --- a/sstable/suffix_rewriter.go +++ b/sstable/suffix_rewriter.go @@ -540,8 +540,9 @@ func readBlockBuf(r *Reader, bh BlockHandle, buf []byte) ([]byte, []byte, error) if cap(buf) < decompressedLen { buf = make([]byte, decompressedLen) } - res, err := decompressInto(typ, raw[prefix:], buf[:decompressedLen]) - return res, buf, err + dst := buf[:decompressedLen] + err = decompressInto(typ, raw[prefix:], dst) + return dst, buf, err } // memReader is a thin wrapper around a []byte such that it can be passed to diff --git a/sstable/testdata/h.zstd-compression.sst b/sstable/testdata/h.zstd-compression.sst index 37de2506ad933c09dd082c6108ec6fc7a36c360b..698d80d2b4b41a0b32458a9230b6de490167e14b 100644 GIT binary patch delta 9766 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 delta 9856 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