5
5
package tool
6
6
7
7
import (
8
+ "bufio"
8
9
"context"
9
10
"fmt"
10
11
"io"
12
+ "strings"
11
13
"text/tabwriter"
12
14
13
15
"github.com/cockroachdb/errors"
@@ -29,6 +31,7 @@ import (
29
31
type dbT struct {
30
32
Root * cobra.Command
31
33
Check * cobra.Command
34
+ Upgrade * cobra.Command
32
35
Checkpoint * cobra.Command
33
36
Get * cobra.Command
34
37
Logs * cobra.Command
@@ -58,6 +61,7 @@ type dbT struct {
58
61
ioParallelism int
59
62
ioSizes string
60
63
verbose bool
64
+ bypassPrompt bool
61
65
}
62
66
63
67
func newDB (
@@ -93,6 +97,17 @@ database not be in use by another process.
93
97
Args : cobra .ExactArgs (1 ),
94
98
Run : d .runCheck ,
95
99
}
100
+ d .Upgrade = & cobra.Command {
101
+ Use : "upgrade <dir>" ,
102
+ Short : "upgrade the DB internal format version" ,
103
+ Long : `
104
+ Upgrades the DB internal format version to the latest version.
105
+ It is recommended to make a backup copy of the DB directory before upgrading.
106
+ Requires that the specified database not be in use by another process.
107
+ ` ,
108
+ Args : cobra .ExactArgs (1 ),
109
+ Run : d .runUpgrade ,
110
+ }
96
111
d .Checkpoint = & cobra.Command {
97
112
Use : "checkpoint <src-dir> <dest-dir>" ,
98
113
Short : "create a checkpoint" ,
@@ -177,10 +192,10 @@ specified database.
177
192
Run : d .runIOBench ,
178
193
}
179
194
180
- d .Root .AddCommand (d .Check , d .Checkpoint , d .Get , d .Logs , d .LSM , d .Properties , d .Scan , d .Set , d .Space , d .IOBench )
195
+ d .Root .AddCommand (d .Check , d .Upgrade , d . Checkpoint , d .Get , d .Logs , d .LSM , d .Properties , d .Scan , d .Set , d .Space , d .IOBench )
181
196
d .Root .PersistentFlags ().BoolVarP (& d .verbose , "verbose" , "v" , false , "verbose output" )
182
197
183
- for _ , cmd := range []* cobra.Command {d .Check , d .Checkpoint , d .Get , d .LSM , d .Properties , d .Scan , d .Set , d .Space } {
198
+ for _ , cmd := range []* cobra.Command {d .Check , d .Upgrade , d . Checkpoint , d .Get , d .LSM , d .Properties , d .Scan , d .Set , d .Space } {
184
199
cmd .Flags ().StringVar (
185
200
& d .comparerName , "comparer" , "" , "comparer name (use default if empty)" )
186
201
cmd .Flags ().StringVar (
@@ -200,6 +215,10 @@ specified database.
200
215
cmd .Flags ().Var (
201
216
& d .fmtValue , "value" , "value formatter" )
202
217
}
218
+ for _ , cmd := range []* cobra.Command {d .Upgrade } {
219
+ cmd .Flags ().BoolVarP (
220
+ & d .bypassPrompt , "yes" , "y" , false , "bypass prompt" )
221
+ }
203
222
204
223
d .Scan .Flags ().Int64Var (
205
224
& d .count , "count" , 0 , "key count for scan (0 is unlimited)" )
@@ -350,13 +369,43 @@ func (d *dbT) runCheck(cmd *cobra.Command, args []string) {
350
369
stats .NumPoints , makePlural ("point" , stats .NumPoints ), stats .NumTombstones , makePlural ("tombstone" , int64 (stats .NumTombstones )))
351
370
}
352
371
353
- type nonReadOnly struct {}
372
+ func (d * dbT ) runUpgrade (cmd * cobra.Command , args []string ) {
373
+ stdout , stderr := cmd .OutOrStdout (), cmd .ErrOrStderr ()
374
+ db , err := d .openDB (args [0 ], nonReadOnly {})
375
+ if err != nil {
376
+ fmt .Fprintf (stderr , "%s\n " , err )
377
+ return
378
+ }
379
+ defer d .closeDB (stderr , db )
354
380
355
- func (n nonReadOnly ) apply (opts * pebble.Options ) {
356
- opts .ReadOnly = false
357
- // Increase the L0 compaction threshold to reduce the likelihood of an
358
- // unintended compaction changing test output.
359
- opts .L0CompactionThreshold = 10
381
+ targetVersion := pebble .FormatNewest
382
+ current := db .FormatMajorVersion ()
383
+ if current >= targetVersion {
384
+ fmt .Fprintf (stdout , "DB is already at internal version %d.\n " , current )
385
+ return
386
+ }
387
+ fmt .Fprintf (stdout , "Upgrading DB from internal version %d to %d.\n " , current , targetVersion )
388
+
389
+ prompt := `WARNING!!!
390
+ This DB will not be usable with older versions of Pebble!
391
+
392
+ It is strongly recommended to back up the data before upgrading.
393
+ `
394
+
395
+ if len (d .opts .BlockPropertyCollectors ) == 0 {
396
+ prompt += `
397
+ If this DB uses custom block property collectors, the upgrade should be invoked
398
+ through a custom binary that configures them. Otherwise, any new tables created
399
+ during upgrade will not have the relevant block properties.
400
+ `
401
+ }
402
+ if ! d .promptForConfirmation (prompt , cmd .InOrStdin (), stdout , stderr ) {
403
+ return
404
+ }
405
+ if err := db .RatchetFormatMajorVersion (targetVersion ); err != nil {
406
+ fmt .Fprintf (stderr , "error: %s\n " , err )
407
+ }
408
+ fmt .Fprintf (stdout , "Upgrade complete.\n " )
360
409
}
361
410
362
411
func (d * dbT ) runCheckpoint (cmd * cobra.Command , args []string ) {
@@ -665,6 +714,46 @@ func (d *dbT) runSet(cmd *cobra.Command, args []string) {
665
714
}
666
715
}
667
716
717
+ func (d * dbT ) promptForConfirmation (prompt string , stdin io.Reader , stdout , stderr io.Writer ) bool {
718
+ if d .bypassPrompt {
719
+ return true
720
+ }
721
+ if _ , err := fmt .Fprintf (stdout , "%s\n " , prompt ); err != nil {
722
+ fmt .Fprintf (stderr , "Error: %v\n " , err )
723
+ return false
724
+ }
725
+ reader := bufio .NewReader (stdin )
726
+ for {
727
+ if _ , err := fmt .Fprintf (stdout , "Continue? [Y/N] " ); err != nil {
728
+ fmt .Fprintf (stderr , "Error: %v\n " , err )
729
+ return false
730
+ }
731
+ answer , err := reader .ReadString ('\n' )
732
+ if err != nil {
733
+ fmt .Fprintf (stderr , "Error: %v\n " , err )
734
+ return false
735
+ }
736
+ answer = strings .ToLower (strings .TrimSpace (answer ))
737
+ if answer == "y" || answer == "yes" {
738
+ return true
739
+ }
740
+
741
+ if answer == "n" || answer == "no" {
742
+ _ , _ = fmt .Fprintf (stderr , "Aborting\n " )
743
+ return false
744
+ }
745
+ }
746
+ }
747
+
748
+ type nonReadOnly struct {}
749
+
750
+ func (n nonReadOnly ) apply (opts * pebble.Options ) {
751
+ opts .ReadOnly = false
752
+ // Increase the L0 compaction threshold to reduce the likelihood of an
753
+ // unintended compaction changing test output.
754
+ opts .L0CompactionThreshold = 10
755
+ }
756
+
668
757
func propArgs (props []props , getProp func (* props ) interface {}) []interface {} {
669
758
args := make ([]interface {}, 0 , len (props ))
670
759
for _ , p := range props {
0 commit comments