Skip to content

Commit 8af50ee

Browse files
committed
internal/strparse: new package
Pull out the manifest package's debugParser used to facilitate parsing of debug representation's of data structures into a new internal package. This is in preparation for an additional use in parsing debug representations of blob handles.
1 parent f8261e8 commit 8af50ee

File tree

4 files changed

+50
-42
lines changed

4 files changed

+50
-42
lines changed

internal/manifest/blob_metadata.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/cockroachdb/pebble/internal/base"
1212
"github.com/cockroachdb/pebble/internal/humanize"
1313
"github.com/cockroachdb/pebble/internal/invariants"
14+
"github.com/cockroachdb/pebble/internal/strparse"
1415
"github.com/cockroachdb/redact"
1516
)
1617

@@ -148,7 +149,7 @@ func ParseBlobFileMetadataDebug(s string) (_ *BlobFileMetadata, err error) {
148149
// Input format:
149150
// 000000: size:[206536 (201KiB)], vals:[393256 (384KiB)]
150151
m := &BlobFileMetadata{}
151-
p := makeDebugParser(s)
152+
p := strparse.MakeParser(debugParserSeparators, s)
152153
m.FileNum = base.DiskFileNum(p.FileNum())
153154

154155
maybeSkipParens := func() {

internal/manifest/version.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/cockroachdb/errors"
1818
"github.com/cockroachdb/pebble/internal/base"
1919
"github.com/cockroachdb/pebble/internal/invariants"
20+
"github.com/cockroachdb/pebble/internal/strparse"
2021
"github.com/cockroachdb/pebble/sstable"
2122
"github.com/cockroachdb/pebble/sstable/block"
2223
)
@@ -882,6 +883,16 @@ func (m *TableMetadata) DebugString(format base.FormatKey, verbose bool) string
882883
return b.String()
883884
}
884885

