github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/storage/mem/kv_txn_storage_test.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 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 mem 16 17 import ( 18 "bytes" 19 "context" 20 "math" 21 "sync/atomic" 22 "testing" 23 24 "github.com/google/uuid" 25 "github.com/matrixorigin/matrixone/pkg/common/moerr" 26 "github.com/matrixorigin/matrixone/pkg/logservice" 27 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 28 "github.com/matrixorigin/matrixone/pkg/pb/txn" 29 "github.com/matrixorigin/matrixone/pkg/txn/clock" 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func TestWrite(t *testing.T) { 34 l := NewMemLog() 35 s := NewKVTxnStorage(0, l, newTestClock(1)) 36 37 wTxn := writeTestData(t, s, 1, moerr.Ok, 1, 2) 38 checkUncommitted(t, s, wTxn, 1, 2) 39 checkLogCount(t, l, 0) 40 } 41 42 func TestWriteWithConflict(t *testing.T) { 43 l := NewMemLog() 44 s := NewKVTxnStorage(0, l, newTestClock(1)) 45 46 wTxn1 := writeTestData(t, s, 1, moerr.Ok, 1) 47 checkUncommitted(t, s, wTxn1, 1) 48 49 writeTestData(t, s, 1, moerr.ErrTxnWriteConflict, 1) 50 51 wTxn3 := writeTestData(t, s, 1, moerr.Ok, 2) 52 checkUncommitted(t, s, wTxn3, 2) 53 } 54 55 func TestPrepare(t *testing.T) { 56 l := NewMemLog() 57 s := NewKVTxnStorage(0, l, newTestClock(1)) 58 59 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 60 61 prepareTestTxn(t, s, &wTxn, 2, moerr.Ok) 62 63 checkUncommitted(t, s, wTxn, 1) 64 checkLogCount(t, l, 1) 65 checkLog(t, l, 1, wTxn, 1) 66 } 67 68 func TestPrepareWithConflict(t *testing.T) { 69 l := NewMemLog() 70 s := NewKVTxnStorage(0, l, newTestClock(1)) 71 72 writeCommittedData(t, s, 1, 100, 1) // commit at 100 73 74 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 75 prepareTestTxn(t, s, &wTxn, 5, moerr.ErrTxnWriteConflict) // prepare at 5 76 } 77 78 func TestCommit(t *testing.T) { 79 l := NewMemLog() 80 s := NewKVTxnStorage(0, l, newTestClock(1)) 81 82 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 83 commitTestTxn(t, s, &wTxn, 2, moerr.Ok) 84 85 checkCommitted(t, s, wTxn, 1) 86 checkLogCount(t, l, 1) 87 checkLog(t, l, 1, wTxn, 1) 88 } 89 90 func TestCommitWithTxnNotExist(t *testing.T) { 91 l := NewMemLog() 92 s := NewKVTxnStorage(0, l, newTestClock(1)) 93 94 commitTestTxn(t, s, &txn.TxnMeta{}, 2, moerr.Ok) 95 } 96 97 func TestCommitWithConflict(t *testing.T) { 98 l := NewMemLog() 99 s := NewKVTxnStorage(0, l, newTestClock(1)) 100 101 writeCommittedData(t, s, 1, 2, 1) 102 103 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 104 commitTestTxn(t, s, &wTxn, 5, moerr.ErrTxnWriteConflict) 105 } 106 107 func TestCommitAfterPrepared(t *testing.T) { 108 l := NewMemLog() 109 s := NewKVTxnStorage(0, l, newTestClock(1)) 110 111 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 112 prepareTestTxn(t, s, &wTxn, 2, moerr.Ok) 113 commitTestTxn(t, s, &wTxn, 3, moerr.Ok) 114 115 checkCommitted(t, s, wTxn, 1) 116 checkLogCount(t, l, 2) 117 checkLog(t, l, 2, wTxn) 118 } 119 120 func TestRollback(t *testing.T) { 121 l := NewMemLog() 122 s := NewKVTxnStorage(0, l, newTestClock(1)) 123 124 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 125 checkUncommitted(t, s, wTxn, 1) 126 127 assert.NoError(t, s.Rollback(context.TODO(), wTxn)) 128 checkRollback(t, s, wTxn, 1) 129 } 130 131 func TestRollbackWithTxnNotExist(t *testing.T) { 132 l := NewMemLog() 133 s := NewKVTxnStorage(0, l, newTestClock(1)) 134 135 assert.NoError(t, s.Rollback(context.TODO(), txn.TxnMeta{})) 136 checkRollback(t, s, txn.TxnMeta{}) 137 } 138 139 func TestReadCommittedWithLessVersion(t *testing.T) { 140 l := NewMemLog() 141 s := NewKVTxnStorage(0, l, newTestClock(1)) 142 143 writeCommittedData(t, s, 0, 1, 1) 144 145 _, rs := readTestData(t, s, 2, nil, 1) 146 checkReadResult(t, 0, rs, 1) 147 } 148 149 func TestReadSelfUncommitted(t *testing.T) { 150 l := NewMemLog() 151 s := NewKVTxnStorage(0, l, newTestClock(1)) 152 153 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 154 rs := readTestDataWithTxn(t, s, &wTxn, nil, 1) 155 checkReadResult(t, 1, rs, 1) 156 } 157 158 func TestReadCommittedWithGTVersion(t *testing.T) { 159 l := NewMemLog() 160 s := NewKVTxnStorage(0, l, newTestClock(1)) 161 162 writeCommittedData(t, s, 0, 1, 1) 163 164 _, rs := readTestData(t, s, 1, nil, 1) 165 checkReadResult(t, 0, rs, 0) 166 } 167 168 func TestWaitReadByPreparedTxn(t *testing.T) { 169 l := NewMemLog() 170 s := NewKVTxnStorage(0, l, newTestClock(1)) 171 172 writeCommittedData(t, s, 0, 1, 1) 173 174 wTxn := writeTestData(t, s, 2, moerr.Ok, 1) 175 prepareTestTxn(t, s, &wTxn, 5, moerr.Ok) 176 177 readTestData(t, s, 6, [][]byte{wTxn.ID}, 1) 178 } 179 180 func TestReadByGTPreparedTxnCanNotWait(t *testing.T) { 181 l := NewMemLog() 182 s := NewKVTxnStorage(0, l, newTestClock(1)) 183 184 writeCommittedData(t, s, 0, 1, 1) 185 186 wTxn := writeTestData(t, s, 2, moerr.Ok, 1) 187 prepareTestTxn(t, s, &wTxn, 5, moerr.Ok) 188 189 readTestData(t, s, 2, nil, 1) 190 } 191 192 func TestWaitReadByCommittingTxn(t *testing.T) { 193 l := NewMemLog() 194 s := NewKVTxnStorage(0, l, newTestClock(1)) 195 196 writeCommittedData(t, s, 0, 1, 1) 197 198 wTxn := writeTestData(t, s, 2, moerr.Ok, 1) 199 prepareTestTxn(t, s, &wTxn, 5, moerr.Ok) 200 committingTestTxn(t, s, &wTxn, 6) 201 202 readTestData(t, s, 7, [][]byte{wTxn.ID}, 1) 203 } 204 205 func TestReadByGTCommittingTxnCanNotWait(t *testing.T) { 206 l := NewMemLog() 207 s := NewKVTxnStorage(0, l, newTestClock(1)) 208 209 writeCommittedData(t, s, 0, 1, 1) 210 211 wTxn := writeTestData(t, s, 2, moerr.Ok, 1) 212 prepareTestTxn(t, s, &wTxn, 3, moerr.Ok) 213 committingTestTxn(t, s, &wTxn, 4) 214 215 readTestData(t, s, 3, nil, 1) 216 } 217 218 func TestReadAfterWaitTxnResloved(t *testing.T) { 219 l := NewMemLog() 220 s := NewKVTxnStorage(0, l, newTestClock(1)) 221 222 wTxn1 := writeTestData(t, s, 1, moerr.Ok, 1) 223 prepareTestTxn(t, s, &wTxn1, 2, moerr.Ok) 224 225 wTxn2 := writeTestData(t, s, 1, moerr.Ok, 2) 226 prepareTestTxn(t, s, &wTxn2, 2, moerr.Ok) 227 228 _, rs := readTestData(t, s, 5, [][]byte{wTxn1.ID, wTxn2.ID}, 1, 2) 229 _, err := rs.Read() 230 assert.True(t, moerr.IsMoErrCode(err, moerr.ErrMissingTxn)) 231 232 commitTestTxn(t, s, &wTxn2, 6, moerr.Ok) 233 _, err = rs.Read() 234 assert.True(t, moerr.IsMoErrCode(err, moerr.ErrMissingTxn)) 235 236 commitTestTxn(t, s, &wTxn1, 4, moerr.Ok) 237 238 checkReadResult(t, 1, rs, 1, 0) 239 } 240 241 func TestRecovery(t *testing.T) { 242 l := NewMemLog() 243 s := NewKVTxnStorage(0, l, newTestClock(1)) 244 245 prepareTxn := writeTestData(t, s, 1, moerr.Ok, 1) 246 prepareTestTxn(t, s, &prepareTxn, 2, moerr.Ok) 247 checkLog(t, l, 1, prepareTxn, 1) 248 249 committedTxn := writeTestData(t, s, 1, moerr.Ok, 2) 250 commitTestTxn(t, s, &committedTxn, 3, moerr.Ok) 251 checkLog(t, l, 2, committedTxn, 2) 252 253 committedAndPreparedTxn := writeTestData(t, s, 1, moerr.Ok, 3) 254 prepareTestTxn(t, s, &committedAndPreparedTxn, 2, moerr.Ok) 255 checkLog(t, l, 3, committedAndPreparedTxn, 3) 256 commitTestTxn(t, s, &committedAndPreparedTxn, 3, moerr.Ok) 257 checkLog(t, l, 4, committedAndPreparedTxn) 258 259 committingTxn := writeTestData(t, s, 1, moerr.Ok, 4) 260 prepareTestTxn(t, s, &committingTxn, 2, moerr.Ok) 261 checkLog(t, l, 5, committingTxn, 4) 262 committingTestTxn(t, s, &committingTxn, 3) 263 checkLog(t, l, 6, committingTxn) 264 265 checkLogCount(t, l, 6) 266 267 c := make(chan txn.TxnMeta, 10) 268 s2 := NewKVTxnStorage(1, l, newTestClock(1)) 269 s2.StartRecovery(context.TODO(), c) 270 271 checkUncommitted(t, s2, prepareTxn, 1) 272 checkCommitted(t, s2, committedTxn, 2) 273 checkCommitted(t, s2, committedAndPreparedTxn, 3) 274 checkUncommitted(t, s2, committingTxn, 4) 275 276 txns := make([]txn.TxnMeta, 0, 6) 277 for v := range c { 278 txns = append(txns, v) 279 } 280 assert.Equal(t, 6, len(txns)) 281 } 282 283 func TestEvent(t *testing.T) { 284 l := NewMemLog() 285 s := NewKVTxnStorage(0, l, newTestClock(1)) 286 287 wTxn := writeTestData(t, s, 1, moerr.Ok, 1) 288 prepareTestTxn(t, s, &wTxn, 2, moerr.Ok) 289 e := <-s.GetEventC() 290 assert.Equal(t, e, Event{Type: PrepareType, Txn: wTxn}) 291 292 committingTestTxn(t, s, &wTxn, 3) 293 e = <-s.GetEventC() 294 assert.Equal(t, e, Event{Type: CommittingType, Txn: wTxn}) 295 296 commitTestTxn(t, s, &wTxn, 3, moerr.Ok) 297 e = <-s.GetEventC() 298 assert.Equal(t, e, Event{Type: CommitType, Txn: wTxn}) 299 300 wTxn = writeTestData(t, s, 1, moerr.Ok, 2) 301 assert.NoError(t, s.Rollback(context.TODO(), wTxn)) 302 checkRollback(t, s, wTxn, 2) 303 e = <-s.GetEventC() 304 assert.Equal(t, e, Event{Type: RollbackType, Txn: wTxn}) 305 } 306 307 func prepareTestTxn(t *testing.T, s *KVTxnStorage, wTxn *txn.TxnMeta, ts int64, errCode uint16) { 308 wTxn.PreparedTS = newTimestamp(ts) 309 pts, perr := s.Prepare(context.TODO(), *wTxn) 310 assert.True(t, moerr.IsMoErrCode(perr, errCode)) 311 wTxn.Status = txn.TxnStatus_Prepared 312 wTxn.PreparedTS = pts 313 } 314 315 func committingTestTxn(t *testing.T, s *KVTxnStorage, wTxn *txn.TxnMeta, ts int64) { 316 wTxn.CommitTS = newTimestamp(ts) 317 assert.NoError(t, s.Committing(context.TODO(), *wTxn)) 318 wTxn.Status = txn.TxnStatus_Committing 319 } 320 321 func commitTestTxn(t *testing.T, s *KVTxnStorage, wTxn *txn.TxnMeta, ts int64, errCode uint16) { 322 wTxn.CommitTS = newTimestamp(ts) 323 _, e := s.Commit(context.TODO(), *wTxn) 324 assert.True(t, moerr.IsMoErrCode(e, errCode)) 325 wTxn.Status = txn.TxnStatus_Committed 326 } 327 328 func checkLogCount(t *testing.T, ll logservice.Client, expect int) { 329 l := ll.(*memLogClient) 330 331 l.RLock() 332 defer l.RUnlock() 333 334 assert.Equal(t, expect, len(l.logs)) 335 } 336 337 func checkLog(t *testing.T, ll logservice.Client, offset int, wTxn txn.TxnMeta, keys ...byte) { 338 l := ll.(*memLogClient) 339 340 l.RLock() 341 defer l.RUnlock() 342 343 klog := &KVLog{} 344 klog.Txn = wTxn 345 for _, k := range keys { 346 key := []byte{k} 347 value := []byte{k, byte(wTxn.SnapshotTS.PhysicalTime)} 348 349 klog.Keys = append(klog.Keys, key) 350 klog.Values = append(klog.Values, value) 351 } 352 353 assert.Equal(t, klog.MustMarshal(), l.logs[offset-1].Data) 354 } 355 356 func checkUncommitted(t *testing.T, s *KVTxnStorage, wTxn txn.TxnMeta, keys ...byte) { 357 for _, k := range keys { 358 key := []byte{k} 359 value := []byte{k, byte(wTxn.SnapshotTS.PhysicalTime)} 360 uTxn, ok := s.uncommittedKeyTxnMap[string(key)] 361 assert.True(t, ok) 362 assert.Equal(t, wTxn, *uTxn) 363 364 v, ok := s.uncommitted.Get(key) 365 assert.True(t, ok) 366 assert.Equal(t, value, v) 367 368 n := 0 369 s.committed.AscendRange(key, 370 newTimestamp(0), 371 newTimestamp(math.MaxInt64), 372 func(b []byte, _ timestamp.Timestamp) { 373 if bytes.Equal(b, value) { 374 n++ 375 } 376 }) 377 assert.Equal(t, 0, n) 378 } 379 } 380 381 func checkRollback(t *testing.T, s *KVTxnStorage, wTxn txn.TxnMeta, keys ...byte) { 382 for _, k := range keys { 383 key := []byte{k} 384 value := []byte{k, byte(wTxn.SnapshotTS.PhysicalTime)} 385 uTxn, ok := s.uncommittedKeyTxnMap[string(key)] 386 assert.False(t, ok) 387 assert.Nil(t, uTxn) 388 389 v, ok := s.uncommitted.Get(key) 390 assert.False(t, ok) 391 assert.Empty(t, v) 392 393 n := 0 394 s.committed.AscendRange(key, 395 newTimestamp(0), 396 newTimestamp(math.MaxInt64), 397 func(b []byte, _ timestamp.Timestamp) { 398 if bytes.Equal(b, value) { 399 n++ 400 } 401 }) 402 assert.Equal(t, 0, n) 403 } 404 405 uTxn, ok := s.uncommittedTxn[string(wTxn.ID)] 406 assert.False(t, ok) 407 assert.Nil(t, uTxn) 408 } 409 410 func writeTestData(t *testing.T, s *KVTxnStorage, ts int64, expectError uint16, keys ...byte) txn.TxnMeta { 411 req := &message{} 412 for _, v := range keys { 413 req.Keys = append(req.Keys, []byte{v}) 414 req.Values = append(req.Values, []byte{v, byte(ts)}) 415 } 416 wTxn := newTxnMeta(ts) 417 _, err := s.Write(context.TODO(), wTxn, setOpCode, req.mustMarshal()) 418 assert.True(t, moerr.IsMoErrCode(err, expectError)) 419 return wTxn 420 } 421 422 func checkCommitted(t *testing.T, s *KVTxnStorage, wTxn txn.TxnMeta, keys ...byte) { 423 for _, k := range keys { 424 key := []byte{k} 425 value := []byte{k, byte(wTxn.SnapshotTS.PhysicalTime)} 426 427 v, ok := s.uncommittedKeyTxnMap[string(key)] 428 assert.False(t, ok) 429 assert.Nil(t, v) 430 431 hasCommitted := false 432 s.committed.AscendRange(key, 433 newTimestamp(0), 434 newTimestamp(math.MaxInt64), 435 func(b []byte, _ timestamp.Timestamp) { 436 if bytes.Equal(value, b) { 437 hasCommitted = true 438 } 439 }) 440 assert.True(t, hasCommitted) 441 } 442 443 v, ok := s.uncommittedTxn[string(wTxn.ID)] 444 assert.False(t, ok) 445 assert.Nil(t, v) 446 } 447 448 func writeCommittedData(t *testing.T, s *KVTxnStorage, sts, cts int64, keys ...byte) { 449 for _, k := range keys { 450 key := []byte{k} 451 value := []byte{k, byte(sts)} 452 s.committed.Set(key, newTimestamp(cts), value) 453 } 454 } 455 456 func readTestData(t *testing.T, s *KVTxnStorage, ts int64, waitTxns [][]byte, keys ...byte) (txn.TxnMeta, *readResult) { 457 rTxn := newTxnMeta(ts) 458 return rTxn, readTestDataWithTxn(t, s, &rTxn, waitTxns, keys...) 459 } 460 461 func readTestDataWithTxn(t *testing.T, s *KVTxnStorage, rTxn *txn.TxnMeta, waitTxns [][]byte, keys ...byte) *readResult { 462 req := &message{} 463 for _, k := range keys { 464 key := []byte{k} 465 req.Keys = append(req.Keys, key) 466 } 467 468 rs, err := s.Read(context.TODO(), *rTxn, getOpCode, req.mustMarshal()) 469 assert.NoError(t, err) 470 assert.Equal(t, waitTxns, rs.WaitTxns()) 471 return rs.(*readResult) 472 } 473 474 func checkReadResult(t *testing.T, sts byte, rs *readResult, keys ...byte) { 475 data, err := rs.Read() 476 assert.NoError(t, err) 477 resp := &message{} 478 resp.mustUnmarshal(data) 479 480 var values [][]byte 481 for _, k := range keys { 482 if k == 0 { 483 values = append(values, nil) 484 } else { 485 values = append(values, []byte{k, sts}) 486 } 487 } 488 489 assert.Equal(t, values, resp.Values) 490 } 491 492 func newTimestamp(v int64) timestamp.Timestamp { 493 return timestamp.Timestamp{PhysicalTime: v} 494 } 495 496 func newTxnMeta(snapshotTS int64) txn.TxnMeta { 497 id := uuid.New() 498 return txn.TxnMeta{ 499 ID: id[:], 500 Status: txn.TxnStatus_Active, 501 SnapshotTS: newTimestamp(snapshotTS), 502 } 503 } 504 505 func newTestClock(start int64) clock.Clock { 506 ts := start 507 return clock.NewHLCClock(func() int64 { 508 return atomic.AddInt64(&ts, 1) 509 }, math.MaxInt64) 510 }