github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/einsteindb/lock_test.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package einsteindb 15 16 import ( 17 "bytes" 18 "context" 19 "fmt" 20 "math" 21 "math/rand" 22 "runtime" 23 "strings" 24 "sync/atomic" 25 "time" 26 27 . "github.com/whtcorpsinc/check" 28 "github.com/whtcorpsinc/ekvproto/pkg/ekvrpcpb" 29 "github.com/whtcorpsinc/errors" 30 "github.com/whtcorpsinc/failpoint" 31 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb/einsteindbrpc" 32 "github.com/whtcorpsinc/milevadb/ekv" 33 ) 34 35 type testLockSuite struct { 36 OneByOneSuite 37 causetstore *einsteindbStore 38 } 39 40 var _ = Suite(&testLockSuite{}) 41 42 func (s *testLockSuite) SetUpTest(c *C) { 43 s.causetstore = NewTestStore(c).(*einsteindbStore) 44 } 45 46 func (s *testLockSuite) TearDownTest(c *C) { 47 s.causetstore.Close() 48 } 49 50 func (s *testLockSuite) lockKey(c *C, key, value, primaryKey, primaryValue []byte, commitPrimary bool) (uint64, uint64) { 51 txn, err := newEinsteinDBTxn(s.causetstore) 52 c.Assert(err, IsNil) 53 if len(value) > 0 { 54 err = txn.Set(key, value) 55 } else { 56 err = txn.Delete(key) 57 } 58 c.Assert(err, IsNil) 59 60 if len(primaryValue) > 0 { 61 err = txn.Set(primaryKey, primaryValue) 62 } else { 63 err = txn.Delete(primaryKey) 64 } 65 c.Assert(err, IsNil) 66 tpc, err := newTwoPhaseCommitterWithInit(txn, 0) 67 c.Assert(err, IsNil) 68 tpc.primaryKey = primaryKey 69 70 ctx := context.Background() 71 err = tpc.prewriteMutations(NewBackofferWithVars(ctx, PrewriteMaxBackoff, nil), tpc.mutations) 72 c.Assert(err, IsNil) 73 74 if commitPrimary { 75 tpc.commitTS, err = s.causetstore.oracle.GetTimestamp(ctx) 76 c.Assert(err, IsNil) 77 err = tpc.commitMutations(NewBackofferWithVars(ctx, int(atomic.LoadUint64(&CommitMaxBackoff)), nil), tpc.mutationsOfKeys([][]byte{primaryKey})) 78 c.Assert(err, IsNil) 79 } 80 return txn.startTS, tpc.commitTS 81 } 82 83 func (s *testLockSuite) putAlphabets(c *C) { 84 for ch := byte('a'); ch <= byte('z'); ch++ { 85 s.putKV(c, []byte{ch}, []byte{ch}) 86 } 87 } 88 89 func (s *testLockSuite) putKV(c *C, key, value []byte) (uint64, uint64) { 90 txn, err := s.causetstore.Begin() 91 c.Assert(err, IsNil) 92 err = txn.Set(key, value) 93 c.Assert(err, IsNil) 94 err = txn.Commit(context.Background()) 95 c.Assert(err, IsNil) 96 return txn.StartTS(), txn.(*einsteindbTxn).commitTS 97 } 98 99 func (s *testLockSuite) prepareAlphabetLocks(c *C) { 100 s.putKV(c, []byte("c"), []byte("cc")) 101 s.lockKey(c, []byte("c"), []byte("c"), []byte("z1"), []byte("z1"), true) 102 s.lockKey(c, []byte("d"), []byte("dd"), []byte("z2"), []byte("z2"), false) 103 s.lockKey(c, []byte("foo"), []byte("foo"), []byte("z3"), []byte("z3"), false) 104 s.putKV(c, []byte("bar"), []byte("bar")) 105 s.lockKey(c, []byte("bar"), nil, []byte("z4"), []byte("z4"), true) 106 } 107 108 func (s *testLockSuite) TestScanLockResolveWithGet(c *C) { 109 s.putAlphabets(c) 110 s.prepareAlphabetLocks(c) 111 112 txn, err := s.causetstore.Begin() 113 c.Assert(err, IsNil) 114 for ch := byte('a'); ch <= byte('z'); ch++ { 115 v, err := txn.Get(context.TODO(), []byte{ch}) 116 c.Assert(err, IsNil) 117 c.Assert(v, BytesEquals, []byte{ch}) 118 } 119 } 120 121 func (s *testLockSuite) TestScanLockResolveWithSeek(c *C) { 122 s.putAlphabets(c) 123 s.prepareAlphabetLocks(c) 124 125 txn, err := s.causetstore.Begin() 126 c.Assert(err, IsNil) 127 iter, err := txn.Iter([]byte("a"), nil) 128 c.Assert(err, IsNil) 129 for ch := byte('a'); ch <= byte('z'); ch++ { 130 c.Assert(iter.Valid(), IsTrue) 131 c.Assert([]byte(iter.Key()), BytesEquals, []byte{ch}) 132 c.Assert(iter.Value(), BytesEquals, []byte{ch}) 133 c.Assert(iter.Next(), IsNil) 134 } 135 } 136 137 func (s *testLockSuite) TestScanLockResolveWithSeekKeyOnly(c *C) { 138 s.putAlphabets(c) 139 s.prepareAlphabetLocks(c) 140 141 txn, err := s.causetstore.Begin() 142 c.Assert(err, IsNil) 143 txn.SetOption(ekv.KeyOnly, true) 144 iter, err := txn.Iter([]byte("a"), nil) 145 c.Assert(err, IsNil) 146 for ch := byte('a'); ch <= byte('z'); ch++ { 147 c.Assert(iter.Valid(), IsTrue) 148 c.Assert([]byte(iter.Key()), BytesEquals, []byte{ch}) 149 c.Assert(iter.Next(), IsNil) 150 } 151 } 152 153 func (s *testLockSuite) TestScanLockResolveWithBatchGet(c *C) { 154 s.putAlphabets(c) 155 s.prepareAlphabetLocks(c) 156 157 var keys []ekv.Key 158 for ch := byte('a'); ch <= byte('z'); ch++ { 159 keys = append(keys, []byte{ch}) 160 } 161 162 ver, err := s.causetstore.CurrentVersion() 163 c.Assert(err, IsNil) 164 snapshot := newEinsteinDBSnapshot(s.causetstore, ver, 0) 165 m, err := snapshot.BatchGet(context.Background(), keys) 166 c.Assert(err, IsNil) 167 c.Assert(len(m), Equals, int('z'-'a'+1)) 168 for ch := byte('a'); ch <= byte('z'); ch++ { 169 k := []byte{ch} 170 c.Assert(m[string(k)], BytesEquals, k) 171 } 172 } 173 174 func (s *testLockSuite) TestCleanLock(c *C) { 175 for ch := byte('a'); ch <= byte('z'); ch++ { 176 k := []byte{ch} 177 s.lockKey(c, k, k, k, k, false) 178 } 179 txn, err := s.causetstore.Begin() 180 c.Assert(err, IsNil) 181 for ch := byte('a'); ch <= byte('z'); ch++ { 182 err = txn.Set([]byte{ch}, []byte{ch + 1}) 183 c.Assert(err, IsNil) 184 } 185 err = txn.Commit(context.Background()) 186 c.Assert(err, IsNil) 187 } 188 189 func (s *testLockSuite) TestGetTxnStatus(c *C) { 190 startTS, commitTS := s.putKV(c, []byte("a"), []byte("a")) 191 status, err := s.causetstore.lockResolver.GetTxnStatus(startTS, startTS, []byte("a")) 192 c.Assert(err, IsNil) 193 c.Assert(status.IsCommitted(), IsTrue) 194 c.Assert(status.CommitTS(), Equals, commitTS) 195 196 startTS, commitTS = s.lockKey(c, []byte("a"), []byte("a"), []byte("a"), []byte("a"), true) 197 status, err = s.causetstore.lockResolver.GetTxnStatus(startTS, startTS, []byte("a")) 198 c.Assert(err, IsNil) 199 c.Assert(status.IsCommitted(), IsTrue) 200 c.Assert(status.CommitTS(), Equals, commitTS) 201 202 startTS, _ = s.lockKey(c, []byte("a"), []byte("a"), []byte("a"), []byte("a"), false) 203 status, err = s.causetstore.lockResolver.GetTxnStatus(startTS, startTS, []byte("a")) 204 c.Assert(err, IsNil) 205 c.Assert(status.IsCommitted(), IsFalse) 206 c.Assert(status.ttl, Greater, uint64(0), Commentf("action:%s", status.action)) 207 } 208 209 func (s *testLockSuite) TestCheckTxnStatusTTL(c *C) { 210 txn, err := s.causetstore.Begin() 211 c.Assert(err, IsNil) 212 txn.Set(ekv.Key("key"), []byte("value")) 213 s.prewriteTxnWithTTL(c, txn.(*einsteindbTxn), 1000) 214 215 bo := NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil) 216 lr := newLockResolver(s.causetstore) 217 callerStartTS, err := lr.causetstore.GetOracle().GetTimestamp(bo.ctx) 218 c.Assert(err, IsNil) 219 220 // Check the dagger TTL of a transaction. 221 status, err := lr.GetTxnStatus(txn.StartTS(), callerStartTS, []byte("key")) 222 c.Assert(err, IsNil) 223 c.Assert(status.IsCommitted(), IsFalse) 224 c.Assert(status.ttl, Greater, uint64(0)) 225 c.Assert(status.CommitTS(), Equals, uint64(0)) 226 227 // Rollback the txn. 228 dagger := s.mustGetLock(c, []byte("key")) 229 status = TxnStatus{} 230 cleanRegions := make(map[RegionVerID]struct{}) 231 err = newLockResolver(s.causetstore).resolveLock(bo, dagger, status, false, cleanRegions) 232 c.Assert(err, IsNil) 233 234 // Check its status is rollbacked. 235 status, err = lr.GetTxnStatus(txn.StartTS(), callerStartTS, []byte("key")) 236 c.Assert(err, IsNil) 237 c.Assert(status.ttl, Equals, uint64(0)) 238 c.Assert(status.commitTS, Equals, uint64(0)) 239 c.Assert(status.action, Equals, ekvrpcpb.CausetAction_NoCausetAction) 240 241 // Check a committed txn. 242 startTS, commitTS := s.putKV(c, []byte("a"), []byte("a")) 243 status, err = lr.GetTxnStatus(startTS, callerStartTS, []byte("a")) 244 c.Assert(err, IsNil) 245 c.Assert(status.ttl, Equals, uint64(0)) 246 c.Assert(status.commitTS, Equals, commitTS) 247 } 248 249 func (s *testLockSuite) TestTxnHeartBeat(c *C) { 250 txn, err := s.causetstore.Begin() 251 c.Assert(err, IsNil) 252 txn.Set(ekv.Key("key"), []byte("value")) 253 s.prewriteTxn(c, txn.(*einsteindbTxn)) 254 255 bo := NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil) 256 newTTL, err := sendTxnHeartBeat(bo, s.causetstore, []byte("key"), txn.StartTS(), 6666) 257 c.Assert(err, IsNil) 258 c.Assert(newTTL, Equals, uint64(6666)) 259 260 newTTL, err = sendTxnHeartBeat(bo, s.causetstore, []byte("key"), txn.StartTS(), 5555) 261 c.Assert(err, IsNil) 262 c.Assert(newTTL, Equals, uint64(6666)) 263 264 dagger := s.mustGetLock(c, []byte("key")) 265 status := TxnStatus{ttl: newTTL} 266 cleanRegions := make(map[RegionVerID]struct{}) 267 err = newLockResolver(s.causetstore).resolveLock(bo, dagger, status, false, cleanRegions) 268 c.Assert(err, IsNil) 269 270 newTTL, err = sendTxnHeartBeat(bo, s.causetstore, []byte("key"), txn.StartTS(), 6666) 271 c.Assert(err, NotNil) 272 c.Assert(newTTL, Equals, uint64(0)) 273 } 274 275 func (s *testLockSuite) TestCheckTxnStatus(c *C) { 276 txn, err := s.causetstore.Begin() 277 c.Assert(err, IsNil) 278 txn.Set(ekv.Key("key"), []byte("value")) 279 txn.Set(ekv.Key("second"), []byte("xxx")) 280 s.prewriteTxnWithTTL(c, txn.(*einsteindbTxn), 1000) 281 282 oracle := s.causetstore.GetOracle() 283 currentTS, err := oracle.GetTimestamp(context.Background()) 284 c.Assert(err, IsNil) 285 c.Assert(currentTS, Greater, txn.StartTS()) 286 287 bo := NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil) 288 resolver := newLockResolver(s.causetstore) 289 // Call getTxnStatus to check the dagger status. 290 status, err := resolver.getTxnStatus(bo, txn.StartTS(), []byte("key"), currentTS, currentTS, true) 291 c.Assert(err, IsNil) 292 c.Assert(status.IsCommitted(), IsFalse) 293 c.Assert(status.ttl, Greater, uint64(0)) 294 c.Assert(status.CommitTS(), Equals, uint64(0)) 295 c.Assert(status.action, Equals, ekvrpcpb.CausetAction_MinCommitTSPushed) 296 297 // Test the ResolveLocks API 298 dagger := s.mustGetLock(c, []byte("second")) 299 timeBeforeExpire, _, err := resolver.ResolveLocks(bo, currentTS, []*Lock{dagger}) 300 c.Assert(err, IsNil) 301 c.Assert(timeBeforeExpire > int64(0), IsTrue) 302 303 // Force rollback the dagger using dagger.TTL = 0. 304 dagger.TTL = uint64(0) 305 timeBeforeExpire, _, err = resolver.ResolveLocks(bo, currentTS, []*Lock{dagger}) 306 c.Assert(err, IsNil) 307 c.Assert(timeBeforeExpire, Equals, int64(0)) 308 309 // Then call getTxnStatus again and check the dagger status. 310 currentTS, err = oracle.GetTimestamp(context.Background()) 311 c.Assert(err, IsNil) 312 status, err = newLockResolver(s.causetstore).getTxnStatus(bo, txn.StartTS(), []byte("key"), currentTS, 0, true) 313 c.Assert(err, IsNil) 314 c.Assert(status.ttl, Equals, uint64(0)) 315 c.Assert(status.commitTS, Equals, uint64(0)) 316 c.Assert(status.action, Equals, ekvrpcpb.CausetAction_NoCausetAction) 317 318 // Call getTxnStatus on a committed transaction. 319 startTS, commitTS := s.putKV(c, []byte("a"), []byte("a")) 320 status, err = newLockResolver(s.causetstore).getTxnStatus(bo, startTS, []byte("a"), currentTS, currentTS, true) 321 c.Assert(err, IsNil) 322 c.Assert(status.ttl, Equals, uint64(0)) 323 c.Assert(status.commitTS, Equals, commitTS) 324 } 325 326 func (s *testLockSuite) TestCheckTxnStatusNoWait(c *C) { 327 txn, err := s.causetstore.Begin() 328 c.Assert(err, IsNil) 329 txn.Set(ekv.Key("key"), []byte("value")) 330 txn.Set(ekv.Key("second"), []byte("xxx")) 331 committer, err := newTwoPhaseCommitterWithInit(txn.(*einsteindbTxn), 0) 332 c.Assert(err, IsNil) 333 // Increase dagger TTL to make CI more sblock. 334 committer.lockTTL = txnLockTTL(txn.(*einsteindbTxn).startTime, 200*1024*1024) 335 336 // Only prewrite the secondary key to simulate a concurrent prewrite case: 337 // prewrite secondary regions success and prewrite the primary region is pending. 338 err = committer.prewriteMutations(NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil), committer.mutationsOfKeys([][]byte{[]byte("second")})) 339 c.Assert(err, IsNil) 340 341 oracle := s.causetstore.GetOracle() 342 currentTS, err := oracle.GetTimestamp(context.Background()) 343 c.Assert(err, IsNil) 344 bo := NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil) 345 resolver := newLockResolver(s.causetstore) 346 347 // Call getTxnStatus for the TxnNotFound case. 348 _, err = resolver.getTxnStatus(bo, txn.StartTS(), []byte("key"), currentTS, currentTS, false) 349 c.Assert(err, NotNil) 350 _, ok := errors.Cause(err).(txnNotFoundErr) 351 c.Assert(ok, IsTrue) 352 353 errCh := make(chan error) 354 go func() { 355 errCh <- committer.prewriteMutations(NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil), committer.mutationsOfKeys([][]byte{[]byte("key")})) 356 }() 357 358 dagger := &Lock{ 359 Key: []byte("second"), 360 Primary: []byte("key"), 361 TxnID: txn.StartTS(), 362 TTL: 100000, 363 } 364 // Call getTxnStatusFromLock to cover the retry logic. 365 status, err := resolver.getTxnStatusFromLock(bo, dagger, currentTS) 366 c.Assert(err, IsNil) 367 c.Assert(status.ttl, Greater, uint64(0)) 368 c.Assert(<-errCh, IsNil) 369 c.Assert(committer.cleanupMutations(bo, committer.mutations), IsNil) 370 371 // Call getTxnStatusFromLock to cover TxnNotFound and retry timeout. 372 startTS, err := oracle.GetTimestamp(context.Background()) 373 c.Assert(err, IsNil) 374 dagger = &Lock{ 375 Key: []byte("second"), 376 Primary: []byte("key_not_exist"), 377 TxnID: startTS, 378 TTL: 1000, 379 } 380 status, err = resolver.getTxnStatusFromLock(bo, dagger, currentTS) 381 c.Assert(err, IsNil) 382 c.Assert(status.ttl, Equals, uint64(0)) 383 c.Assert(status.commitTS, Equals, uint64(0)) 384 c.Assert(status.action, Equals, ekvrpcpb.CausetAction_LockNotExistRollback) 385 } 386 387 func (s *testLockSuite) prewriteTxn(c *C, txn *einsteindbTxn) { 388 s.prewriteTxnWithTTL(c, txn, 0) 389 } 390 391 func (s *testLockSuite) prewriteTxnWithTTL(c *C, txn *einsteindbTxn, ttl uint64) { 392 committer, err := newTwoPhaseCommitterWithInit(txn, 0) 393 c.Assert(err, IsNil) 394 if ttl > 0 { 395 elapsed := time.Since(txn.startTime) / time.Millisecond 396 committer.lockTTL = uint64(elapsed) + ttl 397 } 398 err = committer.prewriteMutations(NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil), committer.mutations) 399 c.Assert(err, IsNil) 400 } 401 402 func (s *testLockSuite) mustGetLock(c *C, key []byte) *Lock { 403 ver, err := s.causetstore.CurrentVersion() 404 c.Assert(err, IsNil) 405 bo := NewBackofferWithVars(context.Background(), getMaxBackoff, nil) 406 req := einsteindbrpc.NewRequest(einsteindbrpc.CmdGet, &ekvrpcpb.GetRequest{ 407 Key: key, 408 Version: ver.Ver, 409 }) 410 loc, err := s.causetstore.regionCache.LocateKey(bo, key) 411 c.Assert(err, IsNil) 412 resp, err := s.causetstore.SendReq(bo, req, loc.Region, readTimeoutShort) 413 c.Assert(err, IsNil) 414 c.Assert(resp.Resp, NotNil) 415 keyErr := resp.Resp.(*ekvrpcpb.GetResponse).GetError() 416 c.Assert(keyErr, NotNil) 417 dagger, err := extractLockFromKeyErr(keyErr) 418 c.Assert(err, IsNil) 419 return dagger 420 } 421 422 func (s *testLockSuite) ttlEquals(c *C, x, y uint64) { 423 // NOTE: On ppc64le, all integers are by default unsigned integers, 424 // hence we have to separately cast the value returned by "math.Abs()" function for ppc64le. 425 if runtime.GOARCH == "ppc64le" { 426 c.Assert(int(-math.Abs(float64(x-y))), LessEqual, 2) 427 } else { 428 c.Assert(int(math.Abs(float64(x-y))), LessEqual, 2) 429 } 430 431 } 432 433 func (s *testLockSuite) TestLockTTL(c *C) { 434 txn, err := s.causetstore.Begin() 435 c.Assert(err, IsNil) 436 txn.Set(ekv.Key("key"), []byte("value")) 437 time.Sleep(time.Millisecond) 438 s.prewriteTxnWithTTL(c, txn.(*einsteindbTxn), 3100) 439 l := s.mustGetLock(c, []byte("key")) 440 c.Assert(l.TTL >= defaultLockTTL, IsTrue) 441 442 // Huge txn has a greater TTL. 443 txn, err = s.causetstore.Begin() 444 start := time.Now() 445 c.Assert(err, IsNil) 446 txn.Set(ekv.Key("key"), []byte("value")) 447 for i := 0; i < 2048; i++ { 448 k, v := randKV(1024, 1024) 449 txn.Set(ekv.Key(k), []byte(v)) 450 } 451 s.prewriteTxn(c, txn.(*einsteindbTxn)) 452 l = s.mustGetLock(c, []byte("key")) 453 s.ttlEquals(c, l.TTL, uint64(ttlFactor*2)+uint64(time.Since(start)/time.Millisecond)) 454 455 // Txn with long read time. 456 start = time.Now() 457 txn, err = s.causetstore.Begin() 458 c.Assert(err, IsNil) 459 time.Sleep(time.Millisecond * 50) 460 txn.Set(ekv.Key("key"), []byte("value")) 461 s.prewriteTxn(c, txn.(*einsteindbTxn)) 462 l = s.mustGetLock(c, []byte("key")) 463 s.ttlEquals(c, l.TTL, defaultLockTTL+uint64(time.Since(start)/time.Millisecond)) 464 } 465 466 func (s *testLockSuite) TestBatchResolveLocks(c *C) { 467 // The first transaction is a normal transaction with a long TTL 468 txn, err := s.causetstore.Begin() 469 c.Assert(err, IsNil) 470 txn.Set(ekv.Key("k1"), []byte("v1")) 471 txn.Set(ekv.Key("k2"), []byte("v2")) 472 s.prewriteTxnWithTTL(c, txn.(*einsteindbTxn), 20000) 473 474 // The second transaction is an async commit transaction 475 txn, err = s.causetstore.Begin() 476 c.Assert(err, IsNil) 477 txn.Set(ekv.Key("k3"), []byte("v3")) 478 txn.Set(ekv.Key("k4"), []byte("v4")) 479 einsteindbTxn := txn.(*einsteindbTxn) 480 committer, err := newTwoPhaseCommitterWithInit(einsteindbTxn, 0) 481 c.Assert(err, IsNil) 482 committer.setAsyncCommit(true) 483 committer.lockTTL = 20000 484 err = committer.prewriteMutations(NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil), committer.mutations) 485 c.Assert(err, IsNil) 486 487 var locks []*Lock 488 for _, key := range []string{"k1", "k2", "k3", "k4"} { 489 l := s.mustGetLock(c, []byte(key)) 490 locks = append(locks, l) 491 } 492 493 // Locks may not expired 494 msBeforeLockExpired := s.causetstore.GetOracle().UntilExpired(locks[0].TxnID, locks[1].TTL) 495 c.Assert(msBeforeLockExpired, Greater, int64(0)) 496 msBeforeLockExpired = s.causetstore.GetOracle().UntilExpired(locks[3].TxnID, locks[3].TTL) 497 c.Assert(msBeforeLockExpired, Greater, int64(0)) 498 499 lr := newLockResolver(s.causetstore) 500 bo := NewBackofferWithVars(context.Background(), GcResolveLockMaxBackoff, nil) 501 loc, err := lr.causetstore.GetRegionCache().LocateKey(bo, locks[0].Primary) 502 c.Assert(err, IsNil) 503 // Check BatchResolveLocks resolve the dagger even the ttl is not expired. 504 success, err := lr.BatchResolveLocks(bo, locks, loc.Region) 505 c.Assert(success, IsTrue) 506 c.Assert(err, IsNil) 507 508 txn, err = s.causetstore.Begin() 509 c.Assert(err, IsNil) 510 // transaction 1 is rolled back 511 _, err = txn.Get(context.Background(), ekv.Key("k1")) 512 c.Assert(err, Equals, ekv.ErrNotExist) 513 _, err = txn.Get(context.Background(), ekv.Key("k2")) 514 c.Assert(err, Equals, ekv.ErrNotExist) 515 // transaction 2 is committed 516 v, err := txn.Get(context.Background(), ekv.Key("k3")) 517 c.Assert(err, IsNil) 518 c.Assert(bytes.Equal(v, []byte("v3")), IsTrue) 519 v, err = txn.Get(context.Background(), ekv.Key("k4")) 520 c.Assert(err, IsNil) 521 c.Assert(bytes.Equal(v, []byte("v4")), IsTrue) 522 } 523 524 func (s *testLockSuite) TestNewLockZeroTTL(c *C) { 525 l := NewLock(&ekvrpcpb.LockInfo{}) 526 c.Assert(l.TTL, Equals, uint64(0)) 527 } 528 529 func init() { 530 // Speed up tests. 531 oracleUFIDelateInterval = 2 532 } 533 534 func (s *testLockSuite) TestZeroMinCommitTS(c *C) { 535 txn, err := s.causetstore.Begin() 536 c.Assert(err, IsNil) 537 txn.Set(ekv.Key("key"), []byte("value")) 538 bo := NewBackofferWithVars(context.Background(), PrewriteMaxBackoff, nil) 539 540 mockValue := fmt.Sprintf(`return(%d)`, txn.StartTS()) 541 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/mockZeroCommitTS", mockValue), IsNil) 542 s.prewriteTxnWithTTL(c, txn.(*einsteindbTxn), 1000) 543 c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/mockZeroCommitTS"), IsNil) 544 545 dagger := s.mustGetLock(c, []byte("key")) 546 expire, pushed, err := newLockResolver(s.causetstore).ResolveLocks(bo, 0, []*Lock{dagger}) 547 c.Assert(err, IsNil) 548 c.Assert(pushed, HasLen, 0) 549 c.Assert(expire, Greater, int64(0)) 550 551 expire, pushed, err = newLockResolver(s.causetstore).ResolveLocks(bo, math.MaxUint64, []*Lock{dagger}) 552 c.Assert(err, IsNil) 553 c.Assert(pushed, HasLen, 1) 554 c.Assert(expire, Greater, int64(0)) 555 556 // Clean up this test. 557 dagger.TTL = uint64(0) 558 expire, _, err = newLockResolver(s.causetstore).ResolveLocks(bo, 0, []*Lock{dagger}) 559 c.Assert(err, IsNil) 560 c.Assert(expire, Equals, int64(0)) 561 } 562 563 func (s *testLockSuite) TestDeduplicateKeys(c *C) { 564 inputs := []string{ 565 "a b c", 566 "a a b c", 567 "a a a b c", 568 "a a a b b b b c", 569 "a b b b b c c c", 570 } 571 r := rand.New(rand.NewSource(time.Now().UnixNano())) 572 for _, in := range inputs { 573 strs := strings.Split(in, " ") 574 keys := make([][]byte, len(strs)) 575 for _, i := range r.Perm(len(strs)) { 576 keys[i] = []byte(strs[i]) 577 } 578 keys = deduplicateKeys(keys) 579 strs = strs[:len(keys)] 580 for i := range keys { 581 strs[i] = string(keys[i]) 582 } 583 out := strings.Join(strs, " ") 584 c.Assert(out, Equals, "a b c") 585 } 586 }