github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/batch_test.go (about)

     1  // Copyright 2012 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 pebble
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/petermattis/pebble/internal/base"
    16  	"github.com/petermattis/pebble/internal/datadriven"
    17  	"github.com/petermattis/pebble/vfs"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestBatch(t *testing.T) {
    22  	type testCase struct {
    23  		kind       InternalKeyKind
    24  		key, value string
    25  	}
    26  
    27  	verifyTestCases := func(b *Batch, testCases []testCase) {
    28  		r := b.Reader()
    29  
    30  		for _, tc := range testCases {
    31  			kind, k, v, ok := r.Next()
    32  			if !ok {
    33  				t.Fatalf("next returned !ok: test case = %v", tc)
    34  			}
    35  			key, value := string(k), string(v)
    36  			if kind != tc.kind || key != tc.key || value != tc.value {
    37  				t.Errorf("got (%d, %q, %q), want (%d, %q, %q)",
    38  					kind, key, value, tc.kind, tc.key, tc.value)
    39  			}
    40  		}
    41  		if len(r) != 0 {
    42  			t.Errorf("reader was not exhausted: remaining bytes = %q", r)
    43  		}
    44  	}
    45  
    46  	testCases := []testCase{
    47  		{InternalKeyKindSet, "roses", "red"},
    48  		{InternalKeyKindSet, "violets", "blue"},
    49  		{InternalKeyKindDelete, "roses", ""},
    50  		{InternalKeyKindSet, "", ""},
    51  		{InternalKeyKindSet, "", "non-empty"},
    52  		{InternalKeyKindDelete, "", ""},
    53  		{InternalKeyKindSet, "grass", "green"},
    54  		{InternalKeyKindSet, "grass", "greener"},
    55  		{InternalKeyKindSet, "eleventy", strings.Repeat("!!11!", 100)},
    56  		{InternalKeyKindDelete, "nosuchkey", ""},
    57  		{InternalKeyKindSet, "binarydata", "\x00"},
    58  		{InternalKeyKindSet, "binarydata", "\xff"},
    59  		{InternalKeyKindMerge, "merge", "mergedata"},
    60  		{InternalKeyKindMerge, "merge", ""},
    61  		{InternalKeyKindMerge, "", ""},
    62  		{InternalKeyKindRangeDelete, "a", "b"},
    63  		{InternalKeyKindRangeDelete, "", ""},
    64  		{InternalKeyKindLogData, "logdata", ""},
    65  		{InternalKeyKindLogData, "", ""},
    66  	}
    67  	var b Batch
    68  	for _, tc := range testCases {
    69  		switch tc.kind {
    70  		case InternalKeyKindSet:
    71  			_ = b.Set([]byte(tc.key), []byte(tc.value), nil)
    72  		case InternalKeyKindMerge:
    73  			_ = b.Merge([]byte(tc.key), []byte(tc.value), nil)
    74  		case InternalKeyKindDelete:
    75  			_ = b.Delete([]byte(tc.key), nil)
    76  		case InternalKeyKindRangeDelete:
    77  			_ = b.DeleteRange([]byte(tc.key), []byte(tc.value), nil)
    78  		case InternalKeyKindLogData:
    79  			_ = b.LogData([]byte(tc.key), nil)
    80  		}
    81  	}
    82  	verifyTestCases(&b, testCases)
    83  
    84  	b.Reset()
    85  	// Run the same operations, this time using the Deferred variants of each
    86  	// operation (eg. SetDeferred).
    87  	for _, tc := range testCases {
    88  		key := []byte(tc.key)
    89  		value := []byte(tc.value)
    90  		switch tc.kind {
    91  		case InternalKeyKindSet:
    92  			d, _ := b.SetDeferred(len(key), len(value), nil)
    93  			copy(d.Key, key)
    94  			copy(d.Value, value)
    95  			d.Finish()
    96  		case InternalKeyKindMerge:
    97  			d, _ := b.MergeDeferred(len(key), len(value), nil)
    98  			copy(d.Key, key)
    99  			copy(d.Value, value)
   100  			d.Finish()
   101  		case InternalKeyKindDelete:
   102  			d, _ := b.DeleteDeferred(len(key), nil)
   103  			copy(d.Key, key)
   104  			copy(d.Value, value)
   105  			d.Finish()
   106  		case InternalKeyKindRangeDelete:
   107  			d, _ := b.DeleteRangeDeferred(len(key), len(value), nil)
   108  			copy(d.Key, key)
   109  			copy(d.Value, value)
   110  			d.Finish()
   111  		case InternalKeyKindLogData:
   112  			_ = b.LogData([]byte(tc.key), nil)
   113  		}
   114  	}
   115  	verifyTestCases(&b, testCases)
   116  }
   117  
   118  func TestBatchEmpty(t *testing.T) {
   119  	var b Batch
   120  	require.True(t, b.Empty())
   121  
   122  	b.Set(nil, nil, nil)
   123  	require.False(t, b.Empty())
   124  	b.Reset()
   125  	require.True(t, b.Empty())
   126  
   127  	b.Merge(nil, nil, nil)
   128  	require.False(t, b.Empty())
   129  	b.Reset()
   130  	require.True(t, b.Empty())
   131  
   132  	b.Delete(nil, nil)
   133  	require.False(t, b.Empty())
   134  	b.Reset()
   135  	require.True(t, b.Empty())
   136  
   137  	b.DeleteRange(nil, nil, nil)
   138  	require.False(t, b.Empty())
   139  	b.Reset()
   140  	require.True(t, b.Empty())
   141  
   142  	b.LogData(nil, nil)
   143  	require.False(t, b.Empty())
   144  	b.Reset()
   145  	require.True(t, b.Empty())
   146  }
   147  
   148  func TestBatchIncrement(t *testing.T) {
   149  	testCases := []uint32{
   150  		0x00000000,
   151  		0x00000001,
   152  		0x00000002,
   153  		0x0000007f,
   154  		0x00000080,
   155  		0x000000fe,
   156  		0x000000ff,
   157  		0x00000100,
   158  		0x00000101,
   159  		0x000001ff,
   160  		0x00000200,
   161  		0x00000fff,
   162  		0x00001234,
   163  		0x0000fffe,
   164  		0x0000ffff,
   165  		0x00010000,
   166  		0x00010001,
   167  		0x000100fe,
   168  		0x000100ff,
   169  		0x00020100,
   170  		0x03fffffe,
   171  		0x03ffffff,
   172  		0x04000000,
   173  		0x04000001,
   174  		0x7fffffff,
   175  		0xfffffffe,
   176  		0xffffffff,
   177  	}
   178  	for _, tc := range testCases {
   179  		var buf [batchHeaderLen]byte
   180  		binary.LittleEndian.PutUint32(buf[8:12], tc)
   181  		var b Batch
   182  		b.SetRepr(buf[:])
   183  		b.increment()
   184  		got := binary.LittleEndian.Uint32(b.Repr()[8:12])
   185  		want := tc + 1
   186  		if tc == 0xffffffff {
   187  			want = tc
   188  		}
   189  		if got != want {
   190  			t.Errorf("input=%d: got %d, want %d", tc, got, want)
   191  		}
   192  	}
   193  }
   194  
   195  func TestBatchOpDoesIncrement(t *testing.T) {
   196  	var b Batch
   197  	key := []byte("foo")
   198  	value := []byte("bar")
   199  
   200  	if b.Count() != 0 {
   201  		t.Fatalf("new batch has a nonzero count: %d", b.Count())
   202  	}
   203  
   204  	// Should increment count by 1
   205  	_ = b.Set(key, value, nil)
   206  	if b.Count() != 1 {
   207  		t.Fatalf("expected count: %d, got %d", 1, b.Count())
   208  	}
   209  
   210  	var b2 Batch
   211  	// Should increment count by 1 each
   212  	_ = b2.Set(key, value, nil)
   213  	_ = b2.Delete(key, nil)
   214  	if b2.Count() != 2 {
   215  		t.Fatalf("expected count: %d, got %d", 2, b2.Count())
   216  	}
   217  
   218  	// Should increment count by b2.count()
   219  	_ = b.Apply(&b2, nil)
   220  	if b.Count() != 3 {
   221  		t.Fatalf("expected count: %d, got %d", 3, b.Count())
   222  	}
   223  
   224  	// Should increment count by 1
   225  	_ = b.Merge(key, value, nil)
   226  	if b.Count() != 4 {
   227  		t.Fatalf("expected count: %d, got %d", 4, b.Count())
   228  	}
   229  
   230  	// Should NOT increment count.
   231  	_ = b.LogData([]byte("foobarbaz"), nil)
   232  	if b.Count() != 4 {
   233  		t.Fatalf("expected count: %d, got %d", 4, b.Count())
   234  	}
   235  }
   236  
   237  func TestBatchGet(t *testing.T) {
   238  	for _, method := range []string{"build", "apply"} {
   239  		t.Run(method, func(t *testing.T) {
   240  			d, err := Open("", &Options{
   241  				FS: vfs.NewMem(),
   242  			})
   243  			if err != nil {
   244  				t.Fatalf("Open: %v", err)
   245  			}
   246  			defer d.Close()
   247  			var b *Batch
   248  
   249  			datadriven.RunTest(t, "testdata/batch_get", func(td *datadriven.TestData) string {
   250  				switch td.Cmd {
   251  				case "define":
   252  					switch method {
   253  					case "build":
   254  						b = d.NewIndexedBatch()
   255  					case "apply":
   256  						b = d.NewBatch()
   257  					}
   258  
   259  					if err := runBatchDefineCmd(td, b); err != nil {
   260  						return err.Error()
   261  					}
   262  
   263  					switch method {
   264  					case "apply":
   265  						tmp := d.NewIndexedBatch()
   266  						tmp.Apply(b, nil)
   267  						b = tmp
   268  					}
   269  					return ""
   270  
   271  				case "commit":
   272  					if err := b.Commit(nil); err != nil {
   273  						return err.Error()
   274  					}
   275  					return ""
   276  
   277  				case "get":
   278  					if len(td.CmdArgs) != 1 {
   279  						return fmt.Sprintf("%s expects 1 argument", td.Cmd)
   280  					}
   281  					v, err := b.Get([]byte(td.CmdArgs[0].String()))
   282  					if err != nil {
   283  						return err.Error()
   284  					}
   285  					return string(v)
   286  
   287  				default:
   288  					return fmt.Sprintf("unknown command: %s", td.Cmd)
   289  				}
   290  			})
   291  		})
   292  	}
   293  }
   294  
   295  func TestBatchIter(t *testing.T) {
   296  	var b *Batch
   297  
   298  	for _, method := range []string{"build", "apply"} {
   299  		t.Run(method, func(t *testing.T) {
   300  			datadriven.RunTest(t, "testdata/internal_iter_next", func(d *datadriven.TestData) string {
   301  				switch d.Cmd {
   302  				case "define":
   303  					switch method {
   304  					case "build":
   305  						b = newIndexedBatch(nil, DefaultComparer)
   306  					case "apply":
   307  						b = newBatch(nil)
   308  					}
   309  
   310  					for _, key := range strings.Split(d.Input, "\n") {
   311  						j := strings.Index(key, ":")
   312  						ikey := base.ParseInternalKey(key[:j])
   313  						value := []byte(fmt.Sprint(ikey.SeqNum()))
   314  						b.Set(ikey.UserKey, value, nil)
   315  					}
   316  
   317  					switch method {
   318  					case "apply":
   319  						tmp := newIndexedBatch(nil, DefaultComparer)
   320  						tmp.Apply(b, nil)
   321  						b = tmp
   322  					}
   323  					return ""
   324  
   325  				case "iter":
   326  					iter := b.newInternalIter(nil)
   327  					defer iter.Close()
   328  					return runInternalIterCmd(d, iter)
   329  
   330  				default:
   331  					return fmt.Sprintf("unknown command: %s", d.Cmd)
   332  				}
   333  			})
   334  		})
   335  	}
   336  }
   337  
   338  func TestBatchDeleteRange(t *testing.T) {
   339  	var b *Batch
   340  
   341  	datadriven.RunTest(t, "testdata/batch_delete_range", func(td *datadriven.TestData) string {
   342  		switch td.Cmd {
   343  		case "clear":
   344  			b = nil
   345  			return ""
   346  
   347  		case "define":
   348  			if b == nil {
   349  				b = newIndexedBatch(nil, DefaultComparer)
   350  			}
   351  			if err := runBatchDefineCmd(td, b); err != nil {
   352  				return err.Error()
   353  			}
   354  			return ""
   355  
   356  		case "scan":
   357  			var iter internalIterAdapter
   358  			if len(td.CmdArgs) > 1 {
   359  				return fmt.Sprintf("%s expects at most 1 argument", td.Cmd)
   360  			}
   361  			if len(td.CmdArgs) == 1 {
   362  				if td.CmdArgs[0].String() != "range-del" {
   363  					return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0])
   364  				}
   365  				iter.internalIterator = b.newRangeDelIter(nil)
   366  			} else {
   367  				iter.internalIterator = b.newInternalIter(nil)
   368  			}
   369  			defer iter.Close()
   370  
   371  			var buf bytes.Buffer
   372  			for valid := iter.First(); valid; valid = iter.Next() {
   373  				key := iter.Key()
   374  				key.SetSeqNum(key.SeqNum() &^ InternalKeySeqNumBatch)
   375  				fmt.Fprintf(&buf, "%s:%s\n", key, iter.Value())
   376  			}
   377  			return buf.String()
   378  
   379  		default:
   380  			return fmt.Sprintf("unknown command: %s", td.Cmd)
   381  		}
   382  	})
   383  }
   384  
   385  func TestFlushableBatchIter(t *testing.T) {
   386  	var b *flushableBatch
   387  	datadriven.RunTest(t, "testdata/internal_iter_next", func(d *datadriven.TestData) string {
   388  		switch d.Cmd {
   389  		case "define":
   390  			batch := newBatch(nil)
   391  			for _, key := range strings.Split(d.Input, "\n") {
   392  				j := strings.Index(key, ":")
   393  				ikey := base.ParseInternalKey(key[:j])
   394  				value := []byte(fmt.Sprint(ikey.SeqNum()))
   395  				batch.Set(ikey.UserKey, value, nil)
   396  			}
   397  			b = newFlushableBatch(batch, DefaultComparer)
   398  			return ""
   399  
   400  		case "iter":
   401  			iter := b.newIter(nil)
   402  			defer iter.Close()
   403  			return runInternalIterCmd(d, iter)
   404  
   405  		default:
   406  			return fmt.Sprintf("unknown command: %s", d.Cmd)
   407  		}
   408  	})
   409  }
   410  
   411  func TestFlushableBatch(t *testing.T) {
   412  	var b *flushableBatch
   413  	datadriven.RunTest(t, "testdata/flushable_batch", func(d *datadriven.TestData) string {
   414  		switch d.Cmd {
   415  		case "define":
   416  			batch := newBatch(nil)
   417  			for _, key := range strings.Split(d.Input, "\n") {
   418  				j := strings.Index(key, ":")
   419  				ikey := base.ParseInternalKey(key[:j])
   420  				value := []byte(fmt.Sprint(ikey.SeqNum()))
   421  				switch ikey.Kind() {
   422  				case InternalKeyKindDelete:
   423  					batch.Delete(ikey.UserKey, nil)
   424  				case InternalKeyKindSet:
   425  					batch.Set(ikey.UserKey, value, nil)
   426  				case InternalKeyKindMerge:
   427  					batch.Merge(ikey.UserKey, value, nil)
   428  				}
   429  			}
   430  			b = newFlushableBatch(batch, DefaultComparer)
   431  			return ""
   432  
   433  		case "iter":
   434  			var opts IterOptions
   435  			for _, arg := range d.CmdArgs {
   436  				if len(arg.Vals) != 1 {
   437  					return fmt.Sprintf("%s: %s=<value>", d.Cmd, arg.Key)
   438  				}
   439  				switch arg.Key {
   440  				case "lower":
   441  					opts.LowerBound = []byte(arg.Vals[0])
   442  				case "upper":
   443  					opts.UpperBound = []byte(arg.Vals[0])
   444  				default:
   445  					return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key)
   446  				}
   447  			}
   448  
   449  			iter := b.newIter(&opts)
   450  			defer iter.Close()
   451  			return runInternalIterCmd(d, iter)
   452  
   453  		case "dump":
   454  			if len(d.CmdArgs) != 1 || len(d.CmdArgs[0].Vals) != 1 || d.CmdArgs[0].Key != "seq" {
   455  				return fmt.Sprintf("dump seq=<value>\n")
   456  			}
   457  			seqNum, err := strconv.Atoi(d.CmdArgs[0].Vals[0])
   458  			if err != nil {
   459  				return err.Error()
   460  			}
   461  			b.seqNum = uint64(seqNum)
   462  
   463  			iter := internalIterAdapter{b.newIter(nil)}
   464  			var buf bytes.Buffer
   465  			for valid := iter.First(); valid; valid = iter.Next() {
   466  				fmt.Fprintf(&buf, "%s:%s\n", iter.Key(), iter.Value())
   467  			}
   468  			iter.Close()
   469  			return buf.String()
   470  
   471  		default:
   472  			return fmt.Sprintf("unknown command: %s", d.Cmd)
   473  		}
   474  	})
   475  }
   476  
   477  func TestFlushableBatchDeleteRange(t *testing.T) {
   478  	var fb *flushableBatch
   479  	var input string
   480  
   481  	datadriven.RunTest(t, "testdata/delete_range", func(td *datadriven.TestData) string {
   482  		switch td.Cmd {
   483  		case "clear":
   484  			input = ""
   485  			return ""
   486  
   487  		case "define":
   488  			b := newBatch(nil)
   489  			// NB: We can't actually add to the flushable batch as we can to a
   490  			// memtable (which shares the "testdata/delete_range" data), so we fake
   491  			// it be concatenating the input and rebuilding the flushable batch from
   492  			// scratch.
   493  			input += "\n" + td.Input
   494  			td.Input = input
   495  			if err := runBatchDefineCmd(td, b); err != nil {
   496  				return err.Error()
   497  			}
   498  			fb = newFlushableBatch(b, DefaultComparer)
   499  			return ""
   500  
   501  		case "scan":
   502  			var iter internalIterAdapter
   503  			if len(td.CmdArgs) > 1 {
   504  				return fmt.Sprintf("%s expects at most 1 argument", td.Cmd)
   505  			}
   506  			if len(td.CmdArgs) == 1 {
   507  				if td.CmdArgs[0].String() != "range-del" {
   508  					return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0])
   509  				}
   510  				iter.internalIterator = fb.newRangeDelIter(nil)
   511  			} else {
   512  				iter.internalIterator = fb.newIter(nil)
   513  			}
   514  			defer iter.Close()
   515  
   516  			var buf bytes.Buffer
   517  			for valid := iter.First(); valid; valid = iter.Next() {
   518  				fmt.Fprintf(&buf, "%s:%s\n", iter.Key(), iter.Value())
   519  			}
   520  			return buf.String()
   521  
   522  		default:
   523  			return fmt.Sprintf("unknown command: %s", td.Cmd)
   524  		}
   525  	})
   526  }
   527  
   528  func TestFlushableBatchBytesIterated(t *testing.T) {
   529  	batch := newBatch(nil)
   530  	for j := 0; j < 1000; j++ {
   531  		key := make([]byte, 8+j%3)
   532  		value := make([]byte, 7+j%5)
   533  		batch.Set(key, value, nil)
   534  
   535  		fb := newFlushableBatch(batch, DefaultComparer)
   536  
   537  		var bytesIterated uint64
   538  		it := fb.newFlushIter(nil, &bytesIterated)
   539  
   540  		var prevIterated uint64
   541  		for it.First(); it.Valid(); it.Next() {
   542  			if bytesIterated < prevIterated {
   543  				t.Fatalf("bytesIterated moved backward: %d < %d", bytesIterated, prevIterated)
   544  			}
   545  			prevIterated = bytesIterated
   546  		}
   547  
   548  		expected := fb.totalBytes()
   549  		if bytesIterated != expected {
   550  			t.Fatalf("bytesIterated: got %d, want %d", bytesIterated, expected)
   551  		}
   552  	}
   553  }
   554  
   555  func BenchmarkBatchSet(b *testing.B) {
   556  	value := make([]byte, 10)
   557  	for i := range value {
   558  		value[i] = byte(i)
   559  	}
   560  	key := make([]byte, 8)
   561  	batch := newBatch(nil)
   562  
   563  	b.ResetTimer()
   564  
   565  	const batchSize = 1000
   566  	for i := 0; i < b.N; i += batchSize {
   567  		end := i + batchSize
   568  		if end > b.N {
   569  			end = b.N
   570  		}
   571  
   572  		for j := i; j < end; j++ {
   573  			binary.BigEndian.PutUint64(key, uint64(j))
   574  			batch.Set(key, value, nil)
   575  		}
   576  		batch.Reset()
   577  	}
   578  
   579  	b.StopTimer()
   580  }
   581  
   582  func BenchmarkIndexedBatchSet(b *testing.B) {
   583  	value := make([]byte, 10)
   584  	for i := range value {
   585  		value[i] = byte(i)
   586  	}
   587  	key := make([]byte, 8)
   588  	batch := newIndexedBatch(nil, DefaultComparer)
   589  
   590  	b.ResetTimer()
   591  
   592  	const batchSize = 1000
   593  	for i := 0; i < b.N; i += batchSize {
   594  		end := i + batchSize
   595  		if end > b.N {
   596  			end = b.N
   597  		}
   598  
   599  		for j := i; j < end; j++ {
   600  			binary.BigEndian.PutUint64(key, uint64(j))
   601  			batch.Set(key, value, nil)
   602  		}
   603  		batch.Reset()
   604  	}
   605  
   606  	b.StopTimer()
   607  }
   608  
   609  func BenchmarkBatchSetDeferred(b *testing.B) {
   610  	value := make([]byte, 10)
   611  	for i := range value {
   612  		value[i] = byte(i)
   613  	}
   614  	key := make([]byte, 8)
   615  	batch := newBatch(nil)
   616  
   617  	b.ResetTimer()
   618  
   619  	const batchSize = 1000
   620  	for i := 0; i < b.N; i += batchSize {
   621  		end := i + batchSize
   622  		if end > b.N {
   623  			end = b.N
   624  		}
   625  
   626  		for j := i; j < end; j++ {
   627  			binary.BigEndian.PutUint64(key, uint64(j))
   628  			deferredOp, err := batch.SetDeferred(len(key), len(value), nil)
   629  			if err != nil {
   630  				b.Fatal(err)
   631  			}
   632  
   633  			copy(deferredOp.Key, key)
   634  			copy(deferredOp.Value, value)
   635  
   636  			deferredOp.Finish()
   637  		}
   638  		batch.Reset()
   639  	}
   640  
   641  	b.StopTimer()
   642  }
   643  
   644  func BenchmarkIndexedBatchSetDeferred(b *testing.B) {
   645  	value := make([]byte, 10)
   646  	for i := range value {
   647  		value[i] = byte(i)
   648  	}
   649  	key := make([]byte, 8)
   650  	batch := newIndexedBatch(nil, DefaultComparer)
   651  
   652  	b.ResetTimer()
   653  
   654  	const batchSize = 1000
   655  	for i := 0; i < b.N; i += batchSize {
   656  		end := i + batchSize
   657  		if end > b.N {
   658  			end = b.N
   659  		}
   660  
   661  		for j := i; j < end; j++ {
   662  			binary.BigEndian.PutUint64(key, uint64(j))
   663  			deferredOp, err := batch.SetDeferred(len(key), len(value), nil)
   664  			if err != nil {
   665  				b.Fatal(err)
   666  			}
   667  
   668  			copy(deferredOp.Key, key)
   669  			copy(deferredOp.Value, value)
   670  
   671  			deferredOp.Finish()
   672  		}
   673  		batch.Reset()
   674  	}
   675  
   676  	b.StopTimer()
   677  }