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 }