886+
const debugParserSeparators = ":-[]();"
887+
888+
// errFromPanic can be used in a recover block to convert panics into errors.
889+
func errFromPanic(r any) error {
890+
if err, ok := r.(error); ok {
891+
return err
892+
}
893+
return errors.Errorf("%v", r)
894+
}
895+
885896
// ParseTableMetadataDebug parses a TableMetadata from its DebugString
886897
// representation.
887898
func ParseTableMetadataDebug(s string) (_ *TableMetadata, err error) {
@@ -894,7 +905,7 @@ func ParseTableMetadataDebug(s string) (_ *TableMetadata, err error) {
894905
// Input format:
895906
// 000000:[a#0,SET-z#0,SET] seqnums:[5-5] points:[...] ranges:[...] size:5
896907
m := &TableMetadata{}
897-
p := makeDebugParser(s)
908+
p := strparse.MakeParser(debugParserSeparators, s)
898909
m.FileNum = p.FileNum()
899910
var backingNum base.DiskFileNum
900911
if p.Peek() == "(" {
@@ -1357,7 +1368,7 @@ func ParseVersionDebug(comparer *base.Comparer, flushSplitBytes int64, s string)
13571368
if l == "" {
13581369
continue
13591370
}
1360-
p := makeDebugParser(l)
1371+
p := strparse.MakeParser(debugParserSeparators, l)
13611372
if l, ok := p.TryLevel(); ok {
13621373
level = l
13631374
continue

internal/manifest/version_edit.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/cockroachdb/errors"
1919
"github.com/cockroachdb/pebble/internal/base"
2020
"github.com/cockroachdb/pebble/internal/invariants"
21+
"github.com/cockroachdb/pebble/internal/strparse"
2122
"github.com/cockroachdb/pebble/sstable"
2223
)
2324

@@ -640,7 +641,7 @@ func ParseVersionEditDebug(s string) (_ *VersionEdit, err error) {
640641
return nil, errors.Errorf("malformed line %q", l)
641642
}
642643
field = strings.TrimSpace(field)
643-
p := makeDebugParser(value)
644+
p := strparse.MakeParser(debugParserSeparators, value)
644645
switch field {
645646
case "add-table":
646647
level := p.Level()

internal/manifest/testutils.go renamed to internal/strparse/strparse.go

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// of this source code is governed by a BSD-style license that can be found in
33
// the LICENSE file.
44

5-
package manifest
5+
// Package strparse provides facilities for parsing strings, intended for use in
6+
// tests and debug input.
7+
package strparse
68

79
import (
810
"fmt"
@@ -14,31 +16,32 @@ import (
1416
"github.com/cockroachdb/pebble/internal/base"
1517
)
1618

17-
// debugParser is a helper used to implement parsing of debug strings, like
18-
// ParseFileMetadataDebug.
19+
// Parser is a helper used to implement parsing of strings, like
20+
// manifest.ParseFileMetadataDebug.
1921
//
2022
// It takes a string and splits it into tokens. Tokens are separated by
21-
// whitespace; in addition separators "_-[]()" are always separate tokens. For
22-
// example, the string `000001:[a - b]` results in tokens `000001`,
23-
// `:`, `[`, `a`, `-`, `b`, `]`, .
23+
// whitespace; in addition user-specified separators are also always separate
24+
// tokens. For example, when passed the separators `:-[]();` the string
25+
// `000001:[a - b]` results in tokens `000001`, `:`, `[`, `a`, `-`, `b`, `]`, .
2426
//
25-
// All debugParser methods throw panics instead of returning errors. The code
26-
// that uses a debugParser can recover them and convert them to errors.
27-
type debugParser struct {
27+
// All Parser methods throw panics instead of returning errors. The code
28+
// that uses a Parser can recover them and convert them to errors.
29+
type Parser struct {
2830
original string
2931
tokens []string
3032
lastToken string
3133
}
3234

33-
const debugParserSeparators = ":-[]();"
34-
35-
func makeDebugParser(s string) debugParser {
36-
p := debugParser{
37-
original: s,
35+
// MakeParser constructs a new Parser that converts any instance of the runes
36+
// contained in [separators] into separate tokens, and consumes the provided
37+
// input string.
38+
func MakeParser(separators string, input string) Parser {
39+
p := Parser{
40+
original: input,
3841
}
39-
for _, f := range strings.Fields(s) {
42+
for _, f := range strings.Fields(input) {
4043
for f != "" {
41-
pos := strings.IndexAny(f, debugParserSeparators)
44+
pos := strings.IndexAny(f, separators)
4245
if pos == -1 {
4346
p.tokens = append(p.tokens, f)
4447
break
@@ -54,13 +57,13 @@ func makeDebugParser(s string) debugParser {
5457
}
5558

5659
// Done returns true if there are no more tokens.
57-
func (p *debugParser) Done() bool {
60+
func (p *Parser) Done() bool {
5861
return len(p.tokens) == 0
5962
}
6063

6164
// Peek returns the next token, without consuming the token. Returns "" if there
6265
// are no more tokens.
63-
func (p *debugParser) Peek() string {
66+
func (p *Parser) Peek() string {
6467
if p.Done() {
6568
p.lastToken = ""
6669
return ""
@@ -70,7 +73,7 @@ func (p *debugParser) Peek() string {
7073
}
7174

7275
// Next returns the next token, or "" if there are no more tokens.
73-
func (p *debugParser) Next() string {
76+
func (p *Parser) Next() string {
7477
res := p.Peek()
7578
if res != "" {
7679
p.tokens = p.tokens[1:]
@@ -79,15 +82,15 @@ func (p *debugParser) Next() string {
7982
}
8083

8184
// Remaining returns all the remaining tokens, separated by spaces.
82-
func (p *debugParser) Remaining() string {
85+
func (p *Parser) Remaining() string {
8386
res := strings.Join(p.tokens, " ")
8487
p.tokens = nil
8588
return res
8689
}
8790

8891
// Expect consumes the next tokens, verifying that they exactly match the
8992
// arguments.
90-
func (p *debugParser) Expect(tokens ...string) {
93+
func (p *Parser) Expect(tokens ...string) {
9194
for _, tok := range tokens {
9295
if res := p.Next(); res != tok {
9396
p.Errf("expected %q, got %q", tok, res)
@@ -97,7 +100,7 @@ func (p *debugParser) Expect(tokens ...string) {
97100

98101
// TryLevel tries to parse a token as a level (e.g. L1, L0.2). If successful,
99102
// the token is consumed.
100-
func (p *debugParser) TryLevel() (level int, ok bool) {
103+
func (p *Parser) TryLevel() (level int, ok bool) {
101104
t := p.Peek()
102105
if regexp.MustCompile(`^L[0-9](|\.[0-9]+)$`).MatchString(t) {
103106
p.Next()
@@ -107,7 +110,7 @@ func (p *debugParser) TryLevel() (level int, ok bool) {
107110
}
108111

109112
// Level parses the next token as a level.
110-
func (p *debugParser) Level() int {
113+
func (p *Parser) Level() int {
111114
level, ok := p.TryLevel()
112115
if !ok {
113116
p.Errf("cannot parse level")
@@ -116,7 +119,7 @@ func (p *debugParser) Level() int {
116119
}
117120

118121
// Int parses the next token as an integer.
119-
func (p *debugParser) Int() int {
122+
func (p *Parser) Int() int {
120123
x, err := strconv.Atoi(p.Next())
121124
if err != nil {
122125
p.Errf("cannot parse number: %v", err)
@@ -125,7 +128,7 @@ func (p *debugParser) Int() int {
125128
}
126129

127130
// Uint64 parses the next token as an uint64.
128-
func (p *debugParser) Uint64() uint64 {
131+
func (p *Parser) Uint64() uint64 {
129132
x, err := strconv.ParseUint(p.Next(), 10, 64)
130133
if err != nil {
131134
p.Errf("cannot parse number: %v", err)
@@ -134,36 +137,28 @@ func (p *debugParser) Uint64() uint64 {
134137
}
135138

136139
// Uint64 parses the next token as a sequence number.
137-
func (p *debugParser) SeqNum() base.SeqNum {
140+
func (p *Parser) SeqNum() base.SeqNum {
138141
return base.ParseSeqNum(p.Next())
139142
}
140143

141144
// FileNum parses the next token as a FileNum.
142-
func (p *debugParser) FileNum() base.FileNum {
145+
func (p *Parser) FileNum() base.FileNum {
143146
return base.FileNum(p.Int())
144147
}
145148

146149
// DiskFileNum parses the next token as a DiskFileNum.
147-
func (p *debugParser) DiskFileNum() base.DiskFileNum {
150+
func (p *Parser) DiskFileNum() base.DiskFileNum {
148151
return base.DiskFileNum(p.Int())
149152
}
150153

151154
// InternalKey parses the next token as an internal key.
152-
func (p *debugParser) InternalKey() base.InternalKey {
155+
func (p *Parser) InternalKey() base.InternalKey {
153156
return base.ParseInternalKey(p.Next())
154157
}
155158

156159
// Errf panics with an error which includes the original string and the last
157160
// token.
158-
func (p *debugParser) Errf(format string, args ...any) {
161+
func (p *Parser) Errf(format string, args ...any) {
159162
msg := fmt.Sprintf(format, args...)
160163
panic(errors.Errorf("error parsing %q at token %q: %s", p.original, p.lastToken, msg))
161164
}
162-
163-
// errFromPanic can be used in a recover block to convert panics into errors.
164-
func errFromPanic(r any) error {
165-
if err, ok := r.(error); ok {
166-
return err
167-
}
168-
return errors.Errorf("%v", r)
169-
}

0 commit comments

Comments
 (0)