Skip to content

Commit 2922807

Browse files
committed
sstable: track value separation policy props used
Add ValueSeparationKind and ValueSeparationMinSize to sstable properties to track the value separation policy used when writing the table.
1 parent e52aa89 commit 2922807

28 files changed

+533
-338
lines changed

internal/compact/run.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ type ValueSeparation interface {
124124
// sstable. It can be used to configure value separation specifically for
125125
// the next compaction output.
126126
SetNextOutputConfig(config ValueSeparationOutputConfig)
127+
// Kind returns the kind of value separation strategy being used.
128+
Kind() sstable.ValueSeparationKind
129+
// MinimumSize returns the minimum size a value must be in order to be
130+
// separated into a blob file.
131+
MinimumSize() int
127132
// EstimatedFileSize returns an estimate of the disk space consumed by the
128133
// current, pending blob file if it were closed now. If no blob file has
129134
// been created, it returns 0.
@@ -233,6 +238,10 @@ func (r *Runner) WriteTable(
233238
if r.err != nil {
234239
panic("error already encountered")
235240
}
241+
242+
// Set the value separation kind on the writer based on the strategy being used.
243+
tw.SetValueSeparationProps(valueSeparation.Kind(), uint64(valueSeparation.MinimumSize()))
244+
236245
r.tables = append(r.tables, OutputTable{
237246
CreationTime: time.Now(),
238247
ObjMeta: objMeta,
@@ -498,6 +507,14 @@ var _ ValueSeparation = NeverSeparateValues{}
498507
// SetNextOutputConfig implements the ValueSeparation interface.
499508
func (NeverSeparateValues) SetNextOutputConfig(config ValueSeparationOutputConfig) {}
500509

510+
// Kind implements the ValueSeparation interface.
511+
func (NeverSeparateValues) Kind() sstable.ValueSeparationKind {
512+
return sstable.ValueSeparationNone
513+
}
514+
515+
// MinimumSize implements the ValueSeparation interface.
516+
func (v NeverSeparateValues) MinimumSize() int { return 0 }
517+
501518
// EstimatedFileSize implements the ValueSeparation interface.
502519
func (NeverSeparateValues) EstimatedFileSize() uint64 { return 0 }
503520

replay/testdata/corpus/simple_val_sep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,6 @@ stat simple_val_sep/MANIFEST-000013 simple_val_sep/000015.sst simple_val_sep/000
103103
simple_val_sep/MANIFEST-000013:
104104
size: 250
105105
simple_val_sep/000015.sst:
106-
size: 760
106+
size: 802
107107
simple_val_sep/000016.blob:
108108
size: 97

replay/testdata/replay_val_sep

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ tree
55
----
66
/
77
build/
8-
787 000005.sst
8+
829 000005.sst
99
101 000006.blob
10-
766 000008.sst
10+
808 000008.sst
1111
97 000009.blob
1212
92 000011.log
13-
660 000012.sst
13+
707 000012.sst
1414
63 000014.log
15-
760 000015.sst
15+
802 000015.sst
1616
97 000016.blob
1717
0 LOCK
1818
152 MANIFEST-000010
@@ -21,16 +21,16 @@ tree
2121
0 marker.format-version.000011.024
2222
0 marker.manifest.000003.MANIFEST-000013
2323
simple_val_sep/
24-
760 000015.sst
24+
802 000015.sst
2525
97 000016.blob
2626
250 MANIFEST-000013
2727
checkpoint/
28-
787 000005.sst
28+
829 000005.sst
2929
101 000006.blob
30-
766 000008.sst
30+
808 000008.sst
3131
97 000009.blob
3232
11 000011.log
33-
660 000012.sst
33+
707 000012.sst
3434
187 MANIFEST-000013
3535
2947 OPTIONS-000003
3636
0 marker.format-version.000001.024

sstable/colblk_writer.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,12 @@ func (w *RawColumnWriter) copyProperties(props Properties) {
12721272
w.props.IndexType = 0
12731273
}
12741274

1275+
// SetValueSeparationProps implements RawWriter.
1276+
func (w *RawColumnWriter) SetValueSeparationProps(kind ValueSeparationKind, minValueSize uint64) {
1277+
w.props.ValueSeparationKind = uint8(kind)
1278+
w.props.ValueSeparationMinSize = minValueSize
1279+
}
1280+
12751281
// IsLikelyMVCCGarbage determines whether the given user key is likely MVCC
12761282
// garbage.
12771283
//

sstable/internal/genprops/gen_props.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
type Field struct {
2525
Name string // Go identifier
2626
Tag string // tag value
27-
Kind string // bool | uint32 | uint64 | string
27+
Kind string // bool | uint8 | uint32 | uint64 | string
2828
EncodeEmpty bool // whether to encode empty a zero value
2929
Intern bool // whether to intern the string value
3030
}
@@ -56,6 +56,8 @@ func (p *Properties) load(i iter.Seq2[[]byte, []byte]) error {
5656
p.Loaded |= 1 << _bit_{{ .Name }}
5757
{{- if eq .Kind "bool" }}
5858
p.{{ .Name }} = len(v) == 1 && v[0] == '1'
59+
{{- else if eq .Kind "uint8" }}
60+
p.{{ .Name }} = v[0]
5961
{{- else if eq .Kind "uint32" }}
6062
p.{{ .Name }} = binary.LittleEndian.Uint32(v)
6163
{{- else if eq .Kind "uint64" }}
@@ -106,6 +108,9 @@ func (p *Properties) encodeAll() map[string][]byte {
106108
if p.{{ .Name }} {
107109
val[0] = '1'
108110
}
111+
{{- else if eq .Kind "uint8" }}
112+
val := alloc(1)
113+
val[0] = p.{{ .Name }}
109114
{{- else if eq .Kind "uint32" }}
110115
val := alloc(4)
111116
binary.LittleEndian.PutUint32(val, p.{{ .Name }})
@@ -163,7 +168,7 @@ func zeroVal(kind string) string {
163168
switch kind {
164169
case "bool":
165170
return "false"
166-
case "uint32", "uint64":
171+
case "uint8", "uint32", "uint64":
167172
return "0"
168173
case "string":
169174
return `""`
@@ -217,6 +222,8 @@ func main() {
217222
switch typ {
218223
case "bool":
219224
kind = "bool"
225+
case "uint8":
226+
kind = "uint8"
220227
case "uint32":
221228
kind = "uint32"
222229
case "uint64":

sstable/properties.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ type Properties struct {
122122
// The compression statistics encoded as a string. The format is:
123123
// "<setting1>:<compressed1>/<uncompressed1>,<setting2>:<compressed2>/<uncompressed2>,..."
124124
CompressionStats string `prop:"pebble.compression_stats"`
125+
// The value separation policy that was used when writing this sstable.
126+
// This indicates how values were handled during writing (separated into
127+
// blob files, preserved references, or kept in-place). See ValueSeparationKind type
128+
// for possible values.
129+
ValueSeparationKind uint8 `prop:"pebble.value-separation.kind"`
130+
// The minimum size a value must be to be separated into a blob file during writing.
131+
ValueSeparationMinSize uint64 `prop:"pebble.value-separation.min-size"`
125132
// User collected properties. Currently, we only use them to store block
126133
// properties aggregated at the table level.
127134
UserProperties map[string]string
@@ -224,6 +231,28 @@ func (p *Properties) toAttributes() Attributes {
224231
return attributes
225232
}
226233

234+
// ValueSeparationKind indicates the value separation policy that was used
235+
// when writing an sstable.
236+
type ValueSeparationKind uint8
237+
238+
const (
239+
// ValueSeparationNone indicates that no value separation was used.
240+
// All values are stored in-place within the sstable.
241+
ValueSeparationNone ValueSeparationKind = iota
242+
243+
// ValueSeparationDefault indicates that values were separated into
244+
// new blob files during writing.
245+
ValueSeparationDefault
246+
247+
// ValueSeparationSpanPolicy indicates that values were separated
248+
// based on a span policy during writing.
249+
ValueSeparationSpanPolicy
250+
251+
// ValueSeparationPreservedRefs indicates that existing blob references
252+
// were preserved without creating new blob files.
253+
ValueSeparationPreservedRefs
254+
)
255+
227256
var (
228257
singleZeroSlice = []byte{0x00}
229258
maxInt32Slice = binary.AppendUvarint([]byte(nil), math.MaxInt32)

sstable/properties_gen.go

Lines changed: 27 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sstable/rowblk_writer.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,11 @@ func (w *RawRowWriter) setFilter(fw filterWriter) {
19661966
w.filter = fw
19671967
}
19681968

1969+
// SetValueSeparationProps implements RawWriter.
1970+
func (w *RawRowWriter) SetValueSeparationProps(_kind ValueSeparationKind, _minValueSize uint64) {
1971+
// Value separation requires TableFormatPebblev7+ which uses column writers.
1972+
}
1973+
19691974
// SetSnapshotPinnedProperties sets the properties for pinned keys. Should only
19701975
// be used internally by Pebble.
19711976
func (w *RawRowWriter) SetSnapshotPinnedProperties(

sstable/writer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ type RawWriter interface {
362362
// Must not be called after Writer is closed.
363363
IsPrefixEqualPrev(k []byte) bool
364364

365+
// SetValueSeparationProps sets the value separation props that were used when
366+
// writing this sstable. This is recorded in the sstable properties.
367+
SetValueSeparationProps(kind ValueSeparationKind, minValueSize uint64)
368+
365369
// rewriteSuffixes rewrites the table's data blocks to all contain the
366370
// provided suffix. It's specifically used for the implementation of
367371
// RewriteKeySuffixesAndReturnFormat. See that function's documentation for

testdata/checkpoint

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,9 @@ close: checkpoints/checkpoint8/000004.log
10551055
scan checkpoints/checkpoint8
10561056
----
10571057
open: checkpoints/checkpoint8/000005.sst (options: *vfs.randomReadsOption)
1058-
read-at(735, 61): checkpoints/checkpoint8/000005.sst
1059-
read-at(658, 77): checkpoints/checkpoint8/000005.sst
1060-
read-at(197, 461): checkpoints/checkpoint8/000005.sst
1058+
read-at(785, 61): checkpoints/checkpoint8/000005.sst
1059+
read-at(708, 77): checkpoints/checkpoint8/000005.sst
1060+
read-at(197, 511): checkpoints/checkpoint8/000005.sst
10611061
read-at(131, 41): checkpoints/checkpoint8/000005.sst
10621062
read-at(0, 131): checkpoints/checkpoint8/000005.sst
10631063
open: checkpoints/checkpoint8/000006.blob (options: *vfs.randomReadsOption)
@@ -1165,9 +1165,9 @@ close: checkpoints/checkpoint9/000007.log
11651165
scan checkpoints/checkpoint9
11661166
----
11671167
open: checkpoints/checkpoint9/000005.sst (options: *vfs.randomReadsOption)
1168-
read-at(735, 61): checkpoints/checkpoint9/000005.sst
1169-
read-at(658, 77): checkpoints/checkpoint9/000005.sst
1170-
read-at(197, 461): checkpoints/checkpoint9/000005.sst
1168+
read-at(785, 61): checkpoints/checkpoint9/000005.sst
1169+
read-at(708, 77): checkpoints/checkpoint9/000005.sst
1170+
read-at(197, 511): checkpoints/checkpoint9/000005.sst
11711171
read-at(131, 41): checkpoints/checkpoint9/000005.sst
11721172
read-at(0, 131): checkpoints/checkpoint9/000005.sst
11731173
open: checkpoints/checkpoint9/000006.blob (options: *vfs.randomReadsOption)

0 commit comments

Comments
 (0)