github.com/coocood/badger@v1.5.1-0.20200528065104-c02ac3616d04/table/sstable/table_test.go (about)

     1  /*
     2   * Copyright 2017 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package sstable
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"math"
    24  	"math/rand"
    25  	"os"
    26  	"sort"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/coocood/badger/cache"
    31  	"github.com/coocood/badger/cache/z"
    32  	"github.com/coocood/badger/options"
    33  	"github.com/coocood/badger/table"
    34  	"github.com/coocood/badger/y"
    35  	"github.com/dgryski/go-farm"
    36  	"github.com/stretchr/testify/require"
    37  	"golang.org/x/time/rate"
    38  )
    39  
    40  func key(prefix string, i int) string {
    41  	return prefix + fmt.Sprintf("%04d", i)
    42  }
    43  
    44  var defaultBuilderOpt = options.TableBuilderOptions{
    45  	SuRFStartLevel: 0,
    46  	SuRFOptions: options.SuRFOptions{
    47  		BitsPerKeyHint: 40,
    48  		RealSuffixLen:  10,
    49  	},
    50  	CompressionPerLevel: []options.CompressionType{options.ZSTD},
    51  	BlockSize:           4 * 1024,
    52  	HashUtilRatio:       0.75,
    53  	WriteBufferSize:     1024 * 1024,
    54  	MaxLevels:           1,
    55  	LevelSizeMultiplier: 10,
    56  	LogicalBloomFPR:     0.01,
    57  }
    58  
    59  func testCache() *cache.Cache {
    60  	c, err := cache.NewCache(&cache.Config{
    61  		NumCounters: 1000000 * 10,
    62  		MaxCost:     1000000,
    63  		BufferItems: 64,
    64  		Metrics:     true,
    65  	})
    66  	y.Check(err)
    67  	return c
    68  }
    69  
    70  func generateKeyValues(prefix string, n int) [][]string {
    71  	y.Assert(n <= 10000)
    72  	keyValues := make([][]string, n)
    73  	for i := 0; i < n; i++ {
    74  		k := key(prefix, i)
    75  		v := fmt.Sprintf("%d", i)
    76  		keyValues[i] = []string{k, v}
    77  	}
    78  	return keyValues
    79  }
    80  
    81  var compressionType = options.ZSTD
    82  
    83  func buildTestTable(t *testing.T, prefix string, n int) *os.File {
    84  	return buildTable(t, generateKeyValues(prefix, n))
    85  }
    86  
    87  // keyValues is n by 2 where n is number of pairs.
    88  func buildTable(t *testing.T, keyValues [][]string) *os.File {
    89  	// TODO: Add test for file garbage collection here. No files should be left after the tests here.
    90  	b, f := newTableBuilderForTest()
    91  	sort.Slice(keyValues, func(i, j int) bool {
    92  		return keyValues[i][0] < keyValues[j][0]
    93  	})
    94  	for _, kv := range keyValues {
    95  		y.Assert(len(kv) == 2)
    96  		err := b.Add(y.KeyWithTs([]byte(kv[0]), 0), y.ValueStruct{Value: []byte(kv[1]), Meta: 'A', UserMeta: []byte{0}})
    97  		if t != nil {
    98  			require.NoError(t, err)
    99  		} else {
   100  			y.Check(err)
   101  		}
   102  	}
   103  	y.Check(b.Finish())
   104  	y.Check(f.Close())
   105  	f, _ = y.OpenSyncedFile(f.Name(), true)
   106  	return f
   107  }
   108  
   109  func newTableBuilderForTest() (*Builder, *os.File) {
   110  	filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), z.FastRand())
   111  	f, err := y.OpenSyncedFile(filename, true)
   112  	y.Check(err)
   113  	opt := defaultBuilderOpt
   114  	if z.FastRand()%2 == 0 {
   115  		opt.SuRFStartLevel = 8
   116  	}
   117  	y.Assert(filename == f.Name())
   118  	return NewTableBuilder(f, rate.NewLimiter(rate.Inf, math.MaxInt32), 0, opt), f
   119  }
   120  
   121  func buildMultiVersionTable(keyValues [][]string) *os.File {
   122  	b, f := newTableBuilderForTest()
   123  	sort.Slice(keyValues, func(i, j int) bool {
   124  		return keyValues[i][0] < keyValues[j][0]
   125  	})
   126  	for _, kv := range keyValues {
   127  		y.Assert(len(kv) == 2)
   128  		val := fmt.Sprintf("%s_%d", kv[1], 9)
   129  		err := b.Add(y.KeyWithTs([]byte(kv[0]), 9), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}})
   130  		y.Check(err)
   131  		for i := uint64(8); i > 0; i-- {
   132  			if z.FastRand()%4 != 0 {
   133  				val = fmt.Sprintf("%s_%d", kv[1], i)
   134  				err = b.Add(y.KeyWithTs([]byte(kv[0]), i), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}})
   135  				y.Check(err)
   136  			}
   137  		}
   138  	}
   139  	y.Check(b.Finish())
   140  	y.Check(f.Close())
   141  	f, _ = y.OpenSyncedFile(f.Name(), true)
   142  	return f
   143  }
   144  
   145  func TestTableIterator(t *testing.T) {
   146  	for _, n := range []int{99, 100, 101} {
   147  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   148  			f := buildTestTable(t, "key", n)
   149  			table, err := OpenTable(f.Name(), testCache(), testCache())
   150  			require.NoError(t, err)
   151  			defer table.Delete()
   152  			it := table.newIterator(false)
   153  			count := 0
   154  			for it.Rewind(); it.Valid(); it.Next() {
   155  				v := it.Value()
   156  				k := y.KeyWithTs([]byte(key("key", count)), 0)
   157  				require.EqualValues(t, k, it.Key())
   158  				require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value))
   159  				count++
   160  			}
   161  			require.Equal(t, count, n)
   162  		})
   163  	}
   164  }
   165  
   166  func TestHashIndexTS(t *testing.T) {
   167  	filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   168  	f, err := y.OpenSyncedFile(filename, true)
   169  	if t != nil {
   170  		require.NoError(t, err)
   171  	} else {
   172  		y.Check(err)
   173  	}
   174  	b := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
   175  	keys := []y.Key{
   176  		y.KeyWithTs([]byte("key"), 9),
   177  		y.KeyWithTs([]byte("key"), 7),
   178  		y.KeyWithTs([]byte("key"), 5),
   179  		y.KeyWithTs([]byte("key"), 3),
   180  		y.KeyWithTs([]byte("key"), 1),
   181  	}
   182  	for _, k := range keys {
   183  		b.Add(k, y.ValueStruct{Value: k.UserKey, Meta: 'A', UserMeta: []byte{0}})
   184  	}
   185  	y.Check(b.Finish())
   186  	f.Close()
   187  	table, err := OpenTable(filename, testCache(), testCache())
   188  	keyHash := farm.Fingerprint64([]byte("key"))
   189  
   190  	rk, _, ok, err := table.pointGet(y.KeyWithTs([]byte("key"), 10), keyHash)
   191  	require.NoError(t, err)
   192  	require.True(t, ok)
   193  	require.True(t, rk.Equal(keys[0]), "%s", string(rk.UserKey))
   194  
   195  	rk, _, ok, err = table.pointGet(y.KeyWithTs([]byte("key"), 6), keyHash)
   196  	require.NoError(t, err)
   197  	require.True(t, ok)
   198  	require.True(t, rk.Equal(keys[2]))
   199  
   200  	rk, _, ok, err = table.pointGet(y.KeyWithTs([]byte("key"), 2), keyHash)
   201  	require.NoError(t, err)
   202  	require.True(t, ok)
   203  	require.True(t, rk.Equal(keys[4]))
   204  }
   205  
   206  func TestPointGet(t *testing.T) {
   207  	f := buildTestTable(t, "key", 8000)
   208  	table, err := OpenTable(f.Name(), testCache(), testCache())
   209  	require.NoError(t, err)
   210  	defer table.Delete()
   211  
   212  	for i := 0; i < 8000; i++ {
   213  		k := y.KeyWithTs([]byte(key("key", i)), math.MaxUint64)
   214  		keyHash := farm.Fingerprint64(k.UserKey)
   215  		k1, _, ok, err := table.pointGet(k, keyHash)
   216  		require.NoError(t, err)
   217  		if !ok {
   218  			// will fallback to seek
   219  			continue
   220  		}
   221  		require.True(t, k1.SameUserKey(k), "point get not point to correct key")
   222  	}
   223  
   224  	for i := 8000; i < 10000; i++ {
   225  		k := y.KeyWithTs([]byte(key("key", i)), math.MaxUint64)
   226  		keyHash := farm.Fingerprint64(k.UserKey)
   227  		rk, _, ok, err := table.pointGet(k, keyHash)
   228  		require.NoError(t, err)
   229  		if !ok {
   230  			// will fallback to seek
   231  			continue
   232  		}
   233  		if rk.IsEmpty() {
   234  			// hash table says no entry, fast return
   235  			continue
   236  		}
   237  		require.False(t, k.SameUserKey(rk), "point get not point to correct key")
   238  	}
   239  }
   240  
   241  func TestExternalTable(t *testing.T) {
   242  	filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   243  	f, err := y.OpenSyncedFile(filename, true)
   244  	if t != nil {
   245  		require.NoError(t, err)
   246  	} else {
   247  		y.Check(err)
   248  	}
   249  
   250  	n := 200
   251  	b := NewExternalTableBuilder(f, rate.NewLimiter(rate.Inf, math.MaxInt32), defaultBuilderOpt, compressionType)
   252  	kvs := generateKeyValues("key", n)
   253  	for _, kv := range kvs {
   254  		y.Assert(len(kv) == 2)
   255  		err := b.Add(y.KeyWithTs([]byte(kv[0]), 0), y.ValueStruct{Value: []byte(kv[1]), Meta: 'A', UserMeta: []byte{0}})
   256  		if t != nil {
   257  			require.NoError(t, err)
   258  		} else {
   259  			y.Check(err)
   260  		}
   261  	}
   262  	y.Check(b.Finish())
   263  	f.Close()
   264  	table, err := OpenTable(filename, testCache(), testCache())
   265  	require.NoError(t, err)
   266  	require.NoError(t, table.SetGlobalTs(10))
   267  
   268  	require.NoError(t, table.Close())
   269  	table, err = OpenTable(filename, testCache(), testCache())
   270  	require.NoError(t, err)
   271  	defer table.Delete()
   272  
   273  	it := table.newIterator(false)
   274  	count := 0
   275  	for it.Rewind(); it.Valid(); it.Next() {
   276  		v := it.Value()
   277  		k := y.KeyWithTs([]byte(key("key", count)), 10)
   278  		require.EqualValues(t, k, it.Key())
   279  		require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value))
   280  		count++
   281  	}
   282  	require.Equal(t, count, n)
   283  }
   284  
   285  func TestSeekToFirst(t *testing.T) {
   286  	for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} {
   287  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   288  			f := buildTestTable(t, "key", n)
   289  			table, err := OpenTable(f.Name(), testCache(), testCache())
   290  			require.NoError(t, err)
   291  			defer table.Delete()
   292  			it := table.newIterator(false)
   293  			it.seekToFirst()
   294  			require.True(t, it.Valid())
   295  			v := it.Value()
   296  			require.EqualValues(t, "0", string(v.Value))
   297  			require.EqualValues(t, 'A', v.Meta)
   298  		})
   299  	}
   300  }
   301  
   302  func TestSeekToLast(t *testing.T) {
   303  	for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} {
   304  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   305  			f := buildTestTable(t, "key", n)
   306  			table, err := OpenTable(f.Name(), testCache(), testCache())
   307  			require.NoError(t, err)
   308  			defer table.Delete()
   309  			it := table.newIterator(false)
   310  			it.seekToLast()
   311  			require.True(t, it.Valid())
   312  			v := it.Value()
   313  			require.EqualValues(t, fmt.Sprintf("%d", n-1), string(v.Value))
   314  			require.EqualValues(t, 'A', v.Meta)
   315  			it.prev()
   316  			require.True(t, it.Valid())
   317  			v = it.Value()
   318  			require.EqualValues(t, fmt.Sprintf("%d", n-2), string(v.Value))
   319  			require.EqualValues(t, 'A', v.Meta)
   320  		})
   321  	}
   322  }
   323  
   324  func TestSeekBasic(t *testing.T) {
   325  	f := buildTestTable(t, "k", 10000)
   326  	table, err := OpenTable(f.Name(), testCache(), testCache())
   327  	require.NoError(t, err)
   328  	defer table.Delete()
   329  
   330  	it := table.newIterator(false)
   331  
   332  	var data = []struct {
   333  		in    string
   334  		valid bool
   335  		out   string
   336  	}{
   337  		{"abc", true, "k0000"},
   338  		{"k0100", true, "k0100"},
   339  		{"k0100b", true, "k0101"}, // Test case where we jump to next block.
   340  		{"k1234", true, "k1234"},
   341  		{"k1234b", true, "k1235"},
   342  		{"k9999", true, "k9999"},
   343  		{"z", false, ""},
   344  	}
   345  
   346  	for _, tt := range data {
   347  		it.seek([]byte(tt.in))
   348  		if !tt.valid {
   349  			require.False(t, it.Valid())
   350  			continue
   351  		}
   352  		require.True(t, it.Valid())
   353  		k := it.Key()
   354  		require.EqualValues(t, tt.out, string(k.UserKey))
   355  	}
   356  }
   357  
   358  func TestSeekForPrev(t *testing.T) {
   359  	f := buildTestTable(t, "k", 10000)
   360  	table, err := OpenTable(f.Name(), testCache(), testCache())
   361  	require.NoError(t, err)
   362  	defer table.Delete()
   363  
   364  	it := table.newIterator(false)
   365  
   366  	var data = []struct {
   367  		in    string
   368  		valid bool
   369  		out   string
   370  	}{
   371  		{"abc", false, ""},
   372  		{"k0100", true, "k0100"},
   373  		{"k0100b", true, "k0100"}, // Test case where we jump to next block.
   374  		{"k1234", true, "k1234"},
   375  		{"k1234b", true, "k1234"},
   376  		{"k9999", true, "k9999"},
   377  		{"z", true, "k9999"},
   378  	}
   379  
   380  	for _, tt := range data {
   381  		it.seekForPrev([]byte(tt.in))
   382  		if !tt.valid {
   383  			require.False(t, it.Valid())
   384  			continue
   385  		}
   386  		require.True(t, it.Valid())
   387  		k := it.Key()
   388  		require.EqualValues(t, tt.out, string(k.UserKey))
   389  	}
   390  }
   391  
   392  func TestIterateFromStart(t *testing.T) {
   393  	// Vary the number of elements added.
   394  	for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} {
   395  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   396  			f := buildTestTable(t, "key", n)
   397  			table, err := OpenTable(f.Name(), testCache(), testCache())
   398  			require.NoError(t, err)
   399  			defer table.Delete()
   400  			ti := table.newIterator(false)
   401  			ti.reset()
   402  			ti.seekToFirst()
   403  			require.True(t, ti.Valid())
   404  			// No need to do a Next.
   405  			// ti.Seek brings us to the first key >= "". Essentially a SeekToFirst.
   406  			var count int
   407  			for ; ti.Valid(); ti.next() {
   408  				v := ti.Value()
   409  				require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value))
   410  				require.EqualValues(t, 'A', v.Meta)
   411  				count++
   412  			}
   413  			require.EqualValues(t, n, count)
   414  		})
   415  	}
   416  }
   417  
   418  func TestIterateFromEnd(t *testing.T) {
   419  	// Vary the number of elements added.
   420  	for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} {
   421  		t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) {
   422  			f := buildTestTable(t, "key", n)
   423  			table, err := OpenTable(f.Name(), testCache(), testCache())
   424  			require.NoError(t, err)
   425  			defer table.Delete()
   426  			ti := table.newIterator(false)
   427  			ti.reset()
   428  			ti.seek([]byte("zzzzzz")) // Seek to end, an invalid element.
   429  			require.False(t, ti.Valid())
   430  			ti.seekToLast()
   431  			for i := n - 1; i >= 0; i-- {
   432  				require.True(t, ti.Valid())
   433  				v := ti.Value()
   434  				require.EqualValues(t, fmt.Sprintf("%d", i), string(v.Value))
   435  				require.EqualValues(t, 'A', v.Meta)
   436  				ti.prev()
   437  			}
   438  			ti.prev()
   439  			require.False(t, ti.Valid())
   440  		})
   441  	}
   442  }
   443  
   444  func TestTable(t *testing.T) {
   445  	f := buildTestTable(t, "key", 10000)
   446  	table, err := OpenTable(f.Name(), testCache(), testCache())
   447  	require.NoError(t, err)
   448  	defer table.Delete()
   449  	ti := table.newIterator(false)
   450  	kid := 1010
   451  	seek := y.KeyWithTs([]byte(key("key", kid)), 0)
   452  	for ti.seek(seek.UserKey); ti.Valid(); ti.next() {
   453  		k := ti.Key()
   454  		require.EqualValues(t, string(k.UserKey), key("key", kid))
   455  		kid++
   456  	}
   457  	if kid != 10000 {
   458  		t.Errorf("Expected kid: 10000. Got: %v", kid)
   459  	}
   460  
   461  	ti.seek([]byte(key("key", 99999)))
   462  	require.False(t, ti.Valid())
   463  
   464  	ti.seek([]byte(key("key", -1)))
   465  	require.True(t, ti.Valid())
   466  	k := ti.Key()
   467  	require.EqualValues(t, string(k.UserKey), key("key", 0))
   468  }
   469  
   470  func TestIterateBackAndForth(t *testing.T) {
   471  	f := buildTestTable(t, "key", 10000)
   472  	table, err := OpenTable(f.Name(), testCache(), testCache())
   473  	require.NoError(t, err)
   474  	defer table.Delete()
   475  
   476  	seek := y.KeyWithTs([]byte(key("key", 1010)), 0)
   477  	it := table.newIterator(false)
   478  	it.seek(seek.UserKey)
   479  	require.True(t, it.Valid())
   480  	k := it.Key()
   481  	require.EqualValues(t, seek, k)
   482  
   483  	it.prev()
   484  	it.prev()
   485  	require.True(t, it.Valid())
   486  	k = it.Key()
   487  	require.EqualValues(t, key("key", 1008), string(k.UserKey))
   488  
   489  	it.next()
   490  	it.next()
   491  	require.True(t, it.Valid())
   492  	k = it.Key()
   493  	require.EqualValues(t, key("key", 1010), k.UserKey)
   494  
   495  	it.seek([]byte(key("key", 2000)))
   496  	require.True(t, it.Valid())
   497  	k = it.Key()
   498  	require.EqualValues(t, key("key", 2000), k.UserKey)
   499  
   500  	it.prev()
   501  	require.True(t, it.Valid())
   502  	k = it.Key()
   503  	require.EqualValues(t, key("key", 1999), k.UserKey)
   504  
   505  	it.seekToFirst()
   506  	k = it.Key()
   507  	require.EqualValues(t, key("key", 0), k.UserKey)
   508  }
   509  
   510  func TestIterateMultiVersion(t *testing.T) {
   511  	f := buildMultiVersionTable(generateKeyValues("key", 4000))
   512  	table, err := OpenTable(f.Name(), testCache(), testCache())
   513  	require.NoError(t, err)
   514  	defer table.Delete()
   515  	it := table.newIterator(false)
   516  	var lastKey y.Key
   517  	for it.Rewind(); it.Valid(); it.Next() {
   518  		if !lastKey.IsEmpty() {
   519  			require.True(t, lastKey.Compare(it.Key()) < 0)
   520  		}
   521  		lastKey.Copy(it.Key())
   522  	}
   523  	for i := 0; i < 1000; i++ {
   524  		k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5))
   525  		kHash := farm.Fingerprint64(k.UserKey)
   526  		gotKey, _, ok, _ := table.pointGet(k, kHash)
   527  		if ok {
   528  			if !gotKey.IsEmpty() {
   529  				require.True(t, gotKey.SameUserKey(k))
   530  				require.True(t, gotKey.Compare(k) >= 0)
   531  			}
   532  		} else {
   533  			it.Seek(k.UserKey)
   534  			if it.Valid() {
   535  				require.True(t, it.Key().Version == 9)
   536  				require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) >= 0)
   537  				if y.SeekToVersion(it, k.Version) {
   538  					require.True(t, it.Key().Version <= k.Version)
   539  				}
   540  			}
   541  		}
   542  	}
   543  	revIt := table.newIterator(true)
   544  	lastKey.Reset()
   545  	for revIt.Rewind(); revIt.Valid(); revIt.Next() {
   546  		if !lastKey.IsEmpty() {
   547  			require.Truef(t, lastKey.Compare(revIt.Key()) > 0, "%v %v", lastKey.String(), revIt.Key().String())
   548  		}
   549  		lastKey.Copy(revIt.Key())
   550  	}
   551  	for i := 0; i < 1000; i++ {
   552  		k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5))
   553  		// reverse iterator never seek to the same key with smaller version.
   554  		revIt.Seek(k.UserKey)
   555  		if !revIt.Valid() {
   556  			continue
   557  		}
   558  		require.True(t, revIt.Key().Version == 9)
   559  		require.True(t, revIt.Key().Compare(k) <= 0, "%s %s", revIt.Key(), k)
   560  	}
   561  }
   562  
   563  func TestUniIterator(t *testing.T) {
   564  	f := buildTestTable(t, "key", 10000)
   565  	table, err := OpenTable(f.Name(), testCache(), testCache())
   566  	require.NoError(t, err)
   567  	defer table.Delete()
   568  	{
   569  		it := table.newIterator(false)
   570  		var count int
   571  		for it.Rewind(); it.Valid(); it.Next() {
   572  			v := it.Value()
   573  			require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value))
   574  			require.EqualValues(t, 'A', v.Meta)
   575  			count++
   576  		}
   577  		require.EqualValues(t, 10000, count)
   578  	}
   579  	{
   580  		it := table.newIterator(true)
   581  		var count int
   582  		for it.Rewind(); it.Valid(); it.Next() {
   583  			v := it.Value()
   584  			require.EqualValues(t, fmt.Sprintf("%d", 10000-1-count), string(v.Value))
   585  			require.EqualValues(t, 'A', v.Meta)
   586  			count++
   587  		}
   588  		require.EqualValues(t, 10000, count)
   589  	}
   590  }
   591  
   592  // Try having only one table.
   593  func TestConcatIteratorOneTable(t *testing.T) {
   594  	f := buildTable(t, [][]string{
   595  		{"k1", "a1"},
   596  		{"k2", "a2"},
   597  	})
   598  
   599  	tbl, err := OpenTable(f.Name(), testCache(), testCache())
   600  	require.NoError(t, err)
   601  	defer tbl.Delete()
   602  
   603  	it := table.NewConcatIterator([]table.Table{tbl}, false)
   604  
   605  	it.Rewind()
   606  	require.True(t, it.Valid())
   607  	k := it.Key()
   608  	require.EqualValues(t, "k1", string(k.UserKey))
   609  	vs := it.Value()
   610  	require.EqualValues(t, "a1", string(vs.Value))
   611  	require.EqualValues(t, 'A', vs.Meta)
   612  }
   613  
   614  func TestConcatIterator(t *testing.T) {
   615  	f := buildTestTable(t, "keya", 10000)
   616  	f2 := buildTestTable(t, "keyb", 10000)
   617  	f3 := buildTestTable(t, "keyc", 10000)
   618  	blkCache, idxCache := testCache(), testCache()
   619  	tbl, err := OpenTable(f.Name(), blkCache, idxCache)
   620  	require.NoError(t, err)
   621  	defer tbl.Delete()
   622  	tbl2, err := OpenTable(f2.Name(), blkCache, idxCache)
   623  	require.NoError(t, err)
   624  	defer tbl2.Delete()
   625  	tbl3, err := OpenTable(f3.Name(), blkCache, idxCache)
   626  	require.NoError(t, err)
   627  	defer tbl3.Delete()
   628  
   629  	{
   630  		it := table.NewConcatIterator([]table.Table{tbl, tbl2, tbl3}, false)
   631  		it.Rewind()
   632  		require.True(t, it.Valid())
   633  		var count int
   634  		for ; it.Valid(); it.Next() {
   635  			vs := it.Value()
   636  			require.EqualValues(t, fmt.Sprintf("%d", count%10000), string(vs.Value))
   637  			require.EqualValues(t, 'A', vs.Meta)
   638  			count++
   639  		}
   640  		require.EqualValues(t, 30000, count)
   641  
   642  		it.Seek([]byte("a"))
   643  		require.EqualValues(t, "keya0000", string(it.Key().UserKey))
   644  		vs := it.Value()
   645  		require.EqualValues(t, "0", string(vs.Value))
   646  
   647  		it.Seek([]byte("keyb"))
   648  		require.EqualValues(t, "keyb0000", string(it.Key().UserKey))
   649  		vs = it.Value()
   650  		require.EqualValues(t, "0", string(vs.Value))
   651  
   652  		it.Seek([]byte("keyb9999b"))
   653  		require.EqualValues(t, "keyc0000", string(it.Key().UserKey))
   654  		vs = it.Value()
   655  		require.EqualValues(t, "0", string(vs.Value))
   656  
   657  		it.Seek([]byte("keyd"))
   658  		require.False(t, it.Valid())
   659  	}
   660  	{
   661  		it := table.NewConcatIterator([]table.Table{tbl, tbl2, tbl3}, true)
   662  		it.Rewind()
   663  		require.True(t, it.Valid())
   664  		var count int
   665  		for ; it.Valid(); it.Next() {
   666  			vs := it.Value()
   667  			require.EqualValues(t, fmt.Sprintf("%d", 10000-(count%10000)-1), string(vs.Value))
   668  			require.EqualValues(t, 'A', vs.Meta)
   669  			count++
   670  		}
   671  		require.EqualValues(t, 30000, count)
   672  
   673  		it.Seek([]byte("a"))
   674  		require.False(t, it.Valid())
   675  
   676  		it.Seek([]byte("keyb"))
   677  		require.EqualValues(t, "keya9999", string(it.Key().UserKey))
   678  		vs := it.Value()
   679  		require.EqualValues(t, "9999", string(vs.Value))
   680  
   681  		it.Seek([]byte("keyb9999b"))
   682  		require.EqualValues(t, "keyb9999", string(it.Key().UserKey))
   683  		vs = it.Value()
   684  		require.EqualValues(t, "9999", string(vs.Value))
   685  
   686  		it.Seek([]byte("keyd"))
   687  		require.EqualValues(t, "keyc9999", string(it.Key().UserKey))
   688  		vs = it.Value()
   689  		require.EqualValues(t, "9999", string(vs.Value))
   690  	}
   691  }
   692  
   693  func TestMergingIterator(t *testing.T) {
   694  	f1 := buildTable(t, [][]string{
   695  		{"k1", "a1"},
   696  		{"k2", "a2"},
   697  	})
   698  	f2 := buildTable(t, [][]string{
   699  		{"k1", "b1"},
   700  		{"k2", "b2"},
   701  	})
   702  	blkCache, idxCache := testCache(), testCache()
   703  	tbl1, err := OpenTable(f1.Name(), blkCache, idxCache)
   704  	require.NoError(t, err)
   705  	defer tbl1.Delete()
   706  	tbl2, err := OpenTable(f2.Name(), blkCache, idxCache)
   707  	require.NoError(t, err)
   708  	defer tbl2.Delete()
   709  	it1 := tbl1.newIterator(false)
   710  	it2 := table.NewConcatIterator([]table.Table{tbl2}, false)
   711  	it := table.NewMergeIterator([]y.Iterator{it1, it2}, false)
   712  
   713  	it.Rewind()
   714  	require.True(t, it.Valid())
   715  	k := it.Key()
   716  	require.EqualValues(t, "k1", string(k.UserKey))
   717  	vs := it.Value()
   718  	require.EqualValues(t, "a1", string(vs.Value))
   719  	require.EqualValues(t, 'A', vs.Meta)
   720  	it.Next()
   721  
   722  	require.True(t, it.Valid())
   723  	k = it.Key()
   724  	require.EqualValues(t, "k2", string(k.UserKey))
   725  	vs = it.Value()
   726  	require.EqualValues(t, "a2", string(vs.Value))
   727  	require.EqualValues(t, 'A', vs.Meta)
   728  	it.Next()
   729  
   730  	require.False(t, it.Valid())
   731  }
   732  
   733  func TestMergingIteratorReversed(t *testing.T) {
   734  	f1 := buildTable(t, [][]string{
   735  		{"k1", "a1"},
   736  		{"k2", "a2"},
   737  	})
   738  	f2 := buildTable(t, [][]string{
   739  		{"k1", "b1"},
   740  		{"k2", "b2"},
   741  	})
   742  	blkCache, idxCache := testCache(), testCache()
   743  	tbl1, err := OpenTable(f1.Name(), blkCache, idxCache)
   744  	require.NoError(t, err)
   745  	defer tbl1.Delete()
   746  	tbl2, err := OpenTable(f2.Name(), blkCache, idxCache)
   747  	require.NoError(t, err)
   748  	defer tbl2.Delete()
   749  	it1 := tbl1.newIterator(true)
   750  	it2 := table.NewConcatIterator([]table.Table{tbl2}, true)
   751  	it := table.NewMergeIterator([]y.Iterator{it1, it2}, true)
   752  
   753  	it.Rewind()
   754  	require.True(t, it.Valid())
   755  	k := it.Key()
   756  	require.EqualValues(t, "k2", string(k.UserKey))
   757  	vs := it.Value()
   758  	require.EqualValues(t, "a2", string(vs.Value))
   759  	require.EqualValues(t, 'A', vs.Meta)
   760  	it.Next()
   761  
   762  	require.True(t, it.Valid())
   763  	k = it.Key()
   764  	require.EqualValues(t, "k1", string(k.UserKey))
   765  	vs = it.Value()
   766  	require.EqualValues(t, "a1", string(vs.Value))
   767  	require.EqualValues(t, 'A', vs.Meta)
   768  	it.Next()
   769  
   770  	require.False(t, it.Valid())
   771  }
   772  
   773  // Take only the first iterator.
   774  func TestMergingIteratorTakeOne(t *testing.T) {
   775  	f1 := buildTable(t, [][]string{
   776  		{"k1", "a1"},
   777  		{"k2", "a2"},
   778  	})
   779  	f2 := buildTable(t, [][]string{{"l1", "b1"}})
   780  
   781  	blkCache, idxCache := testCache(), testCache()
   782  	t1, err := OpenTable(f1.Name(), blkCache, idxCache)
   783  	require.NoError(t, err)
   784  	defer t1.Delete()
   785  	t2, err := OpenTable(f2.Name(), blkCache, idxCache)
   786  	require.NoError(t, err)
   787  	defer t2.Delete()
   788  
   789  	it1 := table.NewConcatIterator([]table.Table{t1}, false)
   790  	it2 := table.NewConcatIterator([]table.Table{t2}, false)
   791  	it := table.NewMergeIterator([]y.Iterator{it1, it2}, false)
   792  
   793  	it.Rewind()
   794  	require.True(t, it.Valid())
   795  	k := it.Key()
   796  	require.EqualValues(t, "k1", string(k.UserKey))
   797  	vs := it.Value()
   798  	require.EqualValues(t, "a1", string(vs.Value))
   799  	require.EqualValues(t, 'A', vs.Meta)
   800  	it.Next()
   801  
   802  	require.True(t, it.Valid())
   803  	k = it.Key()
   804  	require.EqualValues(t, "k2", string(k.UserKey))
   805  	vs = it.Value()
   806  	require.EqualValues(t, "a2", string(vs.Value))
   807  	require.EqualValues(t, 'A', vs.Meta)
   808  	it.Next()
   809  
   810  	k = it.Key()
   811  	require.EqualValues(t, "l1", string(k.UserKey))
   812  	vs = it.Value()
   813  	require.EqualValues(t, "b1", string(vs.Value))
   814  	require.EqualValues(t, 'A', vs.Meta)
   815  	it.Next()
   816  
   817  	require.False(t, it.Valid())
   818  }
   819  
   820  // Take only the second iterator.
   821  func TestMergingIteratorTakeTwo(t *testing.T) {
   822  	f1 := buildTable(t, [][]string{{"l1", "b1"}})
   823  	f2 := buildTable(t, [][]string{
   824  		{"k1", "a1"},
   825  		{"k2", "a2"},
   826  	})
   827  	blkCache, idxCache := testCache(), testCache()
   828  	t1, err := OpenTable(f1.Name(), blkCache, idxCache)
   829  	require.NoError(t, err)
   830  	defer t1.Delete()
   831  	t2, err := OpenTable(f2.Name(), blkCache, idxCache)
   832  	require.NoError(t, err)
   833  	defer t2.Delete()
   834  
   835  	it1 := table.NewConcatIterator([]table.Table{t1}, false)
   836  	it2 := table.NewConcatIterator([]table.Table{t2}, false)
   837  	it := table.NewMergeIterator([]y.Iterator{it1, it2}, false)
   838  
   839  	it.Rewind()
   840  	require.True(t, it.Valid())
   841  	k := it.Key()
   842  	require.EqualValues(t, "k1", string(k.UserKey))
   843  	vs := it.Value()
   844  	require.EqualValues(t, "a1", string(vs.Value))
   845  	require.EqualValues(t, 'A', vs.Meta)
   846  	it.Next()
   847  
   848  	require.True(t, it.Valid())
   849  	k = it.Key()
   850  	require.EqualValues(t, "k2", string(k.UserKey))
   851  	vs = it.Value()
   852  	require.EqualValues(t, "a2", string(vs.Value))
   853  	require.EqualValues(t, 'A', vs.Meta)
   854  	it.Next()
   855  	require.True(t, it.Valid())
   856  
   857  	k = it.Key()
   858  	require.EqualValues(t, "l1", string(k.UserKey))
   859  	vs = it.Value()
   860  	require.EqualValues(t, "b1", string(vs.Value))
   861  	require.EqualValues(t, 'A', vs.Meta)
   862  	it.Next()
   863  
   864  	require.False(t, it.Valid())
   865  }
   866  
   867  func BenchmarkRead(b *testing.B) {
   868  	n := 5 << 20
   869  	filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   870  	f, err := y.OpenSyncedFile(filename, true)
   871  	y.Check(err)
   872  	builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
   873  	for i := 0; i < n; i++ {
   874  		k := fmt.Sprintf("%016x", i)
   875  		v := fmt.Sprintf("%d", i)
   876  		y.Check(builder.Add(y.KeyWithTs([]byte(k), 0), y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}}))
   877  	}
   878  
   879  	y.Check(builder.Finish())
   880  	tbl, err := OpenTable(f.Name(), testCache(), testCache())
   881  	y.Check(err)
   882  	defer tbl.Delete()
   883  
   884  	//	y.Printf("Size of table: %d\n", tbl.Size())
   885  	b.ResetTimer()
   886  	// Iterate b.N times over the entire table.
   887  	for i := 0; i < b.N; i++ {
   888  		func() {
   889  			it := tbl.newIterator(false)
   890  			for it.seekToFirst(); it.Valid(); it.next() {
   891  			}
   892  		}()
   893  	}
   894  }
   895  
   896  func BenchmarkBuildTable(b *testing.B) {
   897  	ns := []int{1000, 10000, 100000, 1000000, 5000000, 10000000, 15000000}
   898  	for _, n := range ns {
   899  		kvs := make([]struct {
   900  			k y.Key
   901  			v []byte
   902  		}, n)
   903  		for i := 0; i < n; i++ {
   904  			kvs[i].k = y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0)
   905  			kvs[i].v = []byte(fmt.Sprintf("%d", i))
   906  		}
   907  		b.ResetTimer()
   908  
   909  		b.Run(fmt.Sprintf("NoHash_%d", n), func(b *testing.B) {
   910  			filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   911  			f, err := y.OpenSyncedFile(filename, false)
   912  			y.Check(err)
   913  			opt := defaultBuilderOpt
   914  			for bn := 0; bn < b.N; bn++ {
   915  				builder := NewTableBuilder(f, nil, 0, opt)
   916  				for i := 0; i < n; i++ {
   917  					y.Check(builder.Add(kvs[i].k, y.ValueStruct{Value: kvs[i].v, Meta: 123, UserMeta: []byte{0}}))
   918  				}
   919  				y.Check(builder.Finish())
   920  				_, err := f.Seek(0, io.SeekStart)
   921  				y.Check(err)
   922  			}
   923  		})
   924  
   925  		b.Run(fmt.Sprintf("Hash_%d", n), func(b *testing.B) {
   926  			filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   927  			f, err := y.OpenSyncedFile(filename, false)
   928  			y.Check(err)
   929  			for bn := 0; bn < b.N; bn++ {
   930  				builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
   931  				for i := 0; i < n; i++ {
   932  					y.Check(builder.Add(kvs[i].k, y.ValueStruct{Value: kvs[i].v, Meta: 123, UserMeta: []byte{0}}))
   933  				}
   934  				y.Check(builder.Finish())
   935  				_, err := f.Seek(0, io.SeekStart)
   936  				y.Check(err)
   937  			}
   938  		})
   939  	}
   940  }
   941  
   942  var cacheConfig = cache.Config{
   943  	NumCounters: 1000000 * 10,
   944  	MaxCost:     1000000,
   945  	BufferItems: 64,
   946  	Metrics:     true,
   947  }
   948  
   949  func BenchmarkPointGet(b *testing.B) {
   950  	ns := []int{1000, 10000, 100000, 1000000, 5000000, 10000000, 15000000}
   951  	for _, n := range ns {
   952  		filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
   953  		f, err := y.OpenSyncedFile(filename, true)
   954  		builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
   955  		keys := make([]y.Key, n)
   956  		y.Check(err)
   957  		for i := 0; i < n; i++ {
   958  			k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0)
   959  			v := fmt.Sprintf("%d", i)
   960  			keys[i] = k
   961  			y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}}))
   962  		}
   963  
   964  		y.Check(builder.Finish())
   965  		tbl, err := OpenTable(filename, testCache(), testCache())
   966  		y.Check(err)
   967  		b.ResetTimer()
   968  
   969  		b.Run(fmt.Sprintf("Seek_%d", n), func(b *testing.B) {
   970  			var vs y.ValueStruct
   971  			rand := rand.New(rand.NewSource(0))
   972  			for bn := 0; bn < b.N; bn++ {
   973  				rand.Seed(0)
   974  				for i := 0; i < n; i++ {
   975  					k := keys[rand.Intn(n)]
   976  					it := tbl.newIterator(false)
   977  					it.Seek(k.UserKey)
   978  					if !it.Valid() {
   979  						continue
   980  					}
   981  					if !k.SameUserKey(it.Key()) {
   982  						continue
   983  					}
   984  					vs = it.Value()
   985  				}
   986  			}
   987  			_ = vs
   988  		})
   989  
   990  		b.Run(fmt.Sprintf("Hash_%d", n), func(b *testing.B) {
   991  			var (
   992  				resultKey y.Key
   993  				resultVs  y.ValueStruct
   994  				ok        bool
   995  			)
   996  			rand := rand.New(rand.NewSource(0))
   997  			for bn := 0; bn < b.N; bn++ {
   998  				rand.Seed(0)
   999  				for i := 0; i < n; i++ {
  1000  					k := keys[rand.Intn(n)]
  1001  					keyHash := farm.Fingerprint64(k.UserKey)
  1002  					resultKey, resultVs, ok, _ = tbl.pointGet(k, keyHash)
  1003  					if !ok {
  1004  						it := tbl.newIterator(false)
  1005  						it.Seek(k.UserKey)
  1006  						if !it.Valid() {
  1007  							continue
  1008  						}
  1009  						if !k.SameUserKey(it.Key()) {
  1010  							continue
  1011  						}
  1012  						resultKey, resultVs = it.Key(), it.Value()
  1013  					}
  1014  				}
  1015  			}
  1016  			_, _ = resultKey, resultVs
  1017  		})
  1018  
  1019  		tbl.Delete()
  1020  	}
  1021  }
  1022  
  1023  func BenchmarkReadAndBuild(b *testing.B) {
  1024  	n := 5 << 20
  1025  	filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
  1026  	f, err := y.OpenSyncedFile(filename, false)
  1027  	builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
  1028  	y.Check(err)
  1029  	for i := 0; i < n; i++ {
  1030  		k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0)
  1031  		v := fmt.Sprintf("%d", i)
  1032  		y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}}))
  1033  	}
  1034  
  1035  	y.Check(builder.Finish())
  1036  	tbl, err := OpenTable(f.Name(), testCache(), testCache())
  1037  	y.Check(err)
  1038  	defer tbl.Delete()
  1039  
  1040  	//	y.Printf("Size of table: %d\n", tbl.Size())
  1041  	b.ResetTimer()
  1042  	// Iterate b.N times over the entire table.
  1043  	filename = fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
  1044  	f, err = y.OpenSyncedFile(filename, false)
  1045  	y.Check(err)
  1046  	for i := 0; i < b.N; i++ {
  1047  		func() {
  1048  			newBuilder := NewTableBuilder(f, nil, 0, options.TableBuilderOptions{})
  1049  			it := tbl.newIterator(false)
  1050  			for it.seekToFirst(); it.Valid(); it.next() {
  1051  				vs := it.Value()
  1052  				newBuilder.Add(it.Key(), vs)
  1053  			}
  1054  			y.Check(newBuilder.Finish())
  1055  			_, err := f.Seek(0, io.SeekStart)
  1056  			y.Check(err)
  1057  		}()
  1058  	}
  1059  }
  1060  
  1061  func BenchmarkReadMerged(b *testing.B) {
  1062  	n := 5 << 20
  1063  	m := 5 // Number of tables.
  1064  	y.Assert((n % m) == 0)
  1065  	tableSize := n / m
  1066  	var tables []*Table
  1067  
  1068  	for i := 0; i < m; i++ {
  1069  		filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
  1070  		f, err := y.OpenSyncedFile(filename, true)
  1071  		y.Check(err)
  1072  		builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
  1073  		for j := 0; j < tableSize; j++ {
  1074  			id := j*m + i // Arrays are interleaved.
  1075  			// id := i*tableSize+j (not interleaved)
  1076  			k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", id)), 0)
  1077  			v := fmt.Sprintf("%d", id)
  1078  			y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}}))
  1079  		}
  1080  		y.Check(builder.Finish())
  1081  		tbl, err := OpenTable(f.Name(), testCache(), testCache())
  1082  		y.Check(err)
  1083  		tables = append(tables, tbl)
  1084  		defer tbl.Delete()
  1085  	}
  1086  
  1087  	b.ResetTimer()
  1088  	// Iterate b.N times over the entire table.
  1089  	for i := 0; i < b.N; i++ {
  1090  		func() {
  1091  			var iters []y.Iterator
  1092  			for _, tbl := range tables {
  1093  				iters = append(iters, tbl.newIterator(false))
  1094  			}
  1095  			it := table.NewMergeIterator(iters, false)
  1096  			for it.Rewind(); it.Valid(); it.Next() {
  1097  			}
  1098  		}()
  1099  	}
  1100  }
  1101  
  1102  func BenchmarkRandomRead(b *testing.B) {
  1103  	n := int(5 * 1e6)
  1104  	tbl := getTableForBenchmarks(b, n, testCache(), testCache())
  1105  
  1106  	r := rand.New(rand.NewSource(time.Now().Unix()))
  1107  
  1108  	b.ResetTimer()
  1109  	for i := 0; i < b.N; i++ {
  1110  		itr := tbl.newIterator(false)
  1111  		no := r.Intn(n)
  1112  		k := []byte(fmt.Sprintf("%016x", no))
  1113  		v := []byte(fmt.Sprintf("%d", no))
  1114  		itr.Seek(k)
  1115  		if !itr.Valid() {
  1116  			b.Fatal("itr should be valid")
  1117  		}
  1118  		v1 := itr.Value().Value
  1119  
  1120  		if !bytes.Equal(v, v1) {
  1121  			fmt.Println("value does not match")
  1122  			b.Fatal()
  1123  		}
  1124  	}
  1125  }
  1126  
  1127  func getTableForBenchmarks(b *testing.B, count int, blkCache, idxCache *cache.Cache) *Table {
  1128  	rand.Seed(time.Now().Unix())
  1129  	filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32())
  1130  	f, err := y.OpenSyncedFile(filename, false)
  1131  	builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt)
  1132  	require.NoError(b, err)
  1133  	for i := 0; i < count; i++ {
  1134  		k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0)
  1135  		v := fmt.Sprintf("%d", i)
  1136  		builder.Add(k, y.ValueStruct{Value: []byte(v)})
  1137  	}
  1138  
  1139  	err = builder.Finish()
  1140  	require.NoError(b, err, "unable to write to file")
  1141  	tbl, err := OpenTable(f.Name(), blkCache, idxCache)
  1142  	require.NoError(b, err, "unable to open table")
  1143  	return tbl
  1144  }
  1145  
  1146  func TestMain(m *testing.M) {
  1147  	rand.Seed(time.Now().UTC().UnixNano())
  1148  	os.Exit(m.Run())
  1149  }