github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/sstable/data_test.go (about)

     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 sstable
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/cockroachdb/errors"
    15  	"github.com/zuoyebang/bitalostable/bloom"
    16  	"github.com/zuoyebang/bitalostable/internal/base"
    17  	"github.com/zuoyebang/bitalostable/internal/cache"
    18  	"github.com/zuoyebang/bitalostable/internal/datadriven"
    19  	"github.com/zuoyebang/bitalostable/internal/keyspan"
    20  	"github.com/zuoyebang/bitalostable/vfs"
    21  )
    22  
    23  func optsFromArgs(td *datadriven.TestData, writerOpts *WriterOptions) error {
    24  	for _, arg := range td.CmdArgs {
    25  		switch arg.Key {
    26  		case "leveldb":
    27  			if len(arg.Vals) != 0 {
    28  				return errors.Errorf("%s: arg %s expects 0 values", td.Cmd, arg.Key)
    29  			}
    30  			writerOpts.TableFormat = TableFormatLevelDB
    31  		case "block-size":
    32  			if len(arg.Vals) != 1 {
    33  				return errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key)
    34  			}
    35  			var err error
    36  			writerOpts.BlockSize, err = strconv.Atoi(arg.Vals[0])
    37  			if err != nil {
    38  				return err
    39  			}
    40  		case "index-block-size":
    41  			if len(arg.Vals) != 1 {
    42  				return errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key)
    43  			}
    44  			var err error
    45  			writerOpts.IndexBlockSize, err = strconv.Atoi(arg.Vals[0])
    46  			if err != nil {
    47  				return err
    48  			}
    49  		case "filter":
    50  			writerOpts.FilterPolicy = bloom.FilterPolicy(10)
    51  		case "comparer-split-4b-suffix":
    52  			writerOpts.Comparer = test4bSuffixComparer
    53  		}
    54  	}
    55  	return nil
    56  }
    57  
    58  func runBuildCmd(
    59  	td *datadriven.TestData, writerOpts *WriterOptions, cacheSize int,
    60  ) (*WriterMetadata, *Reader, error) {
    61  
    62  	f0 := &memFile{}
    63  	if err := optsFromArgs(td, writerOpts); err != nil {
    64  		return nil, nil, err
    65  	}
    66  
    67  	w := NewWriter(f0, *writerOpts)
    68  	var rangeDels []keyspan.Span
    69  	rangeDelFrag := keyspan.Fragmenter{
    70  		Cmp:    DefaultComparer.Compare,
    71  		Format: DefaultComparer.FormatKey,
    72  		Emit: func(s keyspan.Span) {
    73  			rangeDels = append(rangeDels, s)
    74  		},
    75  	}
    76  	var rangeKeys []keyspan.Span
    77  	rangeKeyFrag := keyspan.Fragmenter{
    78  		Cmp:    DefaultComparer.Compare,
    79  		Format: DefaultComparer.FormatKey,
    80  		Emit: func(s keyspan.Span) {
    81  			rangeKeys = append(rangeKeys, s)
    82  		},
    83  	}
    84  	for _, data := range strings.Split(td.Input, "\n") {
    85  		if strings.HasPrefix(data, "rangekey:") {
    86  			var err error
    87  			func() {
    88  				defer func() {
    89  					if r := recover(); r != nil {
    90  						err = errors.Errorf("%v", r)
    91  					}
    92  				}()
    93  				rangeKeyFrag.Add(keyspan.ParseSpan(strings.TrimPrefix(data, "rangekey:")))
    94  			}()
    95  			if err != nil {
    96  				return nil, nil, err
    97  			}
    98  			continue
    99  		}
   100  
   101  		j := strings.Index(data, ":")
   102  		key := base.ParseInternalKey(data[:j])
   103  		value := []byte(data[j+1:])
   104  		switch key.Kind() {
   105  		case InternalKeyKindRangeDelete:
   106  			var err error
   107  			func() {
   108  				defer func() {
   109  					if r := recover(); r != nil {
   110  						err = errors.Errorf("%v", r)
   111  					}
   112  				}()
   113  				rangeDelFrag.Add(keyspan.Span{
   114  					Start: key.UserKey,
   115  					End:   value,
   116  					Keys:  []keyspan.Key{{Trailer: key.Trailer}},
   117  				})
   118  			}()
   119  			if err != nil {
   120  				return nil, nil, err
   121  			}
   122  		default:
   123  			if err := w.Add(key, value); err != nil {
   124  				return nil, nil, err
   125  			}
   126  		}
   127  	}
   128  	rangeDelFrag.Finish()
   129  	for _, v := range rangeDels {
   130  		for _, k := range v.Keys {
   131  			ik := base.InternalKey{UserKey: v.Start, Trailer: k.Trailer}
   132  			if err := w.Add(ik, v.End); err != nil {
   133  				return nil, nil, err
   134  			}
   135  		}
   136  	}
   137  	rangeKeyFrag.Finish()
   138  	for _, s := range rangeKeys {
   139  		if err := w.addRangeKeySpan(s); err != nil {
   140  			return nil, nil, err
   141  		}
   142  	}
   143  	if err := w.Close(); err != nil {
   144  		return nil, nil, err
   145  	}
   146  	meta, err := w.Metadata()
   147  	if err != nil {
   148  		return nil, nil, err
   149  	}
   150  
   151  	readerOpts := ReaderOptions{Comparer: writerOpts.Comparer}
   152  	if writerOpts.FilterPolicy != nil {
   153  		readerOpts.Filters = map[string]FilterPolicy{
   154  			writerOpts.FilterPolicy.Name(): writerOpts.FilterPolicy,
   155  		}
   156  	}
   157  	if cacheSize > 0 {
   158  		readerOpts.Cache = cache.New(int64(cacheSize))
   159  		defer readerOpts.Cache.Unref()
   160  	}
   161  	r, err := NewMemReader(f0.Data(), readerOpts)
   162  	if err != nil {
   163  		return nil, nil, err
   164  	}
   165  	return meta, r, nil
   166  }
   167  
   168  func runBuildRawCmd(
   169  	td *datadriven.TestData, opts *WriterOptions,
   170  ) (*WriterMetadata, *Reader, error) {
   171  	mem := vfs.NewMem()
   172  	f0, err := mem.Create("test")
   173  	if err != nil {
   174  		return nil, nil, err
   175  	}
   176  
   177  	w := NewWriter(f0, *opts)
   178  	for i := range td.CmdArgs {
   179  		arg := &td.CmdArgs[i]
   180  		if arg.Key == "range-del-v1" {
   181  			w.rangeDelV1Format = true
   182  			break
   183  		}
   184  	}
   185  
   186  	for _, data := range strings.Split(td.Input, "\n") {
   187  		if strings.HasPrefix(data, "rangekey:") {
   188  			data = strings.TrimPrefix(data, "rangekey:")
   189  			if err := w.addRangeKeySpan(keyspan.ParseSpan(data)); err != nil {
   190  				return nil, nil, err
   191  			}
   192  			continue
   193  		}
   194  
   195  		j := strings.Index(data, ":")
   196  		key := base.ParseInternalKey(data[:j])
   197  		value := []byte(data[j+1:])
   198  		switch key.Kind() {
   199  		case base.InternalKeyKindRangeKeyDelete,
   200  			base.InternalKeyKindRangeKeyUnset,
   201  			base.InternalKeyKindRangeKeySet:
   202  			if err := w.AddRangeKey(key, value); err != nil {
   203  				return nil, nil, err
   204  			}
   205  		default:
   206  			if err := w.Add(key, value); err != nil {
   207  				return nil, nil, err
   208  			}
   209  		}
   210  	}
   211  	if err := w.Close(); err != nil {
   212  		return nil, nil, err
   213  	}
   214  	meta, err := w.Metadata()
   215  	if err != nil {
   216  		return nil, nil, err
   217  	}
   218  
   219  	f1, err := mem.Open("test")
   220  	if err != nil {
   221  		return nil, nil, err
   222  	}
   223  	r, err := NewReader(f1, ReaderOptions{})
   224  	if err != nil {
   225  		return nil, nil, err
   226  	}
   227  	return meta, r, nil
   228  }
   229  
   230  func scanGlobalSeqNum(td *datadriven.TestData) (uint64, error) {
   231  	for _, arg := range td.CmdArgs {
   232  		switch arg.Key {
   233  		case "globalSeqNum":
   234  			if len(arg.Vals) != 1 {
   235  				return 0, errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key)
   236  			}
   237  			v, err := strconv.Atoi(arg.Vals[0])
   238  			if err != nil {
   239  				return 0, err
   240  			}
   241  			return uint64(v), nil
   242  		}
   243  	}
   244  	return 0, nil
   245  }
   246  
   247  type runIterCmdOption func(*runIterCmdOptions)
   248  
   249  type runIterCmdOptions struct {
   250  	everyOp      func(io.Writer)
   251  	everyOpAfter func(io.Writer)
   252  	stats        *base.InternalIteratorStats
   253  }
   254  
   255  func runIterCmdEveryOp(everyOp func(io.Writer)) runIterCmdOption {
   256  	return func(opts *runIterCmdOptions) { opts.everyOp = everyOp }
   257  }
   258  
   259  func runIterCmdEveryOpAfter(everyOp func(io.Writer)) runIterCmdOption {
   260  	return func(opts *runIterCmdOptions) { opts.everyOpAfter = everyOp }
   261  }
   262  
   263  func runIterCmdStats(stats *base.InternalIteratorStats) runIterCmdOption {
   264  	return func(opts *runIterCmdOptions) { opts.stats = stats }
   265  }
   266  
   267  func runIterCmd(td *datadriven.TestData, origIter Iterator, opt ...runIterCmdOption) string {
   268  	var opts runIterCmdOptions
   269  	for _, o := range opt {
   270  		o(&opts)
   271  	}
   272  
   273  	iter := newIterAdapter(origIter)
   274  	defer iter.Close()
   275  
   276  	var b bytes.Buffer
   277  	var prefix []byte
   278  	for _, line := range strings.Split(td.Input, "\n") {
   279  		parts := strings.Fields(line)
   280  		if len(parts) == 0 {
   281  			continue
   282  		}
   283  		switch parts[0] {
   284  		case "seek-ge":
   285  			if len(parts) < 2 || len(parts) > 3 {
   286  				return "seek-ge <key> [<try-seek-using-next]\n"
   287  			}
   288  			prefix = nil
   289  			var flags base.SeekGEFlags
   290  			if len(parts) == 3 {
   291  				if trySeekUsingNext, err := strconv.ParseBool(parts[2]); err != nil {
   292  					return err.Error()
   293  				} else if trySeekUsingNext {
   294  					flags = flags.EnableTrySeekUsingNext()
   295  				}
   296  			}
   297  			iter.SeekGE([]byte(strings.TrimSpace(parts[1])), flags)
   298  		case "seek-prefix-ge":
   299  			if len(parts) != 2 && len(parts) != 3 {
   300  				return "seek-prefix-ge <key> [<try-seek-using-next>]\n"
   301  			}
   302  			prefix = []byte(strings.TrimSpace(parts[1]))
   303  			var flags base.SeekGEFlags
   304  			if len(parts) == 3 {
   305  				if trySeekUsingNext, err := strconv.ParseBool(parts[2]); err != nil {
   306  					return err.Error()
   307  				} else if trySeekUsingNext {
   308  					flags = flags.EnableTrySeekUsingNext()
   309  				}
   310  			}
   311  			iter.SeekPrefixGE(prefix, prefix /* key */, flags)
   312  		case "seek-lt":
   313  			if len(parts) != 2 {
   314  				return "seek-lt <key>\n"
   315  			}
   316  			prefix = nil
   317  			iter.SeekLT([]byte(strings.TrimSpace(parts[1])), base.SeekLTFlagsNone)
   318  		case "first":
   319  			prefix = nil
   320  			iter.First()
   321  		case "last":
   322  			prefix = nil
   323  			iter.Last()
   324  		case "next":
   325  			iter.Next()
   326  		case "next-ignore-result":
   327  			iter.NextIgnoreResult()
   328  		case "prev":
   329  			iter.Prev()
   330  		case "set-bounds":
   331  			if len(parts) <= 1 || len(parts) > 3 {
   332  				return "set-bounds lower=<lower> upper=<upper>\n"
   333  			}
   334  			var lower []byte
   335  			var upper []byte
   336  			for _, part := range parts[1:] {
   337  				arg := strings.Split(strings.TrimSpace(part), "=")
   338  				switch arg[0] {
   339  				case "lower":
   340  					lower = []byte(arg[1])
   341  					if len(lower) == 0 {
   342  						lower = nil
   343  					}
   344  				case "upper":
   345  					upper = []byte(arg[1])
   346  					if len(upper) == 0 {
   347  						upper = nil
   348  					}
   349  				default:
   350  					return fmt.Sprintf("set-bounds: unknown arg: %s", arg)
   351  				}
   352  			}
   353  			iter.SetBounds(lower, upper)
   354  		case "stats":
   355  			fmt.Fprintf(&b, "%+v\n", *opts.stats)
   356  			continue
   357  		case "reset-stats":
   358  			*opts.stats = base.InternalIteratorStats{}
   359  			continue
   360  		}
   361  		if opts.everyOp != nil {
   362  			opts.everyOp(&b)
   363  		}
   364  		if iter.Valid() && checkValidPrefix(prefix, iter.Key().UserKey) {
   365  			fmt.Fprintf(&b, "<%s:%d>", iter.Key().UserKey, iter.Key().SeqNum())
   366  		} else if err := iter.Error(); err != nil {
   367  			fmt.Fprintf(&b, "<err=%v>", err)
   368  		} else {
   369  			fmt.Fprintf(&b, ".")
   370  		}
   371  		if opts.everyOpAfter != nil {
   372  			opts.everyOpAfter(&b)
   373  		}
   374  		b.WriteString("\n")
   375  	}
   376  	return b.String()
   377  }
   378  
   379  func runRewriteCmd(
   380  	td *datadriven.TestData, r *Reader, writerOpts WriterOptions,
   381  ) (*WriterMetadata, *Reader, error) {
   382  	var from, to []byte
   383  	for _, arg := range td.CmdArgs {
   384  		switch arg.Key {
   385  		case "from":
   386  			from = []byte(arg.Vals[0])
   387  		case "to":
   388  			to = []byte(arg.Vals[0])
   389  		}
   390  	}
   391  	if from == nil || to == nil {
   392  		return nil, r, errors.New("missing from/to")
   393  	}
   394  
   395  	opts := writerOpts
   396  	if err := optsFromArgs(td, &opts); err != nil {
   397  		return nil, r, err
   398  	}
   399  
   400  	f := &memFile{}
   401  	meta, err := rewriteKeySuffixesInBlocks(r, f, opts, from, to, 2)
   402  	if err != nil {
   403  		return nil, r, errors.Wrap(err, "rewrite failed")
   404  	}
   405  	readerOpts := ReaderOptions{Comparer: opts.Comparer}
   406  	if opts.FilterPolicy != nil {
   407  		readerOpts.Filters = map[string]FilterPolicy{
   408  			opts.FilterPolicy.Name(): opts.FilterPolicy,
   409  		}
   410  	}
   411  	r.Close()
   412  
   413  	r, err = NewMemReader(f.Data(), readerOpts)
   414  	if err != nil {
   415  		return nil, nil, err
   416  	}
   417  	return meta, r, nil
   418  }