Skip to content

Commit 7058aad

Browse files
committed
block: support different setting for value blocks
A possible "balanced" setting could be to use Zstd1 for value blocks and MinLZ for everything else.
1 parent 0d44add commit 7058aad

File tree

4 files changed

+91
-14
lines changed

4 files changed

+91
-14
lines changed

sstable/block/compression.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,18 @@ import (
2525
type CompressionProfile struct {
2626
Name string
2727

28-
// DataBlocks applies to sstable data and value blocks, as well as blob file
29-
// value blocks. OtherBlocks applies to all other blocks (such as index,
30-
// filter, metadata blocks).
28+
// DataBlocks applies to sstable data blocks.
29+
// ValueBlocks applies to sstable value blocks and blob file value blocks.
30+
// OtherBlocks applies to all other blocks (such as index, filter, metadata
31+
// blocks).
3132
//
3233
// Some blocks (like rangedel) never use compression; this is at the
3334
// discretion of the sstable or blob file writer.
3435
//
3536
// Note that MinLZ is only supported with table formats v6+. Older formats
3637
// fall back to Snappy.
3738
DataBlocks compression.Setting
39+
ValueBlocks compression.Setting
3840
OtherBlocks compression.Setting
3941

4042
// Blocks that are reduced by less than this percentage are stored
@@ -44,6 +46,14 @@ type CompressionProfile struct {
4446
// TODO(radu): knobs for adaptive compression go here.
4547
}
4648

49+
// UsesMinLZ returns true if the profile uses the MinLZ compression algorithm
50+
// (for any block kind).
51+
func (p *CompressionProfile) UsesMinLZ() bool {
52+
return p.DataBlocks.Algorithm == compression.MinLZ ||
53+
p.ValueBlocks.Algorithm == compression.MinLZ ||
54+
p.OtherBlocks.Algorithm == compression.MinLZ
55+
}
56+
4757
var (
4858
NoCompression = simpleCompressionProfile("NoCompression", compression.None)
4959
SnappyCompression = simpleCompressionProfile("Snappy", compression.Snappy)
@@ -73,6 +83,7 @@ func simpleCompressionProfile(name string, setting compression.Setting) *Compres
7383
p := &CompressionProfile{
7484
Name: name,
7585
DataBlocks: setting,
86+
ValueBlocks: setting,
7687
OtherBlocks: setting,
7788
MinReductionPercent: 12,
7889
}

sstable/block/compressor.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import (
1414
type Compressor struct {
1515
profile CompressionProfile
1616
dataBlocksCompressor compression.Compressor
17+
// valueBlocksCompressor is used for value blocks; It can be the same object as
18+
// dataBlocksCompressor.
19+
valueBlocksCompressor compression.Compressor
1720
// otherBlocksCompressor is used for blocks that are not data blocks, such as
1821
// index blocks or metadata blocks. It can be the same object as
1922
// dataBlocksCompressor.
@@ -27,8 +30,14 @@ func MakeCompressor(profile *CompressionProfile) Compressor {
2730
profile: *profile,
2831
}
2932
c.dataBlocksCompressor = compression.GetCompressor(profile.DataBlocks)
30-
c.otherBlocksCompressor = c.dataBlocksCompressor
31-
if profile.OtherBlocks != profile.DataBlocks {
33+
if profile.ValueBlocks == profile.DataBlocks {
34+
c.valueBlocksCompressor = c.dataBlocksCompressor
35+
} else {
36+
c.valueBlocksCompressor = compression.GetCompressor(profile.ValueBlocks)
37+
}
38+
if profile.OtherBlocks == profile.DataBlocks {
39+
c.otherBlocksCompressor = c.dataBlocksCompressor
40+
} else {
3241
c.otherBlocksCompressor = compression.GetCompressor(profile.OtherBlocks)
3342
}
3443
return c
@@ -40,6 +49,9 @@ func (c *Compressor) Close() {
4049
if c.otherBlocksCompressor != c.dataBlocksCompressor {
4150
c.otherBlocksCompressor.Close()
4251
}
52+
if c.valueBlocksCompressor != c.dataBlocksCompressor {
53+
c.valueBlocksCompressor.Close()
54+
}
4355
c.dataBlocksCompressor.Close()
4456
*c = Compressor{}
4557
}
@@ -48,10 +60,16 @@ func (c *Compressor) Close() {
4860
//
4961
// In addition to the buffer, returns the algorithm that was used.
5062
func (c *Compressor) Compress(dst, src []byte, kind Kind) (CompressionIndicator, []byte) {
51-
compressor := c.dataBlocksCompressor
52-
if kind != blockkind.SSTableData && kind != blockkind.SSTableValue && kind != blockkind.BlobValue {
63+
var compressor compression.Compressor
64+
switch kind {
65+
case blockkind.SSTableData:
66+
compressor = c.dataBlocksCompressor
67+
case blockkind.SSTableValue, blockkind.BlobValue:
68+
compressor = c.valueBlocksCompressor
69+
default:
5370
compressor = c.otherBlocksCompressor
5471
}
72+
5573
out := compressor.Compress(dst, src)
5674

5775
// Return the original data uncompressed if the reduction is less than the

sstable/block/compressor_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2025 The LevelDB-Go and Pebble Authors. All rights reserved. Use
2+
// of this source code is governed by a BSD-style license that can be found in
3+
// the LICENSE file.
4+
5+
package block
6+
7+
import (
8+
"math/rand/v2"
9+
"testing"
10+
11+
"github.com/cockroachdb/pebble/internal/compression"
12+
"github.com/cockroachdb/pebble/sstable/block/blockkind"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestCompressor(t *testing.T) {
17+
settings := []compression.Setting{
18+
compression.None,
19+
compression.Snappy,
20+
compression.MinLZFastest,
21+
compression.ZstdLevel3,
22+
}
23+
24+
src := make([]byte, 1024)
25+
dst := make([]byte, 0, 1024)
26+
for runs := 0; runs < 100; runs++ {
27+
profile := &CompressionProfile{
28+
DataBlocks: settings[rand.IntN(len(settings))],
29+
ValueBlocks: settings[rand.IntN(len(settings))],
30+
OtherBlocks: settings[rand.IntN(len(settings))],
31+
MinReductionPercent: 0,
32+
}
33+
34+
compressor := MakeCompressor(profile)
35+
ci, _ := compressor.Compress(dst, src, blockkind.SSTableData)
36+
require.Equal(t, compressionIndicatorFromAlgorithm(profile.DataBlocks.Algorithm), ci)
37+
38+
ci, _ = compressor.Compress(dst, src, blockkind.SSTableValue)
39+
require.Equal(t, compressionIndicatorFromAlgorithm(profile.ValueBlocks.Algorithm), ci)
40+
41+
ci, _ = compressor.Compress(dst, src, blockkind.BlobValue)
42+
require.Equal(t, compressionIndicatorFromAlgorithm(profile.ValueBlocks.Algorithm), ci)
43+
44+
ci, _ = compressor.Compress(dst, src, blockkind.Index)
45+
require.Equal(t, compressionIndicatorFromAlgorithm(profile.OtherBlocks.Algorithm), ci)
46+
47+
ci, _ = compressor.Compress(dst, src, blockkind.Metadata)
48+
require.Equal(t, compressionIndicatorFromAlgorithm(profile.OtherBlocks.Algorithm), ci)
49+
50+
compressor.Close()
51+
}
52+
}

sstable/options.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"fmt"
99

1010
"github.com/cockroachdb/pebble/internal/base"
11-
"github.com/cockroachdb/pebble/internal/compression"
1211
"github.com/cockroachdb/pebble/internal/sstableinternal"
1312
"github.com/cockroachdb/pebble/sstable/block"
1413
"github.com/cockroachdb/pebble/sstable/colblk"
@@ -355,12 +354,9 @@ func (o WriterOptions) ensureDefaults() WriterOptions {
355354
}
356355

357356
func tableFormatSupportsCompressionProfile(tf TableFormat, profile *block.CompressionProfile) bool {
358-
if tf < TableFormatPebblev6 {
359-
// MinLZ is only supported in TableFormatPebblev6 and higher.
360-
if profile.DataBlocks.Algorithm == compression.MinLZ ||
361-
profile.OtherBlocks.Algorithm == compression.MinLZ {
362-
return false
363-
}
357+
// MinLZ is only supported in TableFormatPebblev6 and higher.
358+
if tf < TableFormatPebblev6 && profile.UsesMinLZ() {
359+
return false
364360
}
365361
return true
366362
}

0 commit comments

Comments
 (0)