github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/einsteindb/latch_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 latch
    15  
    16  import (
    17  	"sync/atomic"
    18  	"testing"
    19  	"time"
    20  
    21  	. "github.com/whtcorpsinc/check"
    22  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle"
    23  )
    24  
    25  func TestT(t *testing.T) {
    26  	TestingT(t)
    27  }
    28  
    29  var _ = Suite(&testLatchSuite{})
    30  
    31  var baseTso uint64
    32  
    33  type testLatchSuite struct {
    34  	latches *Latches
    35  }
    36  
    37  func (s *testLatchSuite) SetUpTest(c *C) {
    38  	s.latches = NewLatches(256)
    39  }
    40  
    41  func (s *testLatchSuite) newLock(keys [][]byte) (startTS uint64, dagger *Lock) {
    42  	startTS = getTso()
    43  	dagger = s.latches.genLock(startTS, keys)
    44  	return
    45  }
    46  
    47  func getTso() uint64 {
    48  	return atomic.AddUint64(&baseTso, uint64(1))
    49  }
    50  
    51  func (s *testLatchSuite) TestWakeUp(c *C) {
    52  	keysA := [][]byte{
    53  		[]byte("a"), []byte("b"), []byte("c")}
    54  	_, lockA := s.newLock(keysA)
    55  
    56  	keysB := [][]byte{[]byte("d"), []byte("e"), []byte("a"), []byte("c")}
    57  	startTSB, lockB := s.newLock(keysB)
    58  
    59  	// A acquire dagger success.
    60  	result := s.latches.acquire(lockA)
    61  	c.Assert(result, Equals, acquireSuccess)
    62  
    63  	// B acquire dagger failed.
    64  	result = s.latches.acquire(lockB)
    65  	c.Assert(result, Equals, acquireLocked)
    66  
    67  	// A release dagger, and get wakeup list.
    68  	commitTSA := getTso()
    69  	wakeupList := make([]*Lock, 0)
    70  	lockA.SetCommitTS(commitTSA)
    71  	wakeupList = s.latches.release(lockA, wakeupList)
    72  	c.Assert(wakeupList[0].startTS, Equals, startTSB)
    73  
    74  	// B acquire failed since startTSB has stale for some keys.
    75  	result = s.latches.acquire(lockB)
    76  	c.Assert(result, Equals, acquireStale)
    77  
    78  	// B release dagger since it received a stale.
    79  	wakeupList = s.latches.release(lockB, wakeupList)
    80  	c.Assert(wakeupList, HasLen, 0)
    81  
    82  	// B restart:get a new startTS.
    83  	startTSB = getTso()
    84  	lockB = s.latches.genLock(startTSB, keysB)
    85  	result = s.latches.acquire(lockB)
    86  	c.Assert(result, Equals, acquireSuccess)
    87  }
    88  
    89  func (s *testLatchSuite) TestFirstAcquireFailedWithStale(c *C) {
    90  	keys := [][]byte{
    91  		[]byte("a"), []byte("b"), []byte("c")}
    92  	_, lockA := s.newLock(keys)
    93  	startTSB, lockB := s.newLock(keys)
    94  	// acquire lockA success
    95  	result := s.latches.acquire(lockA)
    96  	c.Assert(result, Equals, acquireSuccess)
    97  	// release lockA
    98  	commitTSA := getTso()
    99  	wakeupList := make([]*Lock, 0)
   100  	lockA.SetCommitTS(commitTSA)
   101  	s.latches.release(lockA, wakeupList)
   102  
   103  	c.Assert(commitTSA, Greater, startTSB)
   104  	// acquire lockB first time, should be failed with stale since commitTSA > startTSB
   105  	result = s.latches.acquire(lockB)
   106  	c.Assert(result, Equals, acquireStale)
   107  	s.latches.release(lockB, wakeupList)
   108  }
   109  
   110  func (s *testLatchSuite) TestRecycle(c *C) {
   111  	latches := NewLatches(8)
   112  	now := time.Now()
   113  	startTS := oracle.ComposeTS(oracle.GetPhysical(now), 0)
   114  	dagger := latches.genLock(startTS, [][]byte{
   115  		[]byte("a"), []byte("b"),
   116  	})
   117  	lock1 := latches.genLock(startTS, [][]byte{
   118  		[]byte("b"), []byte("c"),
   119  	})
   120  	c.Assert(latches.acquire(dagger), Equals, acquireSuccess)
   121  	c.Assert(latches.acquire(lock1), Equals, acquireLocked)
   122  	dagger.SetCommitTS(startTS + 1)
   123  	var wakeupList []*Lock
   124  	latches.release(dagger, wakeupList)
   125  	// Release dagger will grant latch to lock1 automatically,
   126  	// so release lock1 is called here.
   127  	latches.release(lock1, wakeupList)
   128  
   129  	lock2 := latches.genLock(startTS+3, [][]byte{
   130  		[]byte("b"), []byte("c"),
   131  	})
   132  	c.Assert(latches.acquire(lock2), Equals, acquireSuccess)
   133  	wakeupList = wakeupList[:0]
   134  	latches.release(lock2, wakeupList)
   135  
   136  	allEmpty := true
   137  	for i := 0; i < len(latches.slots); i++ {
   138  		latch := &latches.slots[i]
   139  		if latch.queue != nil {
   140  			allEmpty = false
   141  		}
   142  	}
   143  	c.Assert(allEmpty, IsFalse)
   144  
   145  	currentTS := oracle.ComposeTS(oracle.GetPhysical(now.Add(expireDuration)), 3)
   146  	latches.recycle(currentTS)
   147  
   148  	for i := 0; i < len(latches.slots); i++ {
   149  		latch := &latches.slots[i]
   150  		c.Assert(latch.queue, IsNil)
   151  	}
   152  }