github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/keyspan/iter_test.go (about)

     1  // Copyright 2018 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 keyspan
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/cockroachdb/datadriven"
    14  	"github.com/cockroachdb/pebble/internal/base"
    15  )
    16  
    17  func runFragmentIteratorCmd(iter FragmentIterator, input string, extraInfo func() string) string {
    18  	var b bytes.Buffer
    19  	for _, line := range strings.Split(input, "\n") {
    20  		parts := strings.Fields(line)
    21  		if len(parts) == 0 {
    22  			continue
    23  		}
    24  		var span *Span
    25  		switch parts[0] {
    26  		case "seek-ge":
    27  			if len(parts) != 2 {
    28  				return "seek-ge <key>\n"
    29  			}
    30  			span = iter.SeekGE([]byte(strings.TrimSpace(parts[1])))
    31  		case "seek-lt":
    32  			if len(parts) != 2 {
    33  				return "seek-lt <key>\n"
    34  			}
    35  			span = iter.SeekLT([]byte(strings.TrimSpace(parts[1])))
    36  		case "first":
    37  			span = iter.First()
    38  		case "last":
    39  			span = iter.Last()
    40  		case "next":
    41  			span = iter.Next()
    42  		case "prev":
    43  			span = iter.Prev()
    44  		default:
    45  			return fmt.Sprintf("unknown op: %s", parts[0])
    46  		}
    47  		if span != nil {
    48  			fmt.Fprintf(&b, "%s", span)
    49  			if extraInfo != nil {
    50  				fmt.Fprintf(&b, " (%s)", extraInfo())
    51  			}
    52  			b.WriteByte('\n')
    53  		} else if err := iter.Error(); err != nil {
    54  			fmt.Fprintf(&b, "err=%v\n", err)
    55  		} else {
    56  			fmt.Fprintf(&b, ".\n")
    57  		}
    58  	}
    59  	return b.String()
    60  }
    61  
    62  func TestIter(t *testing.T) {
    63  	var spans []Span
    64  	datadriven.RunTest(t, "testdata/iter", func(t *testing.T, d *datadriven.TestData) string {
    65  		switch d.Cmd {
    66  		case "define":
    67  			spans = nil
    68  			for _, line := range strings.Split(d.Input, "\n") {
    69  				spans = append(spans, ParseSpan(line))
    70  			}
    71  			return ""
    72  
    73  		case "iter":
    74  			iter := NewIter(base.DefaultComparer.Compare, spans)
    75  			defer iter.Close()
    76  			return runFragmentIteratorCmd(iter, d.Input, nil)
    77  		default:
    78  			return fmt.Sprintf("unknown command: %s", d.Cmd)
    79  		}
    80  	})
    81  }
    82  
    83  // invalidatingIter wraps a FragmentIterator and implements FragmentIterator
    84  // itself. Spans surfaced by the inner iterator are copied to buffers that are
    85  // zeroed by sbubsequent iterator positioning calls. This is intended to help
    86  // surface bugs in improper lifetime expectations of Spans.
    87  type invalidatingIter struct {
    88  	iter FragmentIterator
    89  	bufs [][]byte
    90  	keys []Key
    91  	span Span
    92  }
    93  
    94  // invalidatingIter implements FragmentIterator.
    95  var _ FragmentIterator = (*invalidatingIter)(nil)
    96  
    97  func (i *invalidatingIter) invalidate(s *Span) *Span {
    98  	// Zero the entirety of the byte bufs and the keys slice.
    99  	for j := range i.bufs {
   100  		for k := range i.bufs[j] {
   101  			i.bufs[j][k] = 0x00
   102  		}
   103  		i.bufs[j] = nil
   104  	}
   105  	for j := range i.keys {
   106  		i.keys[j] = Key{}
   107  	}
   108  	if s == nil {
   109  		return nil
   110  	}
   111  
   112  	// Copy all of the span's slices into slices owned by the invalidating iter
   113  	// that we can invalidate on a subsequent positioning method.
   114  	i.bufs = i.bufs[:0]
   115  	i.keys = i.keys[:0]
   116  	i.span = Span{
   117  		Start: i.saveBytes(s.Start),
   118  		End:   i.saveBytes(s.End),
   119  	}
   120  	for j := range s.Keys {
   121  		i.keys = append(i.keys, Key{
   122  			Trailer: s.Keys[j].Trailer,
   123  			Suffix:  i.saveBytes(s.Keys[j].Suffix),
   124  			Value:   i.saveBytes(s.Keys[j].Value),
   125  		})
   126  	}
   127  	i.span.Keys = i.keys
   128  	return &i.span
   129  }
   130  
   131  func (i *invalidatingIter) saveBytes(b []byte) []byte {
   132  	if b == nil {
   133  		return nil
   134  	}
   135  	saved := append([]byte(nil), b...)
   136  	i.bufs = append(i.bufs, saved)
   137  	return saved
   138  }
   139  
   140  func (i *invalidatingIter) SeekGE(key []byte) *Span { return i.invalidate(i.iter.SeekGE(key)) }
   141  func (i *invalidatingIter) SeekLT(key []byte) *Span { return i.invalidate(i.iter.SeekLT(key)) }
   142  func (i *invalidatingIter) First() *Span            { return i.invalidate(i.iter.First()) }
   143  func (i *invalidatingIter) Last() *Span             { return i.invalidate(i.iter.Last()) }
   144  func (i *invalidatingIter) Next() *Span             { return i.invalidate(i.iter.Next()) }
   145  func (i *invalidatingIter) Prev() *Span             { return i.invalidate(i.iter.Prev()) }
   146  func (i *invalidatingIter) Close() error            { return i.iter.Close() }
   147  func (i *invalidatingIter) Error() error            { return i.iter.Error() }