Skip to content

Commit ffd01fd

Browse files
committed
manifest: explicitly encode excise operations in the MANIFEST
This adds a new struct field that maps excise span to the sequence number at which it was performed, this will help in benchmarking of replay package as it was not updated with excise operations, this field is implemented in version_edit_apply and version_edit_decode tests. Addresses #4798
1 parent e1bc7c5 commit ffd01fd

File tree

14 files changed

+213
-74
lines changed

14 files changed

+213
-74
lines changed

compaction.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,11 @@ func (d *DB) runIngestFlush(c *tableCompaction) (*manifest.VersionEdit, error) {
15881588
}
15891589
if ingestFlushable.exciseSpan.Valid() {
15901590
exciseBounds := ingestFlushable.exciseSpan.UserKeyBounds()
1591+
ve.ExciseBoundsRecord = append(ve.ExciseBoundsRecord, manifest.ExciseOpEntry{
1592+
Bounds: exciseBounds,
1593+
SeqNum: ingestFlushable.exciseSeqNum,
1594+
})
1595+
15911596
// Iterate through all levels and find files that intersect with exciseSpan.
15921597
for layer, ls := range version.AllLevelsAndSublevels() {
15931598
for m := range ls.Overlaps(d.cmp, ingestFlushable.exciseSpan.UserKeyBounds()).All() {

format_major_version.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ const (
235235
FormatValueSeparation
236236

237237
// -- Add new versions here --
238+
// FormatExciseBoundsRecord is a format major version that adds support for
239+
// persisting excise bounds records in the manifest (VersionEdit).
240+
FormatExciseBoundsRecord
238241

239242
// FormatNewest is the most recent format major version.
240243
FormatNewest FormatMajorVersion = iota - 1
@@ -276,7 +279,7 @@ func (v FormatMajorVersion) MaxTableFormat() sstable.TableFormat {
276279
return sstable.TableFormatPebblev5
277280
case FormatTableFormatV6, formatDeprecatedExperimentalValueSeparation:
278281
return sstable.TableFormatPebblev6
279-
case formatFooterAttributes, FormatValueSeparation:
282+
case formatFooterAttributes, FormatValueSeparation, FormatExciseBoundsRecord:
280283
return sstable.TableFormatPebblev7
281284
default:
282285
panic(fmt.Sprintf("pebble: unsupported format major version: %s", v))
@@ -290,7 +293,7 @@ func (v FormatMajorVersion) MinTableFormat() sstable.TableFormat {
290293
case FormatDefault, FormatFlushableIngest, FormatPrePebblev1MarkedCompacted,
291294
FormatDeleteSizedAndObsolete, FormatVirtualSSTables, FormatSyntheticPrefixSuffix,
292295
FormatFlushableIngestExcises, FormatColumnarBlocks, FormatWALSyncChunks,
293-
FormatTableFormatV6, formatDeprecatedExperimentalValueSeparation, formatFooterAttributes,
296+
FormatExciseBoundsRecord, FormatTableFormatV6, formatDeprecatedExperimentalValueSeparation, formatFooterAttributes,
294297
FormatValueSeparation:
295298
return sstable.TableFormatPebblev1
296299
default:
@@ -349,6 +352,9 @@ var formatMajorVersionMigrations = map[FormatMajorVersion]func(*DB) error{
349352
FormatValueSeparation: func(d *DB) error {
350353
return d.finalizeFormatVersUpgrade(FormatValueSeparation)
351354
},
355+
FormatExciseBoundsRecord: func(d *DB) error {
356+
return d.finalizeFormatVersUpgrade(FormatExciseBoundsRecord)
357+
},
352358
}
353359

354360
const formatVersionMarkerName = `format-version`

format_major_version_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ func TestFormatMajorVersionStableValues(t *testing.T) {
3535

3636
// When we add a new version, we should add a check for the new version in
3737
// addition to updating these expected values.
38-
require.Equal(t, FormatNewest, FormatMajorVersion(24))
39-
require.Equal(t, internalFormatNewest, FormatMajorVersion(24))
38+
require.Equal(t, FormatNewest, FormatMajorVersion(25))
39+
require.Equal(t, internalFormatNewest, FormatMajorVersion(25))
40+
require.Equal(t, FormatExciseBoundsRecord, FormatMajorVersion(25))
4041
}
4142

4243
func TestFormatMajorVersion_MigrationDefined(t *testing.T) {
@@ -77,6 +78,8 @@ func TestRatchetFormat(t *testing.T) {
7778
require.Equal(t, formatFooterAttributes, d.FormatMajorVersion())
7879
require.NoError(t, d.RatchetFormatMajorVersion(FormatValueSeparation))
7980
require.Equal(t, FormatValueSeparation, d.FormatMajorVersion())
81+
require.NoError(t, d.RatchetFormatMajorVersion(FormatExciseBoundsRecord))
82+
require.Equal(t, FormatExciseBoundsRecord, d.FormatMajorVersion())
8083

8184
require.NoError(t, d.Close())
8285

@@ -239,6 +242,7 @@ func TestFormatMajorVersions_TableFormat(t *testing.T) {
239242
formatDeprecatedExperimentalValueSeparation: {sstable.TableFormatPebblev1, sstable.TableFormatPebblev6},
240243
formatFooterAttributes: {sstable.TableFormatPebblev1, sstable.TableFormatPebblev7},
241244
FormatValueSeparation: {sstable.TableFormatPebblev1, sstable.TableFormatPebblev7},
245+
FormatExciseBoundsRecord: {sstable.TableFormatPebblev1, sstable.TableFormatPebblev7},
242246
}
243247

244248
// Valid versions.

ingest.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,6 +2108,10 @@ func (d *DB) ingestApply(
21082108
updateLevelMetricsOnExcise(m, layer.Level(), newFiles)
21092109
}
21102110
}
2111+
ve.ExciseBoundsRecord = append(ve.ExciseBoundsRecord, manifest.ExciseOpEntry{
2112+
Bounds: exciseBounds,
2113+
SeqNum: exciseSeqNum,
2114+
})
21112115
}
21122116
if len(filesToSplit) > 0 {
21132117
// For the same reasons as the above call to excise, we hold the db mutex

internal/manifest/testdata/version_edit_apply

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ apply v6
187187
add-table: L1 000003(000009):[a#2,SET-b#2,SET]
188188
add-table: L1 000004(000009):[c#2,SET-e#2,SET]
189189
add-backing: 000009
190+
excise-op: [b, c] #3
190191
----
191192
L1:
192193
000003(000009):[a#2,SET-b#2,SET] seqnums:[0-0] points:[a#2,SET-b#2,SET]

internal/manifest/testdata/version_edit_decode

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,37 @@ f9a006 # . ValueSize = 102521
6464
6c # <tagDeleteBlobFile>
6565
21 # . BlobFileID = 000033
6666
21 # . FileNum = 000033
67+
0a016201630103 # <tagExciseBoundsRecord>, [b, c] #3
6768
----
68-
021903660484106b2929d8a301f9a0069f9485bd066c2121
69+
021903660484106b2929d8a301f9a0069f9485bd066c21210a0162016301
70+
03
6971
log-num: 25
7072
next-file-num: 102
7173
last-seq-num: 2052
7274
add-blob-file: B000041 physical:{000041 size:[20952 (20KB)] vals:[102521 (100KB)]}
7375
del-blob-file: B000033 000033
76+
excise-op: [b, c] #3
7477

7578
encode
7679
add-table: L6 000029:[bar#14,DEL-foo#13,SET] blobrefs:[(B000041: 20952); depth:1]
7780
add-blob-file: B000943 physical:{000041 size:[20952 (20KB)] vals:[102521 (100KB)]}
7881
del-blob-file: B000033 000033
82+
excise-op: [b, c] #3
7983
----
8084
67061d000b626172000e0000000000000b666f6f010d0000000000000000
81-
45010129d8a301016baf0729d8a301f9a006006c2121
85+
45010129d8a301016baf0729d8a301f9a006006c21210a016201630103
8286
add-table: L6 000029:[bar#14,DEL-foo#13,SET] seqnums:[0-0] points:[bar#14,DEL-foo#13,SET] blobrefs:[(B000041: 20952); depth:1]
8387
add-blob-file: B000943 physical:{000041 size:[20952 (20KB)] vals:[102521 (100KB)]}
8488
del-blob-file: B000033 000033
89+
excise-op: [b, c] #3
8590

8691
decode
8792
67061d000b626172000e0000000000000b666f6f010d0000000000000000
88-
45010129d8a301016baf0729d8a301f9a006006c2121
93+
45010129d8a301016baf0729d8a301f9a006006c21210a016201630103
8994
----
9095
67061d000b626172000e0000000000000b666f6f010d0000000000000000
91-
45010129d8a301016baf0729d8a301f9a006006c2121
96+
45010129d8a301016baf0729d8a301f9a006006c21210a016201630103
9297
add-table: L6 000029:[bar#14,DEL-foo#13,SET]
9398
add-blob-file: B000943 physical:{000041 size:[20952 (20KB)] vals:[102521 (100KB)]}
9499
del-blob-file: B000033 000033
100+
excise-op: [b, c] #3

internal/manifest/version_edit.go

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ type byteReader interface {
3535
// Tag 8 is no longer used.
3636
const (
3737
// LevelDB tags.
38-
tagComparator = 1
39-
tagLogNumber = 2
40-
tagNextFileNumber = 3
41-
tagLastSequence = 4
42-
tagCompactPointer = 5
43-
tagDeletedFile = 6
44-
tagNewFile = 7
45-
tagPrevLogNumber = 9
38+
tagComparator = 1
39+
tagLogNumber = 2
40+
tagNextFileNumber = 3
41+
tagLastSequence = 4
42+
tagCompactPointer = 5
43+
tagDeletedFile = 6
44+
tagNewFile = 7
45+
tagPrevLogNumber = 9
46+
tagExciseBoundsRecord = 10
4647

4748
// RocksDB tags.
4849
tagNewFile2 = 100
@@ -98,6 +99,12 @@ type NewTableEntry struct {
9899
BackingFileNum base.DiskFileNum
99100
}
100101

102+
// ExciseOpEntry holds the bounds and sequence number for an excise operation.
103+
type ExciseOpEntry struct {
104+
Bounds base.UserKeyBounds
105+
SeqNum base.SeqNum
106+
}
107+
101108
// VersionEdit holds the state for an edit to a Version along with other
102109
// on-disk state (log numbers, next file number, and the last sequence number).
103110
type VersionEdit struct {
@@ -179,6 +186,9 @@ type VersionEdit struct {
179186
// While replaying a MANIFEST, the values are nil. Otherwise the values must
180187
// not be nil.
181188
DeletedBlobFiles map[DeletedBlobFileEntry]*PhysicalBlobFile
189+
190+
// ExciseBoundsRecord holds excise operations as a slice of entries.
191+
ExciseBoundsRecord []ExciseOpEntry
182192
}
183193

184194
// Decode decodes an edit from the specified reader.
@@ -575,6 +585,32 @@ func (v *VersionEdit) Decode(r io.Reader) error {
575585
}
576586
v.ObsoletePrevLogNum = n
577587

588+
case tagExciseBoundsRecord:
589+
start, err := d.readBytes()
590+
if err != nil {
591+
return err
592+
}
593+
end, err := d.readBytes()
594+
if err != nil {
595+
return err
596+
}
597+
kind, err := d.readUvarint()
598+
if err != nil {
599+
return err
600+
}
601+
seqNum, err := d.readUvarint()
602+
if err != nil {
603+
return err
604+
}
605+
bounds := base.UserKeyBounds{
606+
Start: start,
607+
End: base.UserKeyExclusiveIf(end, base.BoundaryKind(kind) == base.Exclusive),
608+
}
609+
v.ExciseBoundsRecord = append(v.ExciseBoundsRecord, ExciseOpEntry{
610+
Bounds: bounds,
611+
SeqNum: base.SeqNum(seqNum),
612+
})
613+
578614
case tagColumnFamily, tagColumnFamilyAdd, tagColumnFamilyDrop, tagMaxColumnFamily:
579615
return base.CorruptionErrorf("column families are not supported")
580616

@@ -641,6 +677,10 @@ func (v *VersionEdit) string(verbose bool, fmtKey base.FormatKey) string {
641677
for _, df := range deletedBlobFileEntries {
642678
fmt.Fprintf(&buf, " del-blob-file: %s %s\n", df.FileID, df.FileNum)
643679
}
680+
for _, exciseBounds := range v.ExciseBoundsRecord {
681+
fmt.Fprintf(&buf, " excise-op: %s #%d\n", exciseBounds.Bounds.String(), exciseBounds.SeqNum)
682+
}
683+
644684
return buf.String()
645685
}
646686

@@ -728,6 +768,14 @@ func ParseVersionEditDebug(s string) (_ *VersionEdit, err error) {
728768
FileNum: p.DiskFileNum(),
729769
}] = nil
730770

771+
case "excise-op":
772+
bounds := p.UserKeyBounds()
773+
seqNum := p.HashSeqNum()
774+
ve.ExciseBoundsRecord = append(ve.ExciseBoundsRecord, ExciseOpEntry{
775+
Bounds: bounds,
776+
SeqNum: seqNum,
777+
})
778+
731779
default:
732780
return nil, errors.Errorf("field %q not implemented", field)
733781
}
@@ -869,6 +917,13 @@ func (v *VersionEdit) Encode(w io.Writer) error {
869917
e.writeUvarint(uint64(x.FileID))
870918
e.writeUvarint(uint64(x.FileNum))
871919
}
920+
for _, entry := range v.ExciseBoundsRecord {
921+
e.writeUvarint(tagExciseBoundsRecord)
922+
e.writeBytes(entry.Bounds.Start)
923+
e.writeBytes(entry.Bounds.End.Key)
924+
e.writeUvarint(uint64(entry.Bounds.End.Kind))
925+
e.writeUvarint(uint64(entry.SeqNum))
926+
}
872927
_, err := w.Write(e.Bytes())
873928
return err
874929
}

internal/strparse/strparse.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,36 @@ func (p *Parser) TryLevel() (level int, ok bool) {
109109
return 0, false
110110
}
111111

112+
// BracketedRange parses UserKeyBounds as string form [a, b], [bb, cc),
113+
// handles exclusive and inclusive cases of excise bounds.
114+
func (p *Parser) BracketedRange() string {
115+
if p.Done() {
116+
p.Errf("expected bracketed range, but no tokens found")
117+
}
118+
open := p.Peek()
119+
if !(open == "[") {
120+
p.Errf("expected opening bracket, got %q", open)
121+
}
122+
123+
p.Next()
124+
var builder strings.Builder
125+
builder.WriteString(open)
126+
first := true
127+
for !p.Done() {
128+
tok := p.Next()
129+
if tok == "]" || tok == ")" {
130+
builder.WriteString(tok)
131+
break
132+
}
133+
if !first {
134+
builder.WriteString(" ")
135+
}
136+
builder.WriteString(tok)
137+
first = false
138+
}
139+
return builder.String()
140+
}
141+
112142
// Level parses the next token as a level.
113143
func (p *Parser) Level() int {
114144
level, ok := p.TryLevel()
@@ -150,6 +180,12 @@ func (p *Parser) SeqNum() base.SeqNum {
150180
return base.ParseSeqNum(p.Next())
151181
}
152182

183+
// Uint64 parses the next token as a sequence number with a "#" prefix.
184+
func (p *Parser) HashSeqNum() base.SeqNum {
185+
p.tokens[0] = p.tokens[0][1:]
186+
return base.ParseSeqNum(p.Next())
187+
}
188+
153189
// BlobFileID parses the next token as a BlobFileID.
154190
func (p *Parser) BlobFileID() base.BlobFileID {
155191
s := p.Next()
@@ -178,6 +214,11 @@ func (p *Parser) InternalKey() base.InternalKey {
178214
return base.ParseInternalKey(p.Next())
179215
}
180216

217+
// UserKeyBounds parses the next token as an user key interval.
218+
func (p *Parser) UserKeyBounds() base.UserKeyBounds {
219+
return base.ParseUserKeyBounds(p.BracketedRange())
220+
}
221+
181222
// Errf panics with an error which includes the original string and the last
182223
// token.
183224
func (p *Parser) Errf(format string, args ...any) {

open_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ func TestNewDBFilenames(t *testing.T) {
502502
"LOCK",
503503
"MANIFEST-000001",
504504
"OPTIONS-000003",
505-
"marker.format-version.000011.024",
505+
"marker.format-version.000012.025",
506506
"marker.manifest.000001.MANIFEST-000001",
507507
},
508508
}

0 commit comments

Comments
 (0)