Line data Source code
1 : // Copyright 2019 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 tool
6 :
7 : import (
8 : "github.com/cockroachdb/pebble"
9 : "github.com/cockroachdb/pebble/bloom"
10 : "github.com/cockroachdb/pebble/internal/base"
11 : "github.com/cockroachdb/pebble/objstorage/remote"
12 : "github.com/cockroachdb/pebble/sstable"
13 : "github.com/cockroachdb/pebble/sstable/colblk"
14 : "github.com/cockroachdb/pebble/vfs"
15 : "github.com/spf13/cobra"
16 : )
17 :
18 : // Comparer exports the base.Comparer type.
19 : type Comparer = base.Comparer
20 :
21 : // FilterPolicy exports the base.FilterPolicy type.
22 : type FilterPolicy = base.FilterPolicy
23 :
24 : // Merger exports the base.Merger type.
25 : type Merger = base.Merger
26 :
27 : // T is the container for all of the introspection tools.
28 : type T struct {
29 : Commands []*cobra.Command
30 : db *dbT
31 : find *findT
32 : lsm *lsmT
33 : manifest *manifestT
34 : remotecat *remoteCatalogT
35 : sstable *sstableT
36 : wal *walT
37 : opts pebble.Options
38 : comparers sstable.Comparers
39 : mergers sstable.Mergers
40 : defaultComparer string
41 : openErrEnhancer func(error) error
42 : openOptions []OpenOption
43 : exciseSpanFn DBExciseSpanFn
44 : }
45 :
46 : // A Option configures the Pebble introspection tool.
47 : type Option func(*T)
48 :
49 : // Comparers may be passed to New to register comparers for use by
50 : // the introspesction tools.
51 1 : func Comparers(cmps ...*Comparer) Option {
52 1 : return func(t *T) {
53 1 : for _, c := range cmps {
54 1 : t.comparers[c.Name] = c
55 1 : }
56 : }
57 : }
58 :
59 : // KeySchema configures the name of the schema to use when writing sstables.
60 0 : func KeySchema(name string) Option {
61 0 : return func(t *T) {
62 0 : t.opts.KeySchema = name
63 0 : }
64 : }
65 :
66 : // KeySchemas may be passed to New to register key schemas for use by the
67 : // introspection tools.
68 0 : func KeySchemas(schemas ...*colblk.KeySchema) Option {
69 0 : return func(t *T) {
70 0 : if t.opts.KeySchemas == nil {
71 0 : t.opts.KeySchemas = make(map[string]*colblk.KeySchema)
72 0 : }
73 0 : for _, s := range schemas {
74 0 : t.opts.KeySchemas[s.Name] = s
75 0 : }
76 : }
77 : }
78 :
79 : // DefaultComparer registers a comparer for use by the introspection tools and
80 : // sets it as the default.
81 1 : func DefaultComparer(c *Comparer) Option {
82 1 : return func(t *T) {
83 1 : t.comparers[c.Name] = c
84 1 : t.defaultComparer = c.Name
85 1 : }
86 : }
87 :
88 : // Mergers may be passed to New to register mergers for use by the
89 : // introspection tools.
90 1 : func Mergers(mergers ...*Merger) Option {
91 1 : return func(t *T) {
92 1 : for _, m := range mergers {
93 1 : t.mergers[m.Name] = m
94 1 : }
95 : }
96 : }
97 :
98 : // Filters may be passed to New to register filter policies for use by the
99 : // introspection tools.
100 1 : func Filters(filters ...FilterPolicy) Option {
101 1 : return func(t *T) {
102 1 : for _, f := range filters {
103 1 : t.opts.Filters[f.Name()] = f
104 1 : }
105 : }
106 : }
107 :
108 : // OpenOptions may be passed to New to provide a set of OpenOptions that should
109 : // be invoked to configure the *pebble.Options before opening a database.
110 0 : func OpenOptions(openOptions ...OpenOption) Option {
111 0 : return func(t *T) {
112 0 : t.openOptions = append(t.openOptions, openOptions...)
113 0 : }
114 : }
115 :
116 : // FS sets the filesystem implementation to use by the introspection tools.
117 1 : func FS(fs vfs.FS) Option {
118 1 : return func(t *T) {
119 1 : t.opts.FS = fs
120 1 : }
121 : }
122 :
123 : // OpenErrEnhancer sets a function that enhances an error encountered when the
124 : // tool opens a database; used to provide the user additional context, for
125 : // example that a corruption error might be caused by encryption at rest not
126 : // being configured properly.
127 1 : func OpenErrEnhancer(fn func(error) error) Option {
128 1 : return func(t *T) {
129 1 : t.openErrEnhancer = fn
130 1 : }
131 : }
132 :
133 : // DBExciseSpanFn is a function used to obtain the excise span for the `db
134 : // excise` command. This allows a higher-level wrapper to add its own way of
135 : // specifying the span. Returns an invalid KeyRange if none was specified (in
136 : // which case the default --start/end flags are used).
137 : type DBExciseSpanFn func() (pebble.KeyRange, error)
138 :
139 : // WithDBExciseSpanFn specifies a function that returns the excise span for the
140 : // `db excise` command.
141 0 : func WithDBExciseSpanFn(fn DBExciseSpanFn) Option {
142 0 : return func(t *T) {
143 0 : t.exciseSpanFn = fn
144 0 : }
145 : }
146 :
147 : // New creates a new introspection tool.
148 1 : func New(opts ...Option) *T {
149 1 : t := &T{
150 1 : opts: pebble.Options{
151 1 : Filters: make(map[string]FilterPolicy),
152 1 : FS: vfs.Default,
153 1 : ReadOnly: true,
154 1 : },
155 1 : comparers: make(sstable.Comparers),
156 1 : mergers: make(sstable.Mergers),
157 1 : defaultComparer: base.DefaultComparer.Name,
158 1 : }
159 1 :
160 1 : opts = append(opts,
161 1 : Comparers(base.DefaultComparer),
162 1 : Filters(bloom.FilterPolicy(10)),
163 1 : Mergers(base.DefaultMerger))
164 1 :
165 1 : for _, opt := range opts {
166 1 : opt(t)
167 1 : }
168 :
169 1 : t.db = newDB(&t.opts, t.comparers, t.mergers, t.openErrEnhancer, t.openOptions, t.exciseSpanFn)
170 1 : t.find = newFind(&t.opts, t.comparers, t.defaultComparer, t.mergers)
171 1 : t.lsm = newLSM(&t.opts, t.comparers)
172 1 : t.manifest = newManifest(&t.opts, t.comparers)
173 1 : t.remotecat = newRemoteCatalog(&t.opts)
174 1 : t.sstable = newSSTable(&t.opts, t.comparers, t.mergers)
175 1 : t.wal = newWAL(&t.opts, t.comparers, t.defaultComparer)
176 1 : t.Commands = []*cobra.Command{
177 1 : t.db.Root,
178 1 : t.find.Root,
179 1 : t.lsm.Root,
180 1 : t.manifest.Root,
181 1 : t.remotecat.Root,
182 1 : t.sstable.Root,
183 1 : t.wal.Root,
184 1 : }
185 1 : return t
186 : }
187 :
188 : // ConfigureSharedStorage updates the shared storage options.
189 : func (t *T) ConfigureSharedStorage(
190 : s remote.StorageFactory,
191 : createOnShared remote.CreateOnSharedStrategy,
192 : createOnSharedLocator remote.Locator,
193 0 : ) {
194 0 : t.opts.Experimental.RemoteStorage = s
195 0 : t.opts.Experimental.CreateOnShared = createOnShared
196 0 : t.opts.Experimental.CreateOnSharedLocator = createOnSharedLocator
197 0 : }
|