@@ -18,7 +18,9 @@ import (
1818 "strings"
1919 "testing"
2020 "time"
21+ "unicode"
2122
23+ "github.com/cockroachdb/crlib/crstrings"
2224 "github.com/cockroachdb/datadriven"
2325 "github.com/cockroachdb/errors"
2426 "github.com/cockroachdb/pebble/bloom"
@@ -28,6 +30,7 @@ import (
2830 "github.com/cockroachdb/pebble/internal/rangekey"
2931 "github.com/cockroachdb/pebble/internal/sstableinternal"
3032 "github.com/cockroachdb/pebble/internal/testkeys"
33+ "github.com/cockroachdb/pebble/internal/testutils"
3134 "github.com/cockroachdb/pebble/objstorage/objstorageprovider"
3235 "github.com/cockroachdb/pebble/objstorage/remote"
3336 "github.com/cockroachdb/pebble/sstable"
@@ -428,26 +431,51 @@ func parseValue(s string) []byte {
428431 return []byte (s )
429432}
430433
434+ func splitFields (line string , n int ) ([]string , error ) {
435+ return splitFieldsRange (line , n , n )
436+ }
437+
438+ func splitFieldsRange (line string , minmum , maximum int ) ([]string , error ) {
439+ fields := strings .Fields (line )
440+ if len (fields ) < minmum {
441+ return nil , errors .Errorf ("require at least %d fields, got %d" , minmum , len (fields ))
442+ }
443+ if len (fields ) > maximum {
444+ fields [maximum - 1 ] = strings .Join (fields [maximum - 1 :], " " )
445+ fields = fields [:maximum ]
446+ }
447+ for i := range fields {
448+ if fields [i ] == `<nil>` {
449+ fields [i ] = ""
450+ }
451+ }
452+ return fields , nil
453+ }
454+
431455func runBatchDefineCmd (d * datadriven.TestData , b * Batch ) error {
432- for _ , line := range strings .Split (d .Input , "\n " ) {
433- parts := strings .Fields (line )
434- if len (parts ) == 0 {
456+ for _ , line := range crstrings .Lines (d .Input ) {
457+ i := strings .IndexFunc (line , unicode .IsSpace )
458+ cmd := line
459+ if i > 0 {
460+ cmd = line [:i ]
461+ } else if cmd == "" {
435462 continue
436463 }
437- if parts [1 ] == `<nil>` {
438- parts [1 ] = ""
439- }
464+
465+ var parts []string
440466 var err error
441- switch parts [ 0 ] {
467+ switch cmd {
442468 case "set" :
443- if len (parts ) != 3 {
444- return errors .Errorf ("%s expects 2 arguments" , parts [0 ])
469+ parts , err = splitFields (line , 3 )
470+ if err != nil {
471+ return err
445472 }
446473 err = b .Set ([]byte (parts [1 ]), parseValue (parts [2 ]), nil )
447474
448475 case "set-multiple" :
449- if len (parts ) != 3 {
450- return errors .Errorf ("%s expects 2 arguments (n and prefix)" , parts [0 ])
476+ parts , err = splitFields (line , 3 )
477+ if err != nil {
478+ return err
451479 }
452480 n , err := strconv .ParseUint (parts [1 ], 10 , 32 )
453481 if err != nil {
@@ -462,13 +490,15 @@ func runBatchDefineCmd(d *datadriven.TestData, b *Batch) error {
462490 }
463491
464492 case "del" :
465- if len (parts ) != 2 {
466- return errors .Errorf ("%s expects 1 argument" , parts [0 ])
493+ parts , err = splitFields (line , 2 )
494+ if err != nil {
495+ return err
467496 }
468497 err = b .Delete ([]byte (parts [1 ]), nil )
469498 case "del-sized" :
470- if len (parts ) != 3 {
471- return errors .Errorf ("%s expects 2 arguments" , parts [0 ])
499+ parts , err = splitFields (line , 3 )
500+ if err != nil {
501+ return err
472502 }
473503 var valSize uint64
474504 valSize , err = strconv .ParseUint (parts [2 ], 10 , 32 )
@@ -477,23 +507,27 @@ func runBatchDefineCmd(d *datadriven.TestData, b *Batch) error {
477507 }
478508 err = b .DeleteSized ([]byte (parts [1 ]), uint32 (valSize ), nil )
479509 case "singledel" :
480- if len (parts ) != 2 {
481- return errors .Errorf ("%s expects 1 argument" , parts [0 ])
510+ parts , err = splitFields (line , 2 )
511+ if err != nil {
512+ return err
482513 }
483514 err = b .SingleDelete ([]byte (parts [1 ]), nil )
484515 case "del-range" :
485- if len (parts ) != 3 {
486- return errors .Errorf ("%s expects 2 arguments" , parts [0 ])
516+ parts , err = splitFields (line , 3 )
517+ if err != nil {
518+ return err
487519 }
488520 err = b .DeleteRange ([]byte (parts [1 ]), []byte (parts [2 ]), nil )
489521 case "merge" :
490- if len (parts ) != 3 {
491- return errors .Errorf ("%s expects 2 arguments" , parts [0 ])
522+ parts , err = splitFields (line , 3 )
523+ if err != nil {
524+ return err
492525 }
493526 err = b .Merge ([]byte (parts [1 ]), parseValue (parts [2 ]), nil )
494527 case "range-key-set" :
495- if len (parts ) < 4 || len (parts ) > 5 {
496- return errors .Errorf ("%s expects 3 or 4 arguments" , parts [0 ])
528+ parts , err = splitFieldsRange (line , 4 , 5 )
529+ if err != nil {
530+ return err
497531 }
498532 var val []byte
499533 if len (parts ) == 5 {
@@ -506,24 +540,26 @@ func runBatchDefineCmd(d *datadriven.TestData, b *Batch) error {
506540 val ,
507541 nil )
508542 case "range-key-unset" :
509- if len (parts ) != 4 {
510- return errors .Errorf ("%s expects 3 arguments" , parts [0 ])
543+ parts , err = splitFields (line , 4 )
544+ if err != nil {
545+ return err
511546 }
512547 err = b .RangeKeyUnset (
513548 []byte (parts [1 ]),
514549 []byte (parts [2 ]),
515550 []byte (parts [3 ]),
516551 nil )
517552 case "range-key-del" :
518- if len (parts ) != 3 {
519- return errors .Errorf ("%s expects 2 arguments" , parts [0 ])
553+ parts , err = splitFields (line , 3 )
554+ if err != nil {
555+ return err
520556 }
521557 err = b .RangeKeyDelete (
522558 []byte (parts [1 ]),
523559 []byte (parts [2 ]),
524560 nil )
525561 default :
526- return errors .Errorf ("unknown op: %s" , parts [ 0 ] )
562+ return errors .Errorf ("unknown op: %s" , cmd )
527563 }
528564 if err != nil {
529565 return err
@@ -635,7 +671,27 @@ func runBuildRemoteCmd(td *datadriven.TestData, d *DB, storage remote.Storage) e
635671 return w .Close ()
636672}
637673
638- func runBuildCmd (td * datadriven.TestData , d * DB , fs vfs.FS ) error {
674+ type dataDrivenCmdOptions struct {
675+ blobValues * testutils.BlobValues
676+ }
677+
678+ func withBlobValues (bv * testutils.BlobValues ) func (* dataDrivenCmdOptions ) {
679+ return func (o * dataDrivenCmdOptions ) { o .blobValues = bv }
680+ }
681+
682+ func combineDataDrivenOpts (opts ... func (* dataDrivenCmdOptions )) dataDrivenCmdOptions {
683+ combined := dataDrivenCmdOptions {}
684+ for _ , opt := range opts {
685+ opt (& combined )
686+ }
687+ return combined
688+ }
689+
690+ func runBuildCmd (
691+ td * datadriven.TestData , d * DB , fs vfs.FS , opts ... func (* dataDrivenCmdOptions ),
692+ ) error {
693+ ddOpts := combineDataDrivenOpts (opts ... )
694+
639695 b := newIndexedBatch (nil , d .opts .Comparer )
640696 if err := runBatchDefineCmd (td , b ); err != nil {
641697 return err
@@ -660,14 +716,16 @@ func runBuildCmd(td *datadriven.TestData, d *DB, fs vfs.FS) error {
660716 tableFormat = sstable .TableFormatPebblev3
661717 case "pebblev4" :
662718 tableFormat = sstable .TableFormatPebblev4
719+ case "pebblev5" :
720+ tableFormat = sstable .TableFormatPebblev5
663721 default :
664722 return errors .Errorf ("unknown format string %s" , cmdArg .Vals [0 ])
665723 }
666724 }
667725 }
668726
669727 writeOpts := d .opts .MakeWriterOptions (0 /* level */ , tableFormat )
670-
728+ var blobReferences testutils. BlobReferences
671729 f , err := fs .Create (path , vfs .WriteCategoryUnspecified )
672730 if err != nil {
673731 return err
@@ -677,7 +735,22 @@ func runBuildCmd(td *datadriven.TestData, d *DB, fs vfs.FS) error {
677735 for kv := iter .First (); kv != nil ; kv = iter .Next () {
678736 tmp := kv .K
679737 tmp .SetSeqNum (0 )
680- if err := w .Raw ().Add (tmp , kv .InPlaceValue (), false ); err != nil {
738+
739+ v := kv .InPlaceValue ()
740+ // If the value looks like it's a debug blob handle, parse it and add it
741+ // to the sstable as a blob handle.
742+ if ddOpts .blobValues != nil && ddOpts .blobValues .IsBlobHandle (string (v )) {
743+ handle , err := ddOpts .blobValues .ParseInlineHandle (string (v ), & blobReferences )
744+ if err != nil {
745+ return err
746+ }
747+ if err := w .Raw ().AddWithBlobHandle (tmp , handle , base .ShortAttribute (0 ), false ); err != nil {
748+ return err
749+ }
750+ continue
751+ }
752+ // Otherwise add it as an ordinary value.
753+ if err := w .Raw ().Add (tmp , v , false ); err != nil {
681754 return err
682755 }
683756 }
0 commit comments