Skip to content

Commit c25e82e

Browse files
committed
tool: add blob handle print mode to tools
This patch adds the ability for commands in the `tool` package (`find`, `sstable check`,`sstable scan`) that read sstables in isolation to support printing the inline blob handles of val-separated kvs. Informs: #4448
1 parent 6816ec8 commit c25e82e

File tree

4 files changed

+91
-13
lines changed

4 files changed

+91
-13
lines changed

sstable/values.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ var AssertNoBlobHandles = TableBlobContext{
2121
References: nil,
2222
}
2323

24+
// DebugHandlesBlobContext is a TableBlobContext that configures a sstable
25+
// iterator to return the partially decoded inline blob handle upon encountering
26+
// a value that references an external blob file.
27+
var DebugHandlesBlobContext = TableBlobContext{
28+
ValueFetcher: nil,
29+
References: nil,
30+
// Passing a non-nil BlobHandleFn will return the partially decoded inline
31+
// handle before panicking due to missing BlobReferences.
32+
BlobHandleFn: func(preface blob.InlineHandlePreface, remainder []byte) base.InternalValue {
33+
handleSuffix := blob.DecodeHandleSuffix(remainder)
34+
ih := blob.InlineHandle{
35+
InlineHandlePreface: preface,
36+
HandleSuffix: handleSuffix,
37+
}
38+
return base.MakeInPlaceValue([]byte(ih.String()))
39+
},
40+
}
41+
2442
// BlobReferences provides a mapping from an index to a file number for a
2543
// sstable's blob references. In practice, this is implemented by
2644
// manifest.BlobReferences.
@@ -41,6 +59,10 @@ type TableBlobContext struct {
4159
// References provides a mapping from an index to a file number for a
4260
// sstable's blob references.
4361
References BlobReferences
62+
// BlobHandleFn is an optional function that is invoked after an inline blob
63+
// handle has had its preface decoded. Note that if this function is set,
64+
// we will not do any work in making a lazy value.
65+
BlobHandleFn func(preface blob.InlineHandlePreface, remainder []byte) base.InternalValue
4466
}
4567

4668
// defaultInternalValueConstructor is the default implementation of the
@@ -76,13 +98,6 @@ func (i *defaultInternalValueConstructor) GetInternalValueForPrefixAndValueHandl
7698
panic(errors.AssertionFailedf("block: %x is neither a valblk or blob handle prefix", vp))
7799
}
78100

79-
// We can't convert a blob handle into an InternalValue without
80-
// BlobReferences providing the mapping of a reference index to a blob file
81-
// number.
82-
if i.blobContext.References == nil {
83-
panic(errors.AssertionFailedf("blob references not configured"))
84-
}
85-
86101
// The first byte of [handle] is the valuePrefix byte.
87102
//
88103
// After that, is the inline-handle preface encoding a) the length of the
@@ -94,6 +109,20 @@ func (i *defaultInternalValueConstructor) GetInternalValueForPrefixAndValueHandl
94109
// value. We propagate it as LazyValue.ValueOrHandle.
95110
preface, remainder := blob.DecodeInlineHandlePreface(handle[1:])
96111

112+
// If BlobHandleFn is specified, we don't care about our value at all; we
113+
// just need to return what we have already decoded for our inline blob
114+
// handle.
115+
if i.blobContext.BlobHandleFn != nil {
116+
return i.blobContext.BlobHandleFn(preface, remainder)
117+
}
118+
119+
// We can't convert a blob handle into an InternalValue without
120+
// BlobReferences providing the mapping of a reference index to a blob file
121+
// number.
122+
if i.blobContext.References == nil {
123+
panic(errors.AssertionFailedf("blob references not configured"))
124+
}
125+
97126
if i.env.Stats != nil {
98127
// TODO(jackson): Add stats to differentiate between blob values and
99128
// value-block values.

tool/find.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type findT struct {
5555
fmtKey keyFormatter
5656
fmtValue valueFormatter
5757
verbose bool
58+
blobMode string
5859

5960
// Map from file num to version edit index which references the file num.
6061
editRefs map[base.DiskFileNum][]int
@@ -117,6 +118,8 @@ provenance of the sstables (flushed, ingested, compacted).
117118
&f.fmtKey, "key", "key formatter")
118119
f.Root.Flags().Var(
119120
&f.fmtValue, "value", "value formatter")
121+
f.Root.Flags().StringVar(
122+
&f.blobMode, "blob-mode", "none", "blob value formatter")
120123
return f
121124
}
122125

@@ -469,10 +472,17 @@ func (f *findT) searchTables(stdout io.Writer, searchKey []byte, refs []findRef)
469472
fragTransforms = m.FragmentIterTransforms()
470473
}
471474

