github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/unionstore/memdb_norace_test.go (about)

     1  // Copyright 2021 TiKV Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // NOTE: The code in this file is based on code from the
    16  // TiDB project, licensed under the Apache License v 2.0
    17  //
    18  // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/unionstore/memdb_norace_test.go
    19  //
    20  
    21  // Copyright 2020 PingCAP, Inc.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //
    27  //     http://www.apache.org/licenses/LICENSE-2.0
    28  //
    29  // Unless required by applicable law or agreed to in writing, software
    30  // distributed under the License is distributed on an "AS IS" BASIS,
    31  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    32  // See the License for the specific language governing permissions and
    33  // limitations under the License.
    34  
    35  // +build !race
    36  
    37  package unionstore
    38  
    39  import (
    40  	"encoding/binary"
    41  	"math/rand"
    42  	"testing"
    43  
    44  	"github.com/pingcap/goleveldb/leveldb/comparer"
    45  	leveldb "github.com/pingcap/goleveldb/leveldb/memdb"
    46  	"github.com/stretchr/testify/require"
    47  )
    48  
    49  // The test takes too long under the race detector.
    50  func TestRandom(t *testing.T) {
    51  	require := require.New(t)
    52  
    53  	const cnt = 50000
    54  	keys := make([][]byte, cnt)
    55  	for i := range keys {
    56  		keys[i] = make([]byte, rand.Intn(19)+1)
    57  		rand.Read(keys[i])
    58  	}
    59  
    60  	p1 := newMemDB()
    61  	p2 := leveldb.New(comparer.DefaultComparer, 4*1024)
    62  	for _, k := range keys {
    63  		p1.Set(k, k)
    64  		_ = p2.Put(k, k)
    65  	}
    66  
    67  	require.Equal(p1.Len(), p2.Len())
    68  	require.Equal(p1.Size(), p2.Size())
    69  
    70  	rand.Shuffle(cnt, func(i, j int) { keys[i], keys[j] = keys[j], keys[i] })
    71  
    72  	for _, k := range keys {
    73  		op := rand.Float64()
    74  		if op < 0.35 {
    75  			p1.DeleteKey(k)
    76  			p2.Delete(k)
    77  		} else {
    78  			newValue := make([]byte, rand.Intn(19)+1)
    79  			rand.Read(newValue)
    80  			p1.Set(k, newValue)
    81  			_ = p2.Put(k, newValue)
    82  		}
    83  	}
    84  	checkConsist(t, p1, p2)
    85  }
    86  
    87  // The test takes too long under the race detector.
    88  func TestRandomDerive(t *testing.T) {
    89  	db := newMemDB()
    90  	golden := leveldb.New(comparer.DefaultComparer, 4*1024)
    91  	testRandomDeriveRecur(t, db, golden, 0)
    92  }
    93  
    94  func testRandomDeriveRecur(t *testing.T, db *MemDB, golden *leveldb.DB, depth int) [][2][]byte {
    95  	var keys [][]byte
    96  	if op := rand.Float64(); op < 0.33 {
    97  		start, end := rand.Intn(512), rand.Intn(512)+512
    98  		cnt := end - start
    99  		keys = make([][]byte, cnt)
   100  		for i := range keys {
   101  			keys[i] = make([]byte, 8)
   102  			binary.BigEndian.PutUint64(keys[i], uint64(start+i))
   103  		}
   104  	} else if op < 0.66 {
   105  		keys = make([][]byte, rand.Intn(512)+512)
   106  		for i := range keys {
   107  			keys[i] = make([]byte, rand.Intn(19)+1)
   108  			rand.Read(keys[i])
   109  		}
   110  	} else {
   111  		keys = make([][]byte, 512)
   112  		for i := range keys {
   113  			keys[i] = make([]byte, 8)
   114  			binary.BigEndian.PutUint64(keys[i], uint64(i))
   115  		}
   116  	}
   117  
   118  	vals := make([][]byte, len(keys))
   119  	for i := range vals {
   120  		vals[i] = make([]byte, rand.Intn(255)+1)
   121  		rand.Read(vals[i])
   122  	}
   123  
   124  	h := db.Staging()
   125  	opLog := make([][2][]byte, 0, len(keys))
   126  	for i := range keys {
   127  		db.Set(keys[i], vals[i])
   128  		old, err := golden.Get(keys[i])
   129  		if err != nil {
   130  			opLog = append(opLog, [2][]byte{keys[i], nil})
   131  		} else {
   132  			opLog = append(opLog, [2][]byte{keys[i], old})
   133  		}
   134  		golden.Put(keys[i], vals[i])
   135  	}
   136  
   137  	if depth < 100 {
   138  		childOps := testRandomDeriveRecur(t, db, golden, depth+1)
   139  		opLog = append(opLog, childOps...)
   140  	}
   141  
   142  	if rand.Float64() < 0.3 && depth > 0 {
   143  		db.Cleanup(h)
   144  		for i := len(opLog) - 1; i >= 0; i-- {
   145  			if opLog[i][1] == nil {
   146  				golden.Delete(opLog[i][0])
   147  			} else {
   148  				golden.Put(opLog[i][0], opLog[i][1])
   149  			}
   150  		}
   151  		opLog = nil
   152  	} else {
   153  		db.Release(h)
   154  	}
   155  
   156  	if depth%10 == 0 {
   157  		checkConsist(t, db, golden)
   158  	}
   159  
   160  	return opLog
   161  }