github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/einsteindb/store_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  	"context"
    18  	"sync"
    19  	"time"
    20  
    21  	fidel "github.com/einsteindb/fidel/client"
    22  	. "github.com/whtcorpsinc/check"
    23  	"github.com/whtcorpsinc/ekvproto/pkg/FIDelpb"
    24  	pb "github.com/whtcorpsinc/ekvproto/pkg/ekvrpcpb"
    25  	"github.com/whtcorpsinc/ekvproto/pkg/spacetimepb"
    26  	"github.com/whtcorpsinc/errors"
    27  	"github.com/whtcorpsinc/failpoint"
    28  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/einsteindbrpc"
    29  	"github.com/whtcorpsinc/milevadb/causetstore/mockoracle"
    30  	"github.com/whtcorpsinc/milevadb/ekv"
    31  )
    32  
    33  var errStopped = errors.New("stopped")
    34  
    35  type testStoreSuite struct {
    36  	testStoreSuiteBase
    37  }
    38  
    39  type testStoreSerialSuite struct {
    40  	testStoreSuiteBase
    41  }
    42  
    43  type testStoreSuiteBase struct {
    44  	OneByOneSuite
    45  	causetstore *einsteindbStore
    46  }
    47  
    48  var _ = Suite(&testStoreSuite{})
    49  var _ = SerialSuites(&testStoreSerialSuite{})
    50  
    51  func (s *testStoreSuiteBase) SetUpTest(c *C) {
    52  	s.causetstore = NewTestStore(c).(*einsteindbStore)
    53  }
    54  
    55  func (s *testStoreSuiteBase) TearDownTest(c *C) {
    56  	c.Assert(s.causetstore.Close(), IsNil)
    57  }
    58  
    59  func (s *testStoreSuite) TestOracle(c *C) {
    60  	o := &mockoracle.MockOracle{}
    61  	s.causetstore.oracle = o
    62  
    63  	ctx := context.Background()
    64  	t1, err := s.causetstore.getTimestampWithRetry(NewBackofferWithVars(ctx, 100, nil))
    65  	c.Assert(err, IsNil)
    66  	t2, err := s.causetstore.getTimestampWithRetry(NewBackofferWithVars(ctx, 100, nil))
    67  	c.Assert(err, IsNil)
    68  	c.Assert(t1, Less, t2)
    69  
    70  	t1, err = o.GetLowResolutionTimestamp(ctx)
    71  	c.Assert(err, IsNil)
    72  	t2, err = o.GetLowResolutionTimestamp(ctx)
    73  	c.Assert(err, IsNil)
    74  	c.Assert(t1, Less, t2)
    75  	f := o.GetLowResolutionTimestampAsync(ctx)
    76  	c.Assert(f, NotNil)
    77  	_ = o.UntilExpired(0, 0)
    78  
    79  	// Check retry.
    80  	var wg sync.WaitGroup
    81  	wg.Add(2)
    82  
    83  	o.Disable()
    84  	go func() {
    85  		defer wg.Done()
    86  		time.Sleep(time.Millisecond * 100)
    87  		o.Enable()
    88  	}()
    89  
    90  	go func() {
    91  		defer wg.Done()
    92  		t3, err := s.causetstore.getTimestampWithRetry(NewBackofferWithVars(ctx, tsoMaxBackoff, nil))
    93  		c.Assert(err, IsNil)
    94  		c.Assert(t2, Less, t3)
    95  		expired := s.causetstore.oracle.IsExpired(t2, 50)
    96  		c.Assert(expired, IsTrue)
    97  	}()
    98  
    99  	wg.Wait()
   100  }
   101  
   102  type mockFIDelClient struct {
   103  	sync.RWMutex
   104  	client fidel.Client
   105  	stop   bool
   106  }
   107  
   108  func (c *mockFIDelClient) enable() {
   109  	c.Lock()
   110  	defer c.Unlock()
   111  	c.stop = false
   112  }
   113  
   114  func (c *mockFIDelClient) disable() {
   115  	c.Lock()
   116  	defer c.Unlock()
   117  	c.stop = true
   118  }
   119  
   120  func (c *mockFIDelClient) GetMemberInfo(ctx context.Context) ([]*FIDelpb.Member, error) {
   121  	return nil, nil
   122  }
   123  
   124  func (c *mockFIDelClient) GetClusterID(context.Context) uint64 {
   125  	return 1
   126  }
   127  
   128  func (c *mockFIDelClient) GetTS(ctx context.Context) (int64, int64, error) {
   129  	c.RLock()
   130  	defer c.RUnlock()
   131  
   132  	if c.stop {
   133  		return 0, 0, errors.Trace(errStopped)
   134  	}
   135  	return c.client.GetTS(ctx)
   136  }
   137  
   138  func (c *mockFIDelClient) GetTSAsync(ctx context.Context) fidel.TSFuture {
   139  	return nil
   140  }
   141  
   142  func (c *mockFIDelClient) GetRegion(ctx context.Context, key []byte) (*fidel.Region, error) {
   143  	c.RLock()
   144  	defer c.RUnlock()
   145  
   146  	if c.stop {
   147  		return nil, errors.Trace(errStopped)
   148  	}
   149  	return c.client.GetRegion(ctx, key)
   150  }
   151  
   152  func (c *mockFIDelClient) GetPrevRegion(ctx context.Context, key []byte) (*fidel.Region, error) {
   153  	c.RLock()
   154  	defer c.RUnlock()
   155  
   156  	if c.stop {
   157  		return nil, errors.Trace(errStopped)
   158  	}
   159  	return c.client.GetPrevRegion(ctx, key)
   160  }
   161  
   162  func (c *mockFIDelClient) GetRegionByID(ctx context.Context, regionID uint64) (*fidel.Region, error) {
   163  	c.RLock()
   164  	defer c.RUnlock()
   165  
   166  	if c.stop {
   167  		return nil, errors.Trace(errStopped)
   168  	}
   169  	return c.client.GetRegionByID(ctx, regionID)
   170  }
   171  
   172  func (c *mockFIDelClient) ScanRegions(ctx context.Context, startKey []byte, endKey []byte, limit int) ([]*fidel.Region, error) {
   173  	c.RLock()
   174  	defer c.RUnlock()
   175  
   176  	if c.stop {
   177  		return nil, errors.Trace(errStopped)
   178  	}
   179  	return c.client.ScanRegions(ctx, startKey, endKey, limit)
   180  }
   181  
   182  func (c *mockFIDelClient) GetStore(ctx context.Context, storeID uint64) (*spacetimepb.CausetStore, error) {
   183  	c.RLock()
   184  	defer c.RUnlock()
   185  
   186  	if c.stop {
   187  		return nil, errors.Trace(errStopped)
   188  	}
   189  	return c.client.GetStore(ctx, storeID)
   190  }
   191  
   192  func (c *mockFIDelClient) GetAllStores(ctx context.Context, opts ...fidel.GetStoreOption) ([]*spacetimepb.CausetStore, error) {
   193  	c.RLock()
   194  	defer c.Unlock()
   195  
   196  	if c.stop {
   197  		return nil, errors.Trace(errStopped)
   198  	}
   199  	return c.client.GetAllStores(ctx)
   200  }
   201  
   202  func (c *mockFIDelClient) UFIDelateGCSafePoint(ctx context.Context, safePoint uint64) (uint64, error) {
   203  	panic("unimplemented")
   204  }
   205  
   206  func (c *mockFIDelClient) UFIDelateServiceGCSafePoint(ctx context.Context, serviceID string, ttl int64, safePoint uint64) (uint64, error) {
   207  	panic("unimplemented")
   208  }
   209  
   210  func (c *mockFIDelClient) Close() {}
   211  
   212  func (c *mockFIDelClient) ScatterRegion(ctx context.Context, regionID uint64) error {
   213  	return nil
   214  }
   215  
   216  func (c *mockFIDelClient) GetOperator(ctx context.Context, regionID uint64) (*FIDelpb.GetOperatorResponse, error) {
   217  	return &FIDelpb.GetOperatorResponse{Status: FIDelpb.OperatorStatus_SUCCESS}, nil
   218  }
   219  
   220  func (c *mockFIDelClient) GetLeaderAddr() string { return "mockFIDel" }
   221  
   222  func (c *mockFIDelClient) ScatterRegionWithOption(ctx context.Context, regionID uint64, opts ...fidel.ScatterRegionOption) error {
   223  	return nil
   224  }
   225  
   226  type checkRequestClient struct {
   227  	Client
   228  	priority pb.CommandPri
   229  }
   230  
   231  func (c *checkRequestClient) SendRequest(ctx context.Context, addr string, req *einsteindbrpc.Request, timeout time.Duration) (*einsteindbrpc.Response, error) {
   232  	resp, err := c.Client.SendRequest(ctx, addr, req, timeout)
   233  	if c.priority != req.Priority {
   234  		if resp.Resp != nil {
   235  			if getResp, ok := resp.Resp.(*pb.GetResponse); ok {
   236  				getResp.Error = &pb.KeyError{
   237  					Abort: "request check error",
   238  				}
   239  			}
   240  		}
   241  	}
   242  	return resp, err
   243  }
   244  
   245  func (s *testStoreSuite) TestRequestPriority(c *C) {
   246  	client := &checkRequestClient{
   247  		Client: s.causetstore.client,
   248  	}
   249  	s.causetstore.client = client
   250  
   251  	// Cover 2PC commit.
   252  	txn, err := s.causetstore.Begin()
   253  	c.Assert(err, IsNil)
   254  	client.priority = pb.CommandPri_High
   255  	txn.SetOption(ekv.Priority, ekv.PriorityHigh)
   256  	err = txn.Set([]byte("key"), []byte("value"))
   257  	c.Assert(err, IsNil)
   258  	err = txn.Commit(context.Background())
   259  	c.Assert(err, IsNil)
   260  
   261  	// Cover the basic Get request.
   262  	txn, err = s.causetstore.Begin()
   263  	c.Assert(err, IsNil)
   264  	client.priority = pb.CommandPri_Low
   265  	txn.SetOption(ekv.Priority, ekv.PriorityLow)
   266  	_, err = txn.Get(context.TODO(), []byte("key"))
   267  	c.Assert(err, IsNil)
   268  
   269  	// A counter example.
   270  	client.priority = pb.CommandPri_Low
   271  	txn.SetOption(ekv.Priority, ekv.PriorityNormal)
   272  	_, err = txn.Get(context.TODO(), []byte("key"))
   273  	// err is translated to "try again later" by backoffer, so doesn't check error value here.
   274  	c.Assert(err, NotNil)
   275  
   276  	// Cover Seek request.
   277  	client.priority = pb.CommandPri_High
   278  	txn.SetOption(ekv.Priority, ekv.PriorityHigh)
   279  	iter, err := txn.Iter([]byte("key"), nil)
   280  	c.Assert(err, IsNil)
   281  	for iter.Valid() {
   282  		c.Assert(iter.Next(), IsNil)
   283  	}
   284  	iter.Close()
   285  }
   286  
   287  func (s *testStoreSerialSuite) TestOracleChangeByFailpoint(c *C) {
   288  	defer func() {
   289  		failpoint.Disable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle/changeTSFromFIDel")
   290  	}()
   291  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle/changeTSFromFIDel",
   292  		"return(10000)"), IsNil)
   293  	o := &mockoracle.MockOracle{}
   294  	s.causetstore.oracle = o
   295  	ctx := context.Background()
   296  	t1, err := s.causetstore.getTimestampWithRetry(NewBackofferWithVars(ctx, 100, nil))
   297  	c.Assert(err, IsNil)
   298  	c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle/changeTSFromFIDel"), IsNil)
   299  	t2, err := s.causetstore.getTimestampWithRetry(NewBackofferWithVars(ctx, 100, nil))
   300  	c.Assert(err, IsNil)
   301  	c.Assert(t1, Greater, t2)
   302  }