472-
// TODO(jackson): Adjust to support two modes: one that surfaces the
475+
var blobContext sstable.TableBlobContext
476+
switch ConvertToBlobRefMode(f.blobMode) {
477+
case BlobRefModePrint:
478+
blobContext = sstable.DebugHandlesBlobContext
479+
default:
480+
blobContext = sstable.AssertNoBlobHandles
481+
}
482+
// TODO(annie): Adjust to support two modes: one that surfaces the
473483
// raw blob value handles, and one that fetches the blob values from
474484
// blob files uncovered by scanning the directory entries. See #4448.
475-
iter, err := r.NewIter(transforms, nil, nil, sstable.AssertNoBlobHandles)
485+
iter, err := r.NewIter(transforms, nil, nil, blobContext)
476486
if err != nil {
477487
return err
478488
}

tool/sstable.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type sstableT struct {
5050
filter key
5151
count int64
5252
verbose bool
53+
blobMode string
5354
}
5455

5556
func newSSTable(
@@ -121,6 +122,8 @@ inclusive-inclusive range specified by --start and --end.
121122

122123
s.Check.Flags().Var(
123124
&s.fmtKey, "key", "key formatter")
125+
s.Check.Flags().StringVar(
126+
&s.blobMode, "blob-mode", "none", "blob value formatter")
124127
s.Layout.Flags().Var(
125128
&s.fmtKey, "key", "key formatter")
126129
s.Layout.Flags().Var(
@@ -139,6 +142,8 @@ inclusive-inclusive range specified by --start and --end.
139142
&s.filter, "filter", "only output records with matching prefix or overlapping range tombstones")
140143
s.Scan.Flags().Int64Var(
141144
&s.count, "count", 0, "key count for scan (0 is unlimited)")
145+
s.Scan.Flags().StringVar(
146+
&s.blobMode, "blob-mode", "none", "blob value formatter")
142147

143148
return s
144149
}
@@ -163,10 +168,17 @@ func (s *sstableT) runCheck(cmd *cobra.Command, args []string) {
163168
s.fmtKey.setForComparer(r.Properties.ComparerName, s.comparers)
164169
s.fmtValue.setForComparer(r.Properties.ComparerName, s.comparers)
165170

166-
// TODO(jackson): Adjust to support two modes: one that surfaces the raw
171+
var blobContext sstable.TableBlobContext
172+
switch ConvertToBlobRefMode(s.blobMode) {
173+
case BlobRefModePrint:
174+
blobContext = sstable.DebugHandlesBlobContext
175+
default:
176+
blobContext = sstable.AssertNoBlobHandles
177+
}
178+
// TODO(annie): Adjust to support two modes: one that surfaces the raw
167179
// blob value handles, and one that fetches the blob values from blob
168180
// files uncovered by scanning the directory entries. See #4448.
169-
iter, err := r.NewIter(sstable.NoTransforms, nil, nil, sstable.AssertNoBlobHandles)
181+
iter, err := r.NewIter(sstable.NoTransforms, nil, nil, blobContext)
170182
if err != nil {
171183
fmt.Fprintf(stderr, "%s\n", err)
172184
return
@@ -334,10 +346,17 @@ func (s *sstableT) runScan(cmd *cobra.Command, args []string) {
334346
prefix = fmt.Sprintf("%s: ", path)
335347
}
336348

337-
// TODO(jackson): Adjust to support two modes: one that surfaces the raw
349+
var blobContext sstable.TableBlobContext
350+
switch ConvertToBlobRefMode(s.blobMode) {
351+
case BlobRefModePrint:
352+
blobContext = sstable.DebugHandlesBlobContext
353+
default:
354+
blobContext = sstable.AssertNoBlobHandles
355+
}
356+
// TODO(annie): Adjust to support two modes: one that surfaces the raw
338357
// blob value handles, and one that fetches the blob values from blob
339358
// files uncovered by scanning the directory entries. See #4448.
340-
iter, err := r.NewIter(sstable.NoTransforms, nil, s.end, sstable.AssertNoBlobHandles)
359+
iter, err := r.NewIter(sstable.NoTransforms, nil, s.end, blobContext)
341360
if err != nil {
342361
fmt.Fprintf(stderr, "%s%s\n", prefix, err)
343362
return

tool/tool.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,23 @@ func (t *T) ConfigureSharedStorage(
195195
t.opts.Experimental.CreateOnShared = createOnShared
196196
t.opts.Experimental.CreateOnSharedLocator = createOnSharedLocator
197197
}
198+
199+
// BlobRefMode specifies how blob references should be handled.
200+
type BlobRefMode int
201+
202+
const (
203+
// BlobRefModeNone specifies the AssertNoBlobHandles TableBlobContext.
204+
BlobRefModeNone BlobRefMode = iota
205+
// BlobRefModePrint specifies a TableBlobContext that allows printing the
206+
// raw blob handle without reading from any blob files.
207+
BlobRefModePrint
208+
)
209+
210+
func ConvertToBlobRefMode(s string) BlobRefMode {
211+
switch s {
212+
case "print":
213+
return BlobRefModePrint
214+
default:
215+
return BlobRefModeNone
216+
}
217+
}

0 commit comments

Comments
 (0)