github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/engine_test.go (about)

     1  // Copyright 2014 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package storage
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"encoding/binary"
    17  	"encoding/hex"
    18  	"fmt"
    19  	"io"
    20  	"math/rand"
    21  	"os"
    22  	"path/filepath"
    23  	"reflect"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/cockroachdb/cockroach/pkg/base"
    31  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    32  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    33  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    34  	"github.com/cockroachdb/cockroach/pkg/storage/fs"
    35  	"github.com/cockroachdb/cockroach/pkg/testutils"
    36  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    37  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    38  	"github.com/cockroachdb/cockroach/pkg/util/protoutil"
    39  	"github.com/cockroachdb/errors"
    40  	"github.com/cockroachdb/pebble"
    41  	"github.com/cockroachdb/pebble/vfs"
    42  	"github.com/stretchr/testify/assert"
    43  	"github.com/stretchr/testify/require"
    44  )
    45  
    46  func ensureRangeEqual(
    47  	t *testing.T, sortedKeys []string, keyMap map[string][]byte, keyvals []MVCCKeyValue,
    48  ) {
    49  	t.Helper()
    50  	if len(keyvals) != len(sortedKeys) {
    51  		t.Errorf("length mismatch. expected %s, got %s", sortedKeys, keyvals)
    52  	}
    53  	for i, kv := range keyvals {
    54  		if sortedKeys[i] != string(kv.Key.Key) {
    55  			t.Errorf("key mismatch at index %d: expected %q, got %q", i, sortedKeys[i], kv.Key)
    56  		}
    57  		if !bytes.Equal(keyMap[sortedKeys[i]], kv.Value) {
    58  			t.Errorf("value mismatch at index %d: expected %q, got %q", i, keyMap[sortedKeys[i]], kv.Value)
    59  		}
    60  	}
    61  }
    62  
    63  // TestEngineBatchCommit writes a batch containing 10K rows (all the
    64  // same key) and concurrently attempts to read the value in a tight
    65  // loop. The test verifies that either there is no value for the key
    66  // or it contains the final value, but never a value in between.
    67  func TestEngineBatchCommit(t *testing.T) {
    68  	defer leaktest.AfterTest(t)()
    69  	numWrites := 10000
    70  	key := mvccKey("a")
    71  	finalVal := []byte(strconv.Itoa(numWrites - 1))
    72  
    73  	for _, engineImpl := range mvccEngineImpls {
    74  		t.Run(engineImpl.name, func(t *testing.T) {
    75  			e := engineImpl.create()
    76  			defer e.Close()
    77  
    78  			// Start a concurrent read operation in a busy loop.
    79  			readsBegun := make(chan struct{})
    80  			readsDone := make(chan error)
    81  			writesDone := make(chan struct{})
    82  			go func() {
    83  				readsDone <- func() error {
    84  					readsBegunAlias := readsBegun
    85  					for {
    86  						select {
    87  						case <-writesDone:
    88  							return nil
    89  						default:
    90  							val, err := e.Get(key)
    91  							if err != nil {
    92  								return err
    93  							}
    94  							if val != nil && !bytes.Equal(val, finalVal) {
    95  								return errors.Errorf("key value should be empty or %q; got %q", string(finalVal), string(val))
    96  							}
    97  							if readsBegunAlias != nil {
    98  								close(readsBegunAlias)
    99  								readsBegunAlias = nil
   100  							}
   101  						}
   102  					}
   103  				}()
   104  			}()
   105  			// Wait until we've succeeded with first read.
   106  			<-readsBegun
   107  
   108  			// Create key/values and put them in a batch to engine.
   109  			batch := e.NewBatch()
   110  			defer batch.Close()
   111  			for i := 0; i < numWrites; i++ {
   112  				if err := batch.Put(key, []byte(strconv.Itoa(i))); err != nil {
   113  					t.Fatal(err)
   114  				}
   115  			}
   116  			if err := batch.Commit(false /* sync */); err != nil {
   117  				t.Fatal(err)
   118  			}
   119  			close(writesDone)
   120  			if err := <-readsDone; err != nil {
   121  				t.Fatal(err)
   122  			}
   123  		})
   124  	}
   125  }
   126  
   127  func TestEngineBatchStaleCachedIterator(t *testing.T) {
   128  	defer leaktest.AfterTest(t)()
   129  	// Prevent regression of a bug which caused spurious MVCC errors due to an
   130  	// invalid optimization which let an iterator return key-value pairs which
   131  	// had since been deleted from the underlying engine.
   132  	// Discovered in #6878.
   133  
   134  	for _, engineImpl := range mvccEngineImpls {
   135  		t.Run(engineImpl.name, func(t *testing.T) {
   136  			eng := engineImpl.create()
   137  			defer eng.Close()
   138  
   139  			// Focused failure mode: highlights the actual bug.
   140  			{
   141  				batch := eng.NewBatch()
   142  				defer batch.Close()
   143  				iter := batch.NewIterator(IterOptions{UpperBound: roachpb.KeyMax})
   144  				key := MVCCKey{Key: roachpb.Key("b")}
   145  
   146  				if err := batch.Put(key, []byte("foo")); err != nil {
   147  					t.Fatal(err)
   148  				}
   149  
   150  				iter.SeekGE(key)
   151  
   152  				if err := batch.Clear(key); err != nil {
   153  					t.Fatal(err)
   154  				}
   155  
   156  				// Iterator should not reuse its cached result.
   157  				iter.SeekGE(key)
   158  
   159  				if ok, err := iter.Valid(); err != nil {
   160  					t.Fatal(err)
   161  				} else if ok {
   162  					t.Fatalf("iterator unexpectedly valid: %v -> %v",
   163  						iter.UnsafeKey(), iter.UnsafeValue())
   164  				}
   165  
   166  				iter.Close()
   167  			}
   168  
   169  			// Higher-level failure mode. Mostly for documentation.
   170  			{
   171  				batch := eng.NewBatch()
   172  				defer batch.Close()
   173  
   174  				key := roachpb.Key("z")
   175  
   176  				// Put a value so that the deletion below finds a value to seek
   177  				// to.
   178  				if err := MVCCPut(context.Background(), batch, nil, key, hlc.Timestamp{},
   179  					roachpb.MakeValueFromString("x"), nil); err != nil {
   180  					t.Fatal(err)
   181  				}
   182  
   183  				// Seek the iterator to `key` and clear the value (but without
   184  				// telling the iterator about that).
   185  				if err := MVCCDelete(context.Background(), batch, nil, key,
   186  					hlc.Timestamp{}, nil); err != nil {
   187  					t.Fatal(err)
   188  				}
   189  
   190  				// Trigger a seek on the cached iterator by seeking to the (now
   191  				// absent) key.
   192  				// The underlying iterator will already be in the right position
   193  				// due to a seek in MVCCDelete (followed by a Clear, which does not
   194  				// invalidate the iterator's cache), and if it reports its cached
   195  				// result back, we'll see the (newly deleted) value (due to the
   196  				// failure mode above).
   197  				if v, _, err := MVCCGet(context.Background(), batch, key,
   198  					hlc.Timestamp{}, MVCCGetOptions{}); err != nil {
   199  					t.Fatal(err)
   200  				} else if v != nil {
   201  					t.Fatalf("expected no value, got %+v", v)
   202  				}
   203  			}
   204  		})
   205  	}
   206  }
   207  
   208  func TestEngineBatch(t *testing.T) {
   209  	defer leaktest.AfterTest(t)()
   210  
   211  	for _, engineImpl := range mvccEngineImpls {
   212  		t.Run(engineImpl.name, func(t *testing.T) {
   213  			engine := engineImpl.create()
   214  			defer engine.Close()
   215  
   216  			numShuffles := 100
   217  			key := mvccKey("a")
   218  			// Those are randomized below.
   219  			type data struct {
   220  				key   MVCCKey
   221  				value []byte
   222  				merge bool
   223  			}
   224  			batch := []data{
   225  				{key, appender("~ockroachDB"), false},
   226  				{key, appender("C~ckroachDB"), false},
   227  				{key, appender("Co~kroachDB"), false},
   228  				{key, appender("Coc~roachDB"), false},
   229  				{key, appender("Cock~oachDB"), false},
   230  				{key, appender("Cockr~achDB"), false},
   231  				{key, appender("Cockro~chDB"), false},
   232  				{key, appender("Cockroa~hDB"), false},
   233  				{key, appender("Cockroac~DB"), false},
   234  				{key, appender("Cockroach~B"), false},
   235  				{key, appender("CockroachD~"), false},
   236  				{key, nil, false},
   237  				{key, appender("C"), true},
   238  				{key, appender(" o"), true},
   239  				{key, appender("  c"), true},
   240  				{key, appender(" k"), true},
   241  				{key, appender("r"), true},
   242  				{key, appender(" o"), true},
   243  				{key, appender("  a"), true},
   244  				{key, appender(" c"), true},
   245  				{key, appender("h"), true},
   246  				{key, appender(" D"), true},
   247  				{key, appender("  B"), true},
   248  			}
   249  
   250  			apply := func(rw ReadWriter, d data) error {
   251  				if d.value == nil {
   252  					return rw.Clear(d.key)
   253  				} else if d.merge {
   254  					return rw.Merge(d.key, d.value)
   255  				}
   256  				return rw.Put(d.key, d.value)
   257  			}
   258  
   259  			get := func(rw ReadWriter, key MVCCKey) []byte {
   260  				b, err := rw.Get(key)
   261  				if err != nil {
   262  					t.Fatal(err)
   263  				}
   264  				var m enginepb.MVCCMetadata
   265  				if err := protoutil.Unmarshal(b, &m); err != nil {
   266  					t.Fatal(err)
   267  				}
   268  				if !m.IsInline() {
   269  					return nil
   270  				}
   271  				valueBytes, err := MakeValue(m).GetBytes()
   272  				if err != nil {
   273  					t.Fatal(err)
   274  				}
   275  				return valueBytes
   276  			}
   277  
   278  			for i := 0; i < numShuffles; i++ {
   279  				// In each run, create an array of shuffled operations.
   280  				shuffledIndices := rand.Perm(len(batch))
   281  				currentBatch := make([]data, len(batch))
   282  				for k := range currentBatch {
   283  					currentBatch[k] = batch[shuffledIndices[k]]
   284  				}
   285  				// Reset the key
   286  				if err := engine.Clear(key); err != nil {
   287  					t.Fatal(err)
   288  				}
   289  				// Run it once with individual operations and remember the result.
   290  				for i, op := range currentBatch {
   291  					if err := apply(engine, op); err != nil {
   292  						t.Errorf("%d: op %v: %+v", i, op, err)
   293  						continue
   294  					}
   295  				}
   296  				expectedValue := get(engine, key)
   297  				// Run the whole thing as a batch and compare.
   298  				b := engine.NewBatch()
   299  				defer b.Close()
   300  				if err := b.Clear(key); err != nil {
   301  					t.Fatal(err)
   302  				}
   303  				for _, op := range currentBatch {
   304  					if err := apply(b, op); err != nil {
   305  						t.Fatal(err)
   306  					}
   307  				}
   308  				// Try getting the value from the batch.
   309  				actualValue := get(b, key)
   310  				if !bytes.Equal(actualValue, expectedValue) {
   311  					t.Errorf("%d: expected %s, but got %s", i, expectedValue, actualValue)
   312  				}
   313  				// Try using an iterator to get the value from the batch.
   314  				iter := b.NewIterator(IterOptions{UpperBound: roachpb.KeyMax})
   315  				iter.SeekGE(key)
   316  				if ok, err := iter.Valid(); !ok {
   317  					if currentBatch[len(currentBatch)-1].value != nil {
   318  						t.Errorf("%d: batch seek invalid, err=%v", i, err)
   319  					}
   320  				} else if !iter.Key().Equal(key) {
   321  					t.Errorf("%d: batch seek expected key %s, but got %s", i, key, iter.Key())
   322  				} else {
   323  					var m enginepb.MVCCMetadata
   324  					if err := iter.ValueProto(&m); err != nil {
   325  						t.Fatal(err)
   326  					}
   327  					valueBytes, err := MakeValue(m).GetBytes()
   328  					if err != nil {
   329  						t.Fatal(err)
   330  					}
   331  					if !bytes.Equal(valueBytes, expectedValue) {
   332  						t.Errorf("%d: expected %s, but got %s", i, expectedValue, valueBytes)
   333  					}
   334  				}
   335  				iter.Close()
   336  				// Commit the batch and try getting the value from the engine.
   337  				if err := b.Commit(false /* sync */); err != nil {
   338  					t.Errorf("%d: %+v", i, err)
   339  					continue
   340  				}
   341  				actualValue = get(engine, key)
   342  				if !bytes.Equal(actualValue, expectedValue) {
   343  					t.Errorf("%d: expected %s, but got %s", i, expectedValue, actualValue)
   344  				}
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func TestEnginePutGetDelete(t *testing.T) {
   351  	defer leaktest.AfterTest(t)()
   352  
   353  	for _, engineImpl := range mvccEngineImpls {
   354  		t.Run(engineImpl.name, func(t *testing.T) {
   355  			engine := engineImpl.create()
   356  			defer engine.Close()
   357  
   358  			// Test for correct handling of empty keys, which should produce errors.
   359  			for i, err := range []error{
   360  				engine.Put(mvccKey(""), []byte("")),
   361  				engine.Put(NilKey, []byte("")),
   362  				func() error {
   363  					_, err := engine.Get(mvccKey(""))
   364  					return err
   365  				}(),
   366  				engine.Clear(NilKey),
   367  				func() error {
   368  					_, err := engine.Get(NilKey)
   369  					return err
   370  				}(),
   371  				engine.Clear(NilKey),
   372  				engine.Clear(mvccKey("")),
   373  			} {
   374  				if err == nil {
   375  					t.Fatalf("%d: illegal handling of empty key", i)
   376  				}
   377  			}
   378  
   379  			// Test for allowed keys, which should go through.
   380  			testCases := []struct {
   381  				key   MVCCKey
   382  				value []byte
   383  			}{
   384  				{mvccKey("dog"), []byte("woof")},
   385  				{mvccKey("cat"), []byte("meow")},
   386  				{mvccKey("emptyval"), nil},
   387  				{mvccKey("emptyval2"), []byte("")},
   388  				{mvccKey("server"), []byte("42")},
   389  			}
   390  			for _, c := range testCases {
   391  				val, err := engine.Get(c.key)
   392  				if err != nil {
   393  					t.Errorf("get: expected no error, but got %s", err)
   394  				}
   395  				if len(val) != 0 {
   396  					t.Errorf("expected key %q value.Bytes to be nil: got %+v", c.key, val)
   397  				}
   398  				if err := engine.Put(c.key, c.value); err != nil {
   399  					t.Errorf("put: expected no error, but got %s", err)
   400  				}
   401  				val, err = engine.Get(c.key)
   402  				if err != nil {
   403  					t.Errorf("get: expected no error, but got %s", err)
   404  				}
   405  				if !bytes.Equal(val, c.value) {
   406  					t.Errorf("expected key value %s to be %+v: got %+v", c.key, c.value, val)
   407  				}
   408  				if err := engine.Clear(c.key); err != nil {
   409  					t.Errorf("delete: expected no error, but got %s", err)
   410  				}
   411  				val, err = engine.Get(c.key)
   412  				if err != nil {
   413  					t.Errorf("get: expected no error, but got %s", err)
   414  				}
   415  				if len(val) != 0 {
   416  					t.Errorf("expected key %s value.Bytes to be nil: got %+v", c.key, val)
   417  				}
   418  			}
   419  		})
   420  	}
   421  }
   422  
   423  func addMergeTimestamp(t *testing.T, data []byte, ts int64) []byte {
   424  	var v enginepb.MVCCMetadata
   425  	if err := protoutil.Unmarshal(data, &v); err != nil {
   426  		t.Fatal(err)
   427  	}
   428  	v.MergeTimestamp = &hlc.LegacyTimestamp{WallTime: ts}
   429  	return mustMarshal(&v)
   430  }
   431  
   432  // TestEngineMerge tests that the passing through of engine merge operations
   433  // to the goMerge function works as expected. The semantics are tested more
   434  // exhaustively in the merge tests themselves.
   435  func TestEngineMerge(t *testing.T) {
   436  	defer leaktest.AfterTest(t)()
   437  
   438  	engineBytes := make([][][]byte, len(mvccEngineImpls))
   439  	for engineIndex, engineImpl := range mvccEngineImpls {
   440  		t.Run(engineImpl.name, func(t *testing.T) {
   441  			engine := engineImpl.create()
   442  			defer engine.Close()
   443  
   444  			testcases := []struct {
   445  				testKey  MVCCKey
   446  				merges   [][]byte
   447  				expected []byte
   448  			}{
   449  				{
   450  					// Test case with RawBytes only.
   451  					mvccKey("haste not in life"),
   452  					[][]byte{
   453  						appender("x"),
   454  						appender("y"),
   455  						appender("z"),
   456  					},
   457  					appender("xyz"),
   458  				},
   459  				{
   460  					// Test case with RawBytes and MergeTimestamp.
   461  					mvccKey("timeseriesmerged"),
   462  					[][]byte{
   463  						addMergeTimestamp(t, timeSeriesRow(testtime, 1000, []tsSample{
   464  							{1, 1, 5, 5, 5},
   465  						}...), 27),
   466  						timeSeriesRow(testtime, 1000, []tsSample{
   467  							{2, 1, 5, 5, 5},
   468  							{1, 2, 10, 7, 3},
   469  						}...),
   470  						addMergeTimestamp(t, timeSeriesRow(testtime, 1000, []tsSample{
   471  							{10, 1, 5, 5, 5},
   472  						}...), 53),
   473  						timeSeriesRow(testtime, 1000, []tsSample{
   474  							{5, 1, 5, 5, 5},
   475  							{3, 1, 5, 5, 5},
   476  						}...),
   477  					},
   478  					addMergeTimestamp(t, timeSeriesRow(testtime, 1000, []tsSample{
   479  						{1, 2, 10, 7, 3},
   480  						{2, 1, 5, 5, 5},
   481  						{3, 1, 5, 5, 5},
   482  						{5, 1, 5, 5, 5},
   483  						{10, 1, 5, 5, 5},
   484  					}...), 27),
   485  				},
   486  			}
   487  			engineBytes[engineIndex] = make([][]byte, len(testcases))
   488  			for tcIndex, tc := range testcases {
   489  				for i, update := range tc.merges {
   490  					if err := engine.Merge(tc.testKey, update); err != nil {
   491  						t.Fatalf("%d: %+v", i, err)
   492  					}
   493  				}
   494  				result, _ := engine.Get(tc.testKey)
   495  				engineBytes[engineIndex][tcIndex] = result
   496  				var resultV, expectedV enginepb.MVCCMetadata
   497  				if err := protoutil.Unmarshal(result, &resultV); err != nil {
   498  					t.Fatal(err)
   499  				}
   500  				if err := protoutil.Unmarshal(tc.expected, &expectedV); err != nil {
   501  					t.Fatal(err)
   502  				}
   503  				if !reflect.DeepEqual(resultV, expectedV) {
   504  					t.Errorf("unexpected append-merge result: %v != %v", resultV, expectedV)
   505  				}
   506  			}
   507  		})
   508  	}
   509  	for i := 0; i < len(engineBytes); i++ {
   510  		// Pair-wise comparison of bytes since difference in serialization
   511  		// can trigger replica consistency checker failures #45811
   512  		if i+1 == len(engineBytes) {
   513  			break
   514  		}
   515  		eng1 := i
   516  		eng2 := i + 1
   517  		for j := 0; j < len(engineBytes[eng1]); j++ {
   518  			if !bytes.Equal(engineBytes[eng1][j], engineBytes[eng2][j]) {
   519  				t.Errorf("engines %d, %d differ at test %d:\n%s\n != \n%s\n", eng1, eng2, j,
   520  					hex.Dump(engineBytes[eng1][j]), hex.Dump(engineBytes[eng2][j]))
   521  			}
   522  		}
   523  	}
   524  }
   525  
   526  func TestEngineMustExist(t *testing.T) {
   527  	defer leaktest.AfterTest(t)()
   528  
   529  	test := func(engineType enginepb.EngineType, errStr string) {
   530  		tempDir, dirCleanupFn := testutils.TempDir(t)
   531  		defer dirCleanupFn()
   532  
   533  		_, err := NewEngine(
   534  			engineType,
   535  			0, base.StorageConfig{
   536  				Dir:       tempDir,
   537  				MustExist: true,
   538  			})
   539  		if err == nil {
   540  			t.Fatal("expected error related to missing directory")
   541  		}
   542  		if !strings.Contains(fmt.Sprint(err), errStr) {
   543  			t.Fatal(err)
   544  		}
   545  	}
   546  
   547  	test(enginepb.EngineTypeRocksDB, "does not exist (create_if_missing is false)")
   548  	test(enginepb.EngineTypePebble, "no such file or directory")
   549  }
   550  
   551  func TestEngineTimeBound(t *testing.T) {
   552  	defer leaktest.AfterTest(t)()
   553  
   554  	for _, engineImpl := range mvccEngineImpls {
   555  		t.Run(engineImpl.name, func(t *testing.T) {
   556  			engine := engineImpl.create()
   557  			defer engine.Close()
   558  
   559  			var minTimestamp = hlc.Timestamp{WallTime: 1, Logical: 0}
   560  			var maxTimestamp = hlc.Timestamp{WallTime: 3, Logical: 0}
   561  			times := []hlc.Timestamp{
   562  				{WallTime: 2, Logical: 0},
   563  				minTimestamp,
   564  				maxTimestamp,
   565  				{WallTime: 2, Logical: 0},
   566  			}
   567  
   568  			for i, time := range times {
   569  				s := fmt.Sprintf("%02d", i)
   570  				key := MVCCKey{Key: roachpb.Key(s), Timestamp: time}
   571  				if err := engine.Put(key, []byte(s)); err != nil {
   572  					t.Fatal(err)
   573  				}
   574  			}
   575  			if err := engine.Flush(); err != nil {
   576  				t.Fatal(err)
   577  			}
   578  
   579  			batch := engine.NewBatch()
   580  			defer batch.Close()
   581  
   582  			check := func(t *testing.T, tbi Iterator, keys, ssts int) {
   583  				defer tbi.Close()
   584  				tbi.SeekGE(NilKey)
   585  
   586  				var count int
   587  				for ; ; tbi.Next() {
   588  					ok, err := tbi.Valid()
   589  					if err != nil {
   590  						t.Fatal(err)
   591  					}
   592  					if !ok {
   593  						break
   594  					}
   595  					count++
   596  				}
   597  
   598  				// Make sure the iterator sees no writes.
   599  				if keys != count {
   600  					t.Fatalf("saw %d values in time bounded iterator, but expected %d", count, keys)
   601  				}
   602  				stats := tbi.Stats()
   603  				if a := stats.TimeBoundNumSSTs; a != ssts {
   604  					t.Fatalf("touched %d SSTs, expected %d", a, ssts)
   605  				}
   606  			}
   607  
   608  			testCases := []struct {
   609  				iter       Iterator
   610  				keys, ssts int
   611  			}{
   612  				// Completely to the right, not touching.
   613  				{
   614  					iter: batch.NewIterator(IterOptions{
   615  						MinTimestampHint: maxTimestamp.Next(),
   616  						MaxTimestampHint: maxTimestamp.Next().Next(),
   617  						UpperBound:       roachpb.KeyMax,
   618  						WithStats:        true,
   619  					}),
   620  					keys: 0,
   621  					ssts: 0,
   622  				},
   623  				// Completely to the left, not touching.
   624  				{
   625  					iter: batch.NewIterator(IterOptions{
   626  						MinTimestampHint: minTimestamp.Prev().Prev(),
   627  						MaxTimestampHint: minTimestamp.Prev(),
   628  						UpperBound:       roachpb.KeyMax,
   629  						WithStats:        true,
   630  					}),
   631  					keys: 0,
   632  					ssts: 0,
   633  				},
   634  				// Touching on the right.
   635  				{
   636  					iter: batch.NewIterator(IterOptions{
   637  						MinTimestampHint: maxTimestamp,
   638  						MaxTimestampHint: maxTimestamp,
   639  						UpperBound:       roachpb.KeyMax,
   640  						WithStats:        true,
   641  					}),
   642  					keys: len(times),
   643  					ssts: 1,
   644  				},
   645  				// Touching on the left.
   646  				{
   647  					iter: batch.NewIterator(IterOptions{
   648  						MinTimestampHint: minTimestamp,
   649  						MaxTimestampHint: minTimestamp,
   650  						UpperBound:       roachpb.KeyMax,
   651  						WithStats:        true,
   652  					}),
   653  					keys: len(times),
   654  					ssts: 1,
   655  				},
   656  				// Copy of last case, but confirm that we don't get SST stats if we don't
   657  				// ask for them.
   658  				{
   659  					iter: batch.NewIterator(IterOptions{
   660  						MinTimestampHint: minTimestamp,
   661  						MaxTimestampHint: minTimestamp,
   662  						UpperBound:       roachpb.KeyMax,
   663  						WithStats:        false,
   664  					}),
   665  					keys: len(times),
   666  					ssts: 0,
   667  				},
   668  				// Copy of last case, but confirm that upper bound is respected.
   669  				{
   670  					iter: batch.NewIterator(IterOptions{
   671  						MinTimestampHint: minTimestamp,
   672  						MaxTimestampHint: minTimestamp,
   673  						UpperBound:       []byte("02"),
   674  						WithStats:        false,
   675  					}),
   676  					keys: 2,
   677  					ssts: 0,
   678  				},
   679  			}
   680  
   681  			for _, test := range testCases {
   682  				t.Run("", func(t *testing.T) {
   683  					check(t, test.iter, test.keys, test.ssts)
   684  				})
   685  			}
   686  
   687  			// Make a regular iterator. Before #21721, this would accidentally pick up the
   688  			// time bounded iterator instead.
   689  			iter := batch.NewIterator(IterOptions{UpperBound: roachpb.KeyMax})
   690  			defer iter.Close()
   691  			iter.SeekGE(NilKey)
   692  
   693  			var count int
   694  			for ; ; iter.Next() {
   695  				ok, err := iter.Valid()
   696  				if err != nil {
   697  					t.Fatal(err)
   698  				}
   699  				if !ok {
   700  					break
   701  				}
   702  				count++
   703  			}
   704  
   705  			// Make sure the iterator sees the writes (i.e. it's not the time bounded iterator).
   706  			if expCount := len(times); expCount != count {
   707  				t.Fatalf("saw %d values in regular iterator, but expected %d", count, expCount)
   708  			}
   709  		})
   710  	}
   711  }
   712  
   713  func TestFlushWithSSTables(t *testing.T) {
   714  	defer leaktest.AfterTest(t)()
   715  
   716  	for _, engineImpl := range mvccEngineImpls {
   717  		t.Run(engineImpl.name, func(t *testing.T) {
   718  			engine := engineImpl.create()
   719  			defer engine.Close()
   720  
   721  			batch := engine.NewBatch()
   722  			for i := 0; i < 10000; i++ {
   723  				key := make([]byte, 4)
   724  				binary.BigEndian.PutUint32(key, uint32(i))
   725  				err := batch.Put(MVCCKey{Key: key}, []byte("foobar"))
   726  				if err != nil {
   727  					t.Fatal(err)
   728  				}
   729  			}
   730  
   731  			err := batch.Commit(true)
   732  			if err != nil {
   733  				t.Fatal(err)
   734  			}
   735  			batch.Close()
   736  
   737  			err = engine.Flush()
   738  			if err != nil {
   739  				t.Fatal(err)
   740  			}
   741  
   742  			ssts := engine.GetSSTables()
   743  			if len(ssts) == 0 {
   744  				t.Fatal("expected non-zero sstables, got 0")
   745  			}
   746  		})
   747  	}
   748  }
   749  
   750  func TestEngineScan1(t *testing.T) {
   751  	defer leaktest.AfterTest(t)()
   752  
   753  	for _, engineImpl := range mvccEngineImpls {
   754  		t.Run(engineImpl.name, func(t *testing.T) {
   755  			engine := engineImpl.create()
   756  			defer engine.Close()
   757  
   758  			testCases := []struct {
   759  				key   MVCCKey
   760  				value []byte
   761  			}{
   762  				{mvccKey("dog"), []byte("woof")},
   763  				{mvccKey("cat"), []byte("meow")},
   764  				{mvccKey("server"), []byte("42")},
   765  				{mvccKey("french"), []byte("Allô?")},
   766  				{mvccKey("german"), []byte("hallo")},
   767  				{mvccKey("chinese"), []byte("你好")},
   768  			}
   769  			keyMap := map[string][]byte{}
   770  			for _, c := range testCases {
   771  				if err := engine.Put(c.key, c.value); err != nil {
   772  					t.Errorf("could not put key %q: %+v", c.key, err)
   773  				}
   774  				keyMap[string(c.key.Key)] = c.value
   775  			}
   776  			sortedKeys := make([]string, len(testCases))
   777  			for i, t := range testCases {
   778  				sortedKeys[i] = string(t.key.Key)
   779  			}
   780  			sort.Strings(sortedKeys)
   781  
   782  			keyvals, err := Scan(engine, roachpb.Key("chinese"), roachpb.Key("german"), 0)
   783  			if err != nil {
   784  				t.Fatalf("could not run scan: %+v", err)
   785  			}
   786  			ensureRangeEqual(t, sortedKeys[1:4], keyMap, keyvals)
   787  
   788  			// Check an end of range which does not equal an existing key.
   789  			keyvals, err = Scan(engine, roachpb.Key("chinese"), roachpb.Key("german1"), 0)
   790  			if err != nil {
   791  				t.Fatalf("could not run scan: %+v", err)
   792  			}
   793  			ensureRangeEqual(t, sortedKeys[1:5], keyMap, keyvals)
   794  
   795  			keyvals, err = Scan(engine, roachpb.Key("chinese"), roachpb.Key("german"), 2)
   796  			if err != nil {
   797  				t.Fatalf("could not run scan: %+v", err)
   798  			}
   799  			ensureRangeEqual(t, sortedKeys[1:3], keyMap, keyvals)
   800  
   801  			// Should return all key/value pairs in lexicographic order. Note that ""
   802  			// is the lowest key possible and is a special case in engine.scan, that's
   803  			// why we test it here.
   804  			startKeys := []roachpb.Key{roachpb.Key("cat"), roachpb.Key("")}
   805  			for _, startKey := range startKeys {
   806  				keyvals, err = Scan(engine, startKey, roachpb.KeyMax, 0)
   807  				if err != nil {
   808  					t.Fatalf("could not run scan: %+v", err)
   809  				}
   810  				ensureRangeEqual(t, sortedKeys, keyMap, keyvals)
   811  			}
   812  		})
   813  	}
   814  }
   815  
   816  func verifyScan(start, end roachpb.Key, max int64, expKeys []MVCCKey, engine Engine, t *testing.T) {
   817  	kvs, err := Scan(engine, start, end, max)
   818  	if err != nil {
   819  		t.Errorf("scan %q-%q: expected no error, but got %s", start, end, err)
   820  	}
   821  	if len(kvs) != len(expKeys) {
   822  		t.Errorf("scan %q-%q: expected scanned keys mismatch %d != %d: %v",
   823  			start, end, len(kvs), len(expKeys), kvs)
   824  	}
   825  	for i, kv := range kvs {
   826  		if !kv.Key.Equal(expKeys[i]) {
   827  			t.Errorf("scan %q-%q: expected keys equal %q != %q", start, end, kv.Key, expKeys[i])
   828  		}
   829  	}
   830  }
   831  
   832  func TestEngineScan2(t *testing.T) {
   833  	defer leaktest.AfterTest(t)()
   834  	// TODO(Tobias): Merge this with TestEngineScan1 and remove
   835  	// either verifyScan or the other helper function.
   836  
   837  	for _, engineImpl := range mvccEngineImpls {
   838  		t.Run(engineImpl.name, func(t *testing.T) {
   839  			engine := engineImpl.create()
   840  			defer engine.Close()
   841  
   842  			keys := []MVCCKey{
   843  				mvccKey("a"),
   844  				mvccKey("aa"),
   845  				mvccKey("aaa"),
   846  				mvccKey("ab"),
   847  				mvccKey("abc"),
   848  				mvccKey(roachpb.RKeyMax),
   849  			}
   850  
   851  			insertKeys(keys, engine, t)
   852  
   853  			// Scan all keys (non-inclusive of final key).
   854  			verifyScan(roachpb.KeyMin, roachpb.KeyMax, 10, keys[:5], engine, t)
   855  			verifyScan(roachpb.Key("a"), roachpb.KeyMax, 10, keys[:5], engine, t)
   856  
   857  			// Scan sub range.
   858  			verifyScan(roachpb.Key("aab"), roachpb.Key("abcc"), 10, keys[3:5], engine, t)
   859  			verifyScan(roachpb.Key("aa0"), roachpb.Key("abcc"), 10, keys[2:5], engine, t)
   860  
   861  			// Scan with max values.
   862  			verifyScan(roachpb.KeyMin, roachpb.KeyMax, 3, keys[:3], engine, t)
   863  			verifyScan(roachpb.Key("a0"), roachpb.KeyMax, 3, keys[1:4], engine, t)
   864  
   865  			// Scan with max value 0 gets all values.
   866  			verifyScan(roachpb.KeyMin, roachpb.KeyMax, 0, keys[:5], engine, t)
   867  		})
   868  	}
   869  }
   870  
   871  func testEngineDeleteRange(t *testing.T, clearRange func(engine Engine, start, end MVCCKey) error) {
   872  	for _, engineImpl := range mvccEngineImpls {
   873  		t.Run(engineImpl.name, func(t *testing.T) {
   874  			engine := engineImpl.create()
   875  			defer engine.Close()
   876  
   877  			keys := []MVCCKey{
   878  				mvccKey("a"),
   879  				mvccKey("aa"),
   880  				mvccKey("aaa"),
   881  				mvccKey("ab"),
   882  				mvccKey("abc"),
   883  				mvccKey(roachpb.RKeyMax),
   884  			}
   885  
   886  			insertKeys(keys, engine, t)
   887  
   888  			// Scan all keys (non-inclusive of final key).
   889  			verifyScan(roachpb.KeyMin, roachpb.KeyMax, 10, keys[:5], engine, t)
   890  
   891  			// Delete a range of keys
   892  			if err := clearRange(engine, mvccKey("aa"), mvccKey("abc")); err != nil {
   893  				t.Fatal(err)
   894  			}
   895  			// Verify what's left
   896  			verifyScan(roachpb.KeyMin, roachpb.KeyMax, 10,
   897  				[]MVCCKey{mvccKey("a"), mvccKey("abc")}, engine, t)
   898  		})
   899  	}
   900  }
   901  
   902  func TestEngineDeleteRange(t *testing.T) {
   903  	defer leaktest.AfterTest(t)()
   904  	testEngineDeleteRange(t, func(engine Engine, start, end MVCCKey) error {
   905  		return engine.ClearRange(start, end)
   906  	})
   907  }
   908  
   909  func TestEngineDeleteRangeBatch(t *testing.T) {
   910  	defer leaktest.AfterTest(t)()
   911  	testEngineDeleteRange(t, func(engine Engine, start, end MVCCKey) error {
   912  		batch := engine.NewWriteOnlyBatch()
   913  		defer batch.Close()
   914  		if err := batch.ClearRange(start, end); err != nil {
   915  			return err
   916  		}
   917  		batch2 := engine.NewWriteOnlyBatch()
   918  		defer batch2.Close()
   919  		if err := batch2.ApplyBatchRepr(batch.Repr(), false); err != nil {
   920  			return err
   921  		}
   922  		return batch2.Commit(false)
   923  	})
   924  }
   925  
   926  func TestEngineDeleteIterRange(t *testing.T) {
   927  	defer leaktest.AfterTest(t)()
   928  	testEngineDeleteRange(t, func(engine Engine, start, end MVCCKey) error {
   929  		iter := engine.NewIterator(IterOptions{UpperBound: roachpb.KeyMax})
   930  		defer iter.Close()
   931  		return engine.ClearIterRange(iter, start.Key, end.Key)
   932  	})
   933  }
   934  
   935  func TestSnapshot(t *testing.T) {
   936  	defer leaktest.AfterTest(t)()
   937  
   938  	for _, engineImpl := range mvccEngineImpls {
   939  		t.Run(engineImpl.name, func(t *testing.T) {
   940  			engine := engineImpl.create()
   941  			defer engine.Close()
   942  
   943  			key := mvccKey("a")
   944  			val1 := []byte("1")
   945  			if err := engine.Put(key, val1); err != nil {
   946  				t.Fatal(err)
   947  			}
   948  			val, _ := engine.Get(key)
   949  			if !bytes.Equal(val, val1) {
   950  				t.Fatalf("the value %s in get result does not match the value %s in request",
   951  					val, val1)
   952  			}
   953  
   954  			snap := engine.NewSnapshot()
   955  			defer snap.Close()
   956  
   957  			val2 := []byte("2")
   958  			if err := engine.Put(key, val2); err != nil {
   959  				t.Fatal(err)
   960  			}
   961  			val, _ = engine.Get(key)
   962  			valSnapshot, error := snap.Get(key)
   963  			if error != nil {
   964  				t.Fatalf("error : %s", error)
   965  			}
   966  			if !bytes.Equal(val, val2) {
   967  				t.Fatalf("the value %s in get result does not match the value %s in request",
   968  					val, val2)
   969  			}
   970  			if !bytes.Equal(valSnapshot, val1) {
   971  				t.Fatalf("the value %s in get result does not match the value %s in request",
   972  					valSnapshot, val1)
   973  			}
   974  
   975  			keyvals, _ := Scan(engine, key.Key, roachpb.KeyMax, 0)
   976  			keyvalsSnapshot, error := Scan(snap, key.Key, roachpb.KeyMax, 0)
   977  			if error != nil {
   978  				t.Fatalf("error : %s", error)
   979  			}
   980  			if len(keyvals) != 1 || !bytes.Equal(keyvals[0].Value, val2) {
   981  				t.Fatalf("the value %s in get result does not match the value %s in request",
   982  					keyvals[0].Value, val2)
   983  			}
   984  			if len(keyvalsSnapshot) != 1 || !bytes.Equal(keyvalsSnapshot[0].Value, val1) {
   985  				t.Fatalf("the value %s in get result does not match the value %s in request",
   986  					keyvalsSnapshot[0].Value, val1)
   987  			}
   988  		})
   989  	}
   990  }
   991  
   992  // TestSnapshotMethods verifies that snapshots allow only read-only
   993  // engine operations.
   994  func TestSnapshotMethods(t *testing.T) {
   995  	defer leaktest.AfterTest(t)()
   996  
   997  	for _, engineImpl := range mvccEngineImpls {
   998  		t.Run(engineImpl.name, func(t *testing.T) {
   999  			engine := engineImpl.create()
  1000  			defer engine.Close()
  1001  
  1002  			keys := []MVCCKey{mvccKey("a"), mvccKey("b")}
  1003  			vals := [][]byte{[]byte("1"), []byte("2")}
  1004  			for i := range keys {
  1005  				if err := engine.Put(keys[i], vals[i]); err != nil {
  1006  					t.Fatal(err)
  1007  				}
  1008  				if val, err := engine.Get(keys[i]); err != nil {
  1009  					t.Fatal(err)
  1010  				} else if !bytes.Equal(vals[i], val) {
  1011  					t.Fatalf("expected %s, but found %s", vals[i], val)
  1012  				}
  1013  			}
  1014  			snap := engine.NewSnapshot()
  1015  			defer snap.Close()
  1016  
  1017  			// Verify Get.
  1018  			for i := range keys {
  1019  				valSnapshot, err := snap.Get(keys[i])
  1020  				if err != nil {
  1021  					t.Fatal(err)
  1022  				}
  1023  				if !bytes.Equal(vals[i], valSnapshot) {
  1024  					t.Fatalf("the value %s in get result does not match the value %s in snapshot",
  1025  						vals[i], valSnapshot)
  1026  				}
  1027  			}
  1028  
  1029  			// Verify Scan.
  1030  			keyvals, _ := Scan(engine, roachpb.KeyMin, roachpb.KeyMax, 0)
  1031  			keyvalsSnapshot, err := Scan(snap, roachpb.KeyMin, roachpb.KeyMax, 0)
  1032  			if err != nil {
  1033  				t.Fatal(err)
  1034  			}
  1035  			if !reflect.DeepEqual(keyvals, keyvalsSnapshot) {
  1036  				t.Fatalf("the key/values %v in scan result does not match the value %s in snapshot",
  1037  					keyvals, keyvalsSnapshot)
  1038  			}
  1039  
  1040  			// Verify Iterate.
  1041  			index := 0
  1042  			if err := snap.Iterate(roachpb.KeyMin, roachpb.KeyMax, func(kv MVCCKeyValue) (bool, error) {
  1043  				if !kv.Key.Equal(keys[index]) || !bytes.Equal(kv.Value, vals[index]) {
  1044  					t.Errorf("%d: key/value not equal between expected and snapshot: %s/%s, %s/%s",
  1045  						index, keys[index], vals[index], kv.Key, kv.Value)
  1046  				}
  1047  				index++
  1048  				return false, nil
  1049  			}); err != nil {
  1050  				t.Fatal(err)
  1051  			}
  1052  
  1053  			// Write a new key to engine.
  1054  			newKey := mvccKey("c")
  1055  			newVal := []byte("3")
  1056  			if err := engine.Put(newKey, newVal); err != nil {
  1057  				t.Fatal(err)
  1058  			}
  1059  
  1060  			// Verify NewIterator still iterates over original snapshot.
  1061  			iter := snap.NewIterator(IterOptions{UpperBound: roachpb.KeyMax})
  1062  			iter.SeekGE(newKey)
  1063  			if ok, err := iter.Valid(); err != nil {
  1064  				t.Fatal(err)
  1065  			} else if ok {
  1066  				t.Error("expected invalid iterator when seeking to element which shouldn't be visible to snapshot")
  1067  			}
  1068  			iter.Close()
  1069  		})
  1070  	}
  1071  }
  1072  
  1073  func insertKeys(keys []MVCCKey, engine Engine, t *testing.T) {
  1074  	insertKeysAndValues(keys, nil, engine, t)
  1075  }
  1076  
  1077  func insertKeysAndValues(keys []MVCCKey, values [][]byte, engine Engine, t *testing.T) {
  1078  	// Add keys to store in random order (make sure they sort!).
  1079  	order := rand.Perm(len(keys))
  1080  	for _, idx := range order {
  1081  		var val []byte
  1082  		if idx < len(values) {
  1083  			val = values[idx]
  1084  		} else {
  1085  			val = []byte("value")
  1086  		}
  1087  		if err := engine.Put(keys[idx], val); err != nil {
  1088  			t.Errorf("put: expected no error, but got %s", err)
  1089  		}
  1090  	}
  1091  }
  1092  
  1093  func TestCreateCheckpoint(t *testing.T) {
  1094  	defer leaktest.AfterTest(t)()
  1095  
  1096  	dir, cleanup := testutils.TempDir(t)
  1097  	defer cleanup()
  1098  
  1099  	rocksDB, err := NewRocksDB(
  1100  		RocksDBConfig{
  1101  			StorageConfig: base.StorageConfig{
  1102  				Settings: cluster.MakeTestingClusterSettings(),
  1103  				Dir:      dir,
  1104  			},
  1105  		},
  1106  		RocksDBCache{},
  1107  	)
  1108  
  1109  	db := Engine(rocksDB) // be impl neutral from now on
  1110  	defer db.Close()
  1111  
  1112  	dir = filepath.Join(dir, "checkpoint")
  1113  
  1114  	assert.NoError(t, err)
  1115  	assert.NoError(t, db.CreateCheckpoint(dir))
  1116  	assert.DirExists(t, dir)
  1117  	m, err := filepath.Glob(dir + "/*")
  1118  	assert.NoError(t, err)
  1119  	assert.True(t, len(m) > 0)
  1120  	if err := db.CreateCheckpoint(dir); !testutils.IsError(err, "exists") {
  1121  		t.Fatal(err)
  1122  	}
  1123  }
  1124  
  1125  func TestIngestDelayLimit(t *testing.T) {
  1126  	defer leaktest.AfterTest(t)()
  1127  	s := cluster.MakeTestingClusterSettings()
  1128  
  1129  	max, ramp := time.Second*5, time.Second*5/10
  1130  
  1131  	for _, tc := range []struct {
  1132  		exp   time.Duration
  1133  		stats Stats
  1134  	}{
  1135  		{0, Stats{}},
  1136  		{0, Stats{L0FileCount: 19}},
  1137  		{0, Stats{L0FileCount: 20}},
  1138  		{ramp, Stats{L0FileCount: 21}},
  1139  		{ramp * 2, Stats{L0FileCount: 22}},
  1140  		{max, Stats{L0FileCount: 55}},
  1141  	} {
  1142  		require.Equal(t, tc.exp, calculatePreIngestDelay(s, &tc.stats))
  1143  	}
  1144  }
  1145  
  1146  type stringSorter []string
  1147  
  1148  func (s stringSorter) Len() int               { return len(s) }
  1149  func (s stringSorter) Swap(i int, j int)      { s[i], s[j] = s[j], s[i] }
  1150  func (s stringSorter) Less(i int, j int) bool { return strings.Compare(s[i], s[j]) < 0 }
  1151  
  1152  func TestEngineFS(t *testing.T) {
  1153  	defer leaktest.AfterTest(t)()
  1154  
  1155  	for _, engineImpl := range mvccEngineImpls {
  1156  		t.Run(engineImpl.name, func(t *testing.T) {
  1157  			e := engineImpl.create()
  1158  			defer e.Close()
  1159  
  1160  			testCases := []string{
  1161  				"1a: f = create /bar",
  1162  				"1b: f.write abcdefghijklmnopqrstuvwxyz",
  1163  				"1c: f.close",
  1164  				"2a: f = open /bar",
  1165  				"2b: f.read 5 == abcde",
  1166  				"2c: f.readat 2 1 == bc",
  1167  				"2d: f.readat 5 20 == uvwxy",
  1168  				"2e: f.close",
  1169  				"3a: link /bar /baz",
  1170  				"3b: f = open /baz",
  1171  				"3c: f.read 5 == abcde",
  1172  				"3d: f.close",
  1173  				"4a: delete /bar",
  1174  				"4b: f = open /baz",
  1175  				"4c: f.read 5 == abcde",
  1176  				"4d: f.close",
  1177  				"4e: open /bar [does-not-exist]",
  1178  				"5a: rename /baz /foo",
  1179  				"5b: f = open /foo",
  1180  				"5c: f.readat 5 20 == uvwxy",
  1181  				"5d: f.close",
  1182  				"5e: open /baz [does-not-exist]",
  1183  				"6a: f = create /red",
  1184  				"6b: f.write blue",
  1185  				"6c: f.sync",
  1186  				"6d: f.close",
  1187  				"7a: f = opendir /",
  1188  				"7b: f.sync",
  1189  				"7c: f.close",
  1190  				"8a: f = create-with-sync /bar",
  1191  				"8b: f.write ghe",
  1192  				"8c: f.close",
  1193  				"8d: f = open /bar",
  1194  				"8e: f.read 3 == ghe",
  1195  				"9a: create-dir /dir1",
  1196  				"9b: create /dir1/bar",
  1197  				"9c: list-dir /dir1 == bar",
  1198  				"9d: create /dir1/baz",
  1199  				"9e: list-dir /dir1 == bar,baz",
  1200  				"9f: delete /dir1/bar",
  1201  				"9g: delete /dir1/baz",
  1202  				"9h: delete-dir /dir1",
  1203  			}
  1204  
  1205  			var f fs.File
  1206  			for _, tc := range testCases {
  1207  				s := strings.Split(tc, " ")[1:]
  1208  
  1209  				saveF := s[0] == "f" && s[1] == "="
  1210  				if saveF {
  1211  					s = s[2:]
  1212  				}
  1213  
  1214  				fails := s[len(s)-1][0] == '['
  1215  				var errorStr string
  1216  				if fails {
  1217  					errorStr = s[len(s)-1][1:]
  1218  					errorStr = errorStr[:len(errorStr)-1]
  1219  					s = s[:len(s)-1]
  1220  				}
  1221  
  1222  				var (
  1223  					g   fs.File
  1224  					err error
  1225  				)
  1226  				switch s[0] {
  1227  				case "create":
  1228  					g, err = e.Create(s[1])
  1229  				case "create-with-sync":
  1230  					g, err = e.CreateWithSync(s[1], 1)
  1231  				case "link":
  1232  					err = e.Link(s[1], s[2])
  1233  				case "open":
  1234  					g, err = e.Open(s[1])
  1235  				case "opendir":
  1236  					g, err = e.OpenDir(s[1])
  1237  				case "delete":
  1238  					err = e.Remove(s[1])
  1239  				case "rename":
  1240  					err = e.Rename(s[1], s[2])
  1241  				case "create-dir":
  1242  					err = e.MkdirAll(s[1])
  1243  				case "delete-dir":
  1244  					err = e.RemoveDir(s[1])
  1245  				case "list-dir":
  1246  					result, err := e.List(s[1])
  1247  					if err != nil {
  1248  						break
  1249  					}
  1250  					sort.Sort(stringSorter(result))
  1251  					got := strings.Join(result, ",")
  1252  					want := s[3]
  1253  					if got != want {
  1254  						t.Fatalf("%q: got %s, want %s", tc, got, want)
  1255  					}
  1256  				case "f.write":
  1257  					_, err = f.Write([]byte(s[1]))
  1258  				case "f.read":
  1259  					n, _ := strconv.Atoi(s[1])
  1260  					buf := make([]byte, n)
  1261  					_, err = io.ReadFull(f, buf)
  1262  					if err != nil {
  1263  						break
  1264  					}
  1265  					if got, want := string(buf), s[3]; got != want {
  1266  						t.Fatalf("%q: got %q, want %q", tc, got, want)
  1267  					}
  1268  				case "f.readat":
  1269  					n, _ := strconv.Atoi(s[1])
  1270  					off, _ := strconv.Atoi(s[2])
  1271  					buf := make([]byte, n)
  1272  					_, err = f.ReadAt(buf, int64(off))
  1273  					if err != nil {
  1274  						break
  1275  					}
  1276  					if got, want := string(buf), s[4]; got != want {
  1277  						t.Fatalf("%q: got %q, want %q", tc, got, want)
  1278  					}
  1279  				case "f.close":
  1280  					f, err = nil, f.Close()
  1281  				case "f.sync":
  1282  					err = f.Sync()
  1283  				default:
  1284  					t.Fatalf("bad test case: %q", tc)
  1285  				}
  1286  
  1287  				if saveF {
  1288  					f, g = g, nil
  1289  				} else if g != nil {
  1290  					g.Close()
  1291  				}
  1292  
  1293  				if fails {
  1294  					if err == nil {
  1295  						t.Fatalf("%q: got nil error, want non-nil %s", tc, errorStr)
  1296  					}
  1297  					var actualErrStr string
  1298  					if os.IsExist(err) {
  1299  						actualErrStr = "exists"
  1300  					} else if os.IsNotExist(err) {
  1301  						actualErrStr = "does-not-exist"
  1302  					} else {
  1303  						actualErrStr = "error"
  1304  					}
  1305  					if errorStr != actualErrStr {
  1306  						t.Fatalf("%q: got %s, want %s", tc, actualErrStr, errorStr)
  1307  					}
  1308  				} else {
  1309  					if err != nil {
  1310  						t.Fatalf("%q: %v", tc, err)
  1311  					}
  1312  				}
  1313  			}
  1314  		})
  1315  	}
  1316  }
  1317  
  1318  type engineImpl struct {
  1319  	name   string
  1320  	create func(*testing.T, string) Engine
  1321  }
  1322  
  1323  // These FS implementations are not in-memory.
  1324  var engineRealFSImpls = []engineImpl{
  1325  	{"rocksdb", func(t *testing.T, dir string) Engine {
  1326  		db, err := NewRocksDB(
  1327  			RocksDBConfig{
  1328  				StorageConfig: base.StorageConfig{
  1329  					Settings: cluster.MakeTestingClusterSettings(),
  1330  					Dir:      dir,
  1331  				},
  1332  			},
  1333  			RocksDBCache{},
  1334  		)
  1335  		if err != nil {
  1336  			t.Fatalf("could not create new rocksdb instance at %s: %+v", dir, err)
  1337  		}
  1338  		return db
  1339  	}},
  1340  	{"pebble", func(t *testing.T, dir string) Engine {
  1341  
  1342  		opts := DefaultPebbleOptions()
  1343  		opts.FS = vfs.Default
  1344  		opts.Cache = pebble.NewCache(testCacheSize)
  1345  		defer opts.Cache.Unref()
  1346  
  1347  		db, err := NewPebble(
  1348  			context.Background(),
  1349  			PebbleConfig{
  1350  				StorageConfig: base.StorageConfig{
  1351  					Dir: dir,
  1352  				},
  1353  				Opts: opts,
  1354  			})
  1355  		if err != nil {
  1356  			t.Fatalf("could not create new pebble instance at %s: %+v", dir, err)
  1357  		}
  1358  		return db
  1359  	}},
  1360  }
  1361  
  1362  func TestEngineFSFileNotFoundError(t *testing.T) {
  1363  	defer leaktest.AfterTest(t)()
  1364  
  1365  	for _, engineImpl := range engineRealFSImpls {
  1366  		t.Run(engineImpl.name, func(t *testing.T) {
  1367  			dir, dirCleanup := testutils.TempDir(t)
  1368  			defer dirCleanup()
  1369  			db := engineImpl.create(t, dir)
  1370  			defer db.Close()
  1371  
  1372  			// Verify Remove returns os.ErrNotExist if file does not exist.
  1373  			if err := db.Remove("/non/existent/file"); !os.IsNotExist(err) {
  1374  				t.Fatalf("expected IsNotExist, but got %v (%T)", err, err)
  1375  			}
  1376  
  1377  			// Verify RemoveAll returns nil if path does not exist.
  1378  			if err := db.RemoveAll("/non/existent/file"); err != nil {
  1379  				t.Fatalf("expected nil, but got %v (%T)", err, err)
  1380  			}
  1381  
  1382  			fname := filepath.Join(dir, "random.file")
  1383  			data := "random data"
  1384  			if f, err := db.Create(fname); err != nil {
  1385  				t.Fatalf("unable to open file with filename %s, got err %v", fname, err)
  1386  			} else {
  1387  				// Write data to file so we can read it later.
  1388  				if _, err := f.Write([]byte(data)); err != nil {
  1389  					t.Fatalf("error writing data: '%s' to file %s, got err %v", data, fname, err)
  1390  				}
  1391  				if err := f.Sync(); err != nil {
  1392  					t.Fatalf("error syncing data, got err %v", err)
  1393  				}
  1394  				if err := f.Close(); err != nil {
  1395  					t.Fatalf("error closing file %s, got err %v", fname, err)
  1396  				}
  1397  			}
  1398  
  1399  			if b, err := db.ReadFile(fname); err != nil {
  1400  				t.Errorf("unable to read file with filename %s, got err %v", fname, err)
  1401  			} else if string(b) != data {
  1402  				t.Errorf("expected content in %s is '%s', got '%s'", fname, data, string(b))
  1403  			}
  1404  
  1405  			if err := db.Remove(fname); err != nil {
  1406  				t.Errorf("unable to delete file with filename %s, got err %v", fname, err)
  1407  			}
  1408  
  1409  			// Verify ReadFile returns os.ErrNotExist if reading an already deleted file.
  1410  			if _, err := db.ReadFile(fname); !os.IsNotExist(err) {
  1411  				t.Fatalf("expected IsNotExist, but got %v (%T)", err, err)
  1412  			}
  1413  
  1414  			// Verify Remove returns os.ErrNotExist if deleting an already deleted file.
  1415  			if err := db.Remove(fname); !os.IsNotExist(err) {
  1416  				t.Fatalf("expected IsNotExist, but got %v (%T)", err, err)
  1417  			}
  1418  		})
  1419  	}
  1420  }
  1421  
  1422  func TestFS(t *testing.T) {
  1423  	defer leaktest.AfterTest(t)()
  1424  
  1425  	var engineImpls []engineImpl
  1426  	engineImpls = append(engineImpls, engineRealFSImpls...)
  1427  	engineImpls = append(engineImpls,
  1428  		engineImpl{
  1429  			name: "rocksdb_mem",
  1430  			create: func(_ *testing.T, _ string) Engine {
  1431  				return createTestRocksDBEngine()
  1432  			},
  1433  		},
  1434  		engineImpl{
  1435  			name: "pebble_mem",
  1436  			create: func(_ *testing.T, _ string) Engine {
  1437  				return createTestPebbleEngine()
  1438  			},
  1439  		})
  1440  
  1441  	for _, impl := range engineImpls {
  1442  		t.Run(impl.name, func(t *testing.T) {
  1443  			dir, cleanupDir := testutils.TempDir(t)
  1444  			defer cleanupDir()
  1445  			fs := impl.create(t, dir)
  1446  			defer fs.Close()
  1447  
  1448  			path := func(rel string) string {
  1449  				return filepath.Join(dir, rel)
  1450  			}
  1451  			expectLS := func(dir string, want []string) {
  1452  				t.Helper()
  1453  
  1454  				got, err := fs.List(dir)
  1455  				require.NoError(t, err)
  1456  				if !reflect.DeepEqual(got, want) {
  1457  					t.Fatalf("fs.List(%q) = %#v, want %#v", dir, got, want)
  1458  				}
  1459  			}
  1460  
  1461  			// Create a/ and assert that it's empty.
  1462  			require.NoError(t, fs.MkdirAll(path("a")))
  1463  			expectLS(path("a"), []string{})
  1464  
  1465  			// Create a/b/ and a/b/c/ in a single MkdirAll call.
  1466  			// Then ensure that a duplicate call returns a nil error.
  1467  			require.NoError(t, fs.MkdirAll(path("a/b/c")))
  1468  			require.NoError(t, fs.MkdirAll(path("a/b/c")))
  1469  			expectLS(path("a"), []string{"b"})
  1470  			expectLS(path("a/b"), []string{"c"})
  1471  			expectLS(path("a/b/c"), []string{})
  1472  
  1473  			// Create a file at a/b/c/foo.
  1474  			f, err := fs.Create(path("a/b/c/foo"))
  1475  			require.NoError(t, err)
  1476  			require.NoError(t, f.Close())
  1477  			expectLS(path("a/b/c"), []string{"foo"})
  1478  
  1479  			// Create a file at a/b/c/bar.
  1480  			f, err = fs.Create(path("a/b/c/bar"))
  1481  			require.NoError(t, err)
  1482  			require.NoError(t, f.Close())
  1483  			expectLS(path("a/b/c"), []string{"bar", "foo"})
  1484  
  1485  			// RemoveAll a file.
  1486  			require.NoError(t, fs.RemoveAll(path("a/b/c/bar")))
  1487  			expectLS(path("a/b/c"), []string{"foo"})
  1488  
  1489  			// RemoveAll a directory that contains subdirectories and
  1490  			// descendant files.
  1491  			require.NoError(t, fs.RemoveAll(path("a/b")))
  1492  			expectLS(path("a"), []string{})
  1493  		})
  1494  	}
  1495  }