github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/simulation_test.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 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 package bdb_test 16 17 import ( 18 "bytes" 19 "fmt" 20 "math/rand" 21 "sync" 22 "sync/atomic" 23 "testing" 24 25 "github.com/cockroachdb/errors" 26 "github.com/zuoyebang/bitalosdb/bitree/bdb" 27 "github.com/zuoyebang/bitalosdb/internal/options" 28 ) 29 30 func TestSimulate_1op_1p(t *testing.T) { testSimulate(t, nil, 1, 1, 1) } 31 func TestSimulate_10op_1p(t *testing.T) { testSimulate(t, nil, 1, 10, 1) } 32 func TestSimulate_100op_1p(t *testing.T) { testSimulate(t, nil, 1, 100, 1) } 33 func TestSimulate_1000op_1p(t *testing.T) { testSimulate(t, nil, 1, 1000, 1) } 34 func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, nil, 1, 10000, 1) } 35 36 func TestSimulate_10op_10p(t *testing.T) { testSimulate(t, nil, 1, 10, 10) } 37 func TestSimulate_100op_10p(t *testing.T) { testSimulate(t, nil, 1, 100, 10) } 38 func TestSimulate_1000op_10p(t *testing.T) { testSimulate(t, nil, 1, 1000, 10) } 39 func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, nil, 1, 10000, 10) } 40 41 func TestSimulate_100op_100p(t *testing.T) { testSimulate(t, nil, 1, 100, 100) } 42 func TestSimulate_1000op_100p(t *testing.T) { testSimulate(t, nil, 1, 1000, 100) } 43 func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, nil, 1, 10000, 100) } 44 45 func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, nil, 1, 10000, 1000) } 46 47 func testSimulate(t *testing.T, openOption *options.BdbOptions, round, threadCount, parallelism int) { 48 if testing.Short() { 49 t.Skip("skipping test in short mode.") 50 } 51 52 rand.Seed(int64(qseed)) 53 54 var readerHandlers = []simulateHandler{simulateGetHandler} 55 var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler} 56 57 var versions = make(map[int]*QuickDB) 58 versions[1] = NewQuickDB() 59 60 db := MustOpenWithOption(openOption) 61 defer db.MustClose() 62 63 var mutex sync.Mutex 64 65 for n := 0; n < round; n++ { 66 var threads = make(chan bool, parallelism) 67 var wg sync.WaitGroup 68 69 var opCount int64 70 71 var igCount int64 72 73 var errCh = make(chan error, threadCount) 74 75 var i int 76 for { 77 threads <- true 78 wg.Add(1) 79 writable := ((rand.Int() % 100) < 20) 80 var handler simulateHandler 81 if writable { 82 handler = writerHandlers[rand.Intn(len(writerHandlers))] 83 } else { 84 handler = readerHandlers[rand.Intn(len(readerHandlers))] 85 } 86 87 go func(writable bool, handler simulateHandler) { 88 defer wg.Done() 89 atomic.AddInt64(&opCount, 1) 90 tx, err := db.Begin(writable) 91 if err != nil { 92 errCh <- errors.Errorf("error tx begin: %v", err) 93 return 94 } 95 96 mutex.Lock() 97 var qdb = versions[tx.ID()] 98 if writable { 99 qdb = versions[tx.ID()-1].Copy() 100 } 101 mutex.Unlock() 102 103 if writable { 104 defer func() { 105 mutex.Lock() 106 versions[tx.ID()] = qdb 107 mutex.Unlock() 108 109 if err := tx.Commit(); err != nil { 110 errCh <- err 111 return 112 } 113 }() 114 } else { 115 defer func() { _ = tx.Rollback() }() 116 } 117 118 if qdb == nil { 119 atomic.AddInt64(&igCount, 1) 120 return 121 } 122 123 handler(tx, qdb) 124 125 <-threads 126 }(writable, handler) 127 128 i++ 129 if i >= threadCount { 130 break 131 } 132 } 133 134 wg.Wait() 135 close(errCh) 136 for err := range errCh { 137 if err != nil { 138 t.Fatalf("error from inside goroutine: %v", err) 139 } 140 } 141 142 db.MustClose() 143 db.MustReopen() 144 } 145 146 } 147 148 type simulateHandler func(tx *bdb.Tx, qdb *QuickDB) 149 150 func simulateGetHandler(tx *bdb.Tx, qdb *QuickDB) { 151 keys := qdb.Rand() 152 if len(keys) == 0 { 153 return 154 } 155 156 b := tx.Bucket(keys[0]) 157 if b == nil { 158 panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4))) 159 } 160 161 for _, key := range keys[1 : len(keys)-1] { 162 b = b.Bucket(key) 163 if b == nil { 164 panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key)) 165 } 166 } 167 168 expected := qdb.Get(keys) 169 actual := b.Get(keys[len(keys)-1]) 170 if !bytes.Equal(actual, expected) { 171 fmt.Println("=== EXPECTED ===") 172 fmt.Println(expected) 173 fmt.Println("=== ACTUAL ===") 174 fmt.Println(actual) 175 fmt.Println("=== END ===") 176 panic("value mismatch") 177 } 178 } 179 180 func simulatePutHandler(tx *bdb.Tx, qdb *QuickDB) { 181 var err error 182 keys, value := randKeys(), randValue() 183 184 b := tx.Bucket(keys[0]) 185 if b == nil { 186 b, err = tx.CreateBucket(keys[0]) 187 if err != nil { 188 panic("create bucket: " + err.Error()) 189 } 190 } 191 192 for _, key := range keys[1 : len(keys)-1] { 193 child := b.Bucket(key) 194 if child != nil { 195 b = child 196 } else { 197 b, err = b.CreateBucket(key) 198 if err != nil { 199 panic("create bucket: " + err.Error()) 200 } 201 } 202 } 203 204 if err := b.Put(keys[len(keys)-1], value); err != nil { 205 panic("put: " + err.Error()) 206 } 207 208 qdb.Put(keys, value) 209 } 210 211 type QuickDB struct { 212 sync.RWMutex 213 m map[string]interface{} 214 } 215 216 func NewQuickDB() *QuickDB { 217 return &QuickDB{m: make(map[string]interface{})} 218 } 219 220 func (db *QuickDB) Get(keys [][]byte) []byte { 221 db.RLock() 222 defer db.RUnlock() 223 224 m := db.m 225 for _, key := range keys[:len(keys)-1] { 226 value := m[string(key)] 227 if value == nil { 228 return nil 229 } 230 switch value := value.(type) { 231 case map[string]interface{}: 232 m = value 233 case []byte: 234 return nil 235 } 236 } 237 238 if value, ok := m[string(keys[len(keys)-1])].([]byte); ok { 239 return value 240 } 241 return nil 242 } 243 244 func (db *QuickDB) Put(keys [][]byte, value []byte) { 245 db.Lock() 246 defer db.Unlock() 247 248 m := db.m 249 for _, key := range keys[:len(keys)-1] { 250 if _, ok := m[string(key)].([]byte); ok { 251 return 252 } 253 254 if m[string(key)] == nil { 255 m[string(key)] = make(map[string]interface{}) 256 } 257 m = m[string(key)].(map[string]interface{}) 258 } 259 260 m[string(keys[len(keys)-1])] = value 261 } 262 263 func (db *QuickDB) Rand() [][]byte { 264 db.RLock() 265 defer db.RUnlock() 266 if len(db.m) == 0 { 267 return nil 268 } 269 var keys [][]byte 270 db.rand(db.m, &keys) 271 return keys 272 } 273 274 func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) { 275 i, index := 0, rand.Intn(len(m)) 276 for k, v := range m { 277 if i == index { 278 *keys = append(*keys, []byte(k)) 279 if v, ok := v.(map[string]interface{}); ok { 280 db.rand(v, keys) 281 } 282 return 283 } 284 i++ 285 } 286 panic("quickdb rand: out-of-range") 287 } 288 289 func (db *QuickDB) Copy() *QuickDB { 290 db.RLock() 291 defer db.RUnlock() 292 return &QuickDB{m: db.copy(db.m)} 293 } 294 295 func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} { 296 clone := make(map[string]interface{}, len(m)) 297 for k, v := range m { 298 switch v := v.(type) { 299 case map[string]interface{}: 300 clone[k] = db.copy(v) 301 default: 302 clone[k] = v 303 } 304 } 305 return clone 306 } 307 308 func randKey() []byte { 309 var min, max = 1, 1024 310 n := rand.Intn(max-min) + min 311 b := make([]byte, n) 312 for i := 0; i < n; i++ { 313 b[i] = byte(rand.Intn(255)) 314 } 315 return b 316 } 317 318 func randKeys() [][]byte { 319 var keys [][]byte 320 var count = rand.Intn(2) + 2 321 for i := 0; i < count; i++ { 322 keys = append(keys, randKey()) 323 } 324 return keys 325 } 326 327 func randValue() []byte { 328 n := rand.Intn(8192) 329 b := make([]byte, n) 330 for i := 0; i < n; i++ { 331 b[i] = byte(rand.Intn(255)) 332 } 333 return b 334 }