github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/causetstore/entangledstore/cluster.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 entangledstore
    15  
    16  import (
    17  	"fmt"
    18  	"sync"
    19  	"time"
    20  
    21  	us "github.com/ngaut/entangledstore/einsteindb"
    22  	"github.com/whtcorpsinc/ekvproto/pkg/spacetimepb"
    23  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore/cluster"
    24  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    25  )
    26  
    27  type delayKey struct {
    28  	startTS  uint64
    29  	regionID uint64
    30  }
    31  
    32  var _ cluster.Cluster = new(Cluster)
    33  
    34  // Cluster simulates a EinsteinDB cluster. It focuses on management and the change of
    35  // spacetime data. A Cluster mainly includes following 3 HoTTs of spacetime data:
    36  // 1) Region: A Region is a fragment of EinsteinDB's data whose range is [start, end).
    37  //    The data of a Region is duplicated to multiple Peers and distributed in
    38  //    multiple Stores.
    39  // 2) Peer: A Peer is a replica of a Region's data. All peers of a Region form
    40  //    a group, each group elects a Leader to provide services.
    41  // 3) CausetStore: A CausetStore is a storage/service node. Try to think it as a EinsteinDB server
    42  //    process. Only the causetstore with request's Region's leader Peer could respond
    43  //    to client's request.
    44  type Cluster struct {
    45  	*us.MockRegionManager
    46  
    47  	// delayEvents is used to control the execution sequence of rpc requests for test.
    48  	delayEvents map[delayKey]time.Duration
    49  	delayMu     sync.Mutex
    50  }
    51  
    52  func newCluster(rm *us.MockRegionManager) *Cluster {
    53  	return &Cluster{
    54  		MockRegionManager: rm,
    55  		delayEvents:       make(map[delayKey]time.Duration),
    56  	}
    57  }
    58  
    59  // ScheduleDelay schedules a delay event for a transaction on a region.
    60  func (c *Cluster) ScheduleDelay(startTS, regionID uint64, dur time.Duration) {
    61  	c.delayMu.Lock()
    62  	c.delayEvents[delayKey{startTS: startTS, regionID: regionID}] = dur
    63  	c.delayMu.Unlock()
    64  }
    65  
    66  func (c *Cluster) handleDelay(startTS, regionID uint64) {
    67  	key := delayKey{startTS: startTS, regionID: regionID}
    68  	c.delayMu.Lock()
    69  	dur, ok := c.delayEvents[key]
    70  	if ok {
    71  		delete(c.delayEvents, key)
    72  	}
    73  	c.delayMu.Unlock()
    74  	if ok {
    75  		time.Sleep(dur)
    76  	}
    77  }
    78  
    79  // SplitRaw splits region for raw KV.
    80  func (c *Cluster) SplitRaw(regionID, newRegionID uint64, rawKey []byte, peerIDs []uint64, leaderPeerID uint64) *spacetimepb.Region {
    81  	encodedKey := codec.EncodeBytes(nil, rawKey)
    82  	return c.MockRegionManager.SplitRaw(regionID, newRegionID, encodedKey, peerIDs, leaderPeerID)
    83  }
    84  
    85  // BootstrapWithSingleStore initializes a Cluster with 1 Region and 1 CausetStore.
    86  func BootstrapWithSingleStore(cluster *Cluster) (storeID, peerID, regionID uint64) {
    87  	storeID, regionID, peerID = cluster.AllocID(), cluster.AllocID(), cluster.AllocID()
    88  	causetstore := &spacetimepb.CausetStore{
    89  		Id:      storeID,
    90  		Address: fmt.Sprintf("causetstore%d", storeID),
    91  	}
    92  	region := &spacetimepb.Region{
    93  		Id:          regionID,
    94  		RegionEpoch: &spacetimepb.RegionEpoch{ConfVer: 1, Version: 1},
    95  		Peers:       []*spacetimepb.Peer{{Id: peerID, StoreId: storeID}},
    96  	}
    97  	if err := cluster.Bootstrap([]*spacetimepb.CausetStore{causetstore}, region); err != nil {
    98  		panic(err)
    99  	}
   100  	return
   101  }
   102  
   103  // BootstrapWithMultiStores initializes a Cluster with 1 Region and n Stores.
   104  func BootstrapWithMultiStores(cluster *Cluster, n int) (storeIDs, peerIDs []uint64, regionID uint64, leaderPeer uint64) {
   105  	storeIDs = cluster.AllocIDs(n)
   106  	peerIDs = cluster.AllocIDs(n)
   107  	leaderPeer = peerIDs[0]
   108  	regionID = cluster.AllocID()
   109  	stores := make([]*spacetimepb.CausetStore, n)
   110  	for i, storeID := range storeIDs {
   111  		stores[i] = &spacetimepb.CausetStore{
   112  			Id:      storeID,
   113  			Address: fmt.Sprintf("causetstore%d", storeID),
   114  		}
   115  	}
   116  	peers := make([]*spacetimepb.Peer, n)
   117  	for i, peerID := range peerIDs {
   118  		peers[i] = &spacetimepb.Peer{
   119  			Id:      peerID,
   120  			StoreId: storeIDs[i],
   121  		}
   122  	}
   123  	region := &spacetimepb.Region{
   124  		Id:          regionID,
   125  		RegionEpoch: &spacetimepb.RegionEpoch{ConfVer: 1, Version: 1},
   126  		Peers:       peers,
   127  	}
   128  	if err := cluster.Bootstrap(stores, region); err != nil {
   129  		panic(err)
   130  	}
   131  	return
   132  }
   133  
   134  // BootstrapWithMultiRegions initializes a Cluster with multiple Regions and 1
   135  // CausetStore. The number of Regions will be len(splitKeys) + 1.
   136  func BootstrapWithMultiRegions(cluster *Cluster, splitKeys ...[]byte) (storeID uint64, regionIDs, peerIDs []uint64) {
   137  	var firstRegionID, firstPeerID uint64
   138  	storeID, firstPeerID, firstRegionID = BootstrapWithSingleStore(cluster)
   139  	regionIDs = append([]uint64{firstRegionID}, cluster.AllocIDs(len(splitKeys))...)
   140  	peerIDs = append([]uint64{firstPeerID}, cluster.AllocIDs(len(splitKeys))...)
   141  	for i, k := range splitKeys {
   142  		cluster.Split(regionIDs[i], regionIDs[i+1], k, []uint64{peerIDs[i]}, peerIDs[i])
   143  	}
   144  	return
   145  }