github.com/matrixorigin/matrixone@v1.2.0/pkg/hakeeper/bootstrap/bootstrap.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bootstrap 16 17 import ( 18 "sort" 19 20 "github.com/matrixorigin/matrixone/pkg/common/moerr" 21 "github.com/matrixorigin/matrixone/pkg/common/runtime" 22 "github.com/matrixorigin/matrixone/pkg/hakeeper/checkers/util" 23 pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 24 "github.com/mohae/deepcopy" 25 "go.uber.org/zap" 26 ) 27 28 type Manager struct { 29 cluster pb.ClusterInfo 30 } 31 32 func NewBootstrapManager(cluster pb.ClusterInfo) *Manager { 33 nc, ok := deepcopy.Copy(cluster).(pb.ClusterInfo) 34 if !ok { 35 panic("deep copy failed") 36 } 37 38 return &Manager{ 39 cluster: nc, 40 } 41 } 42 43 func (bm *Manager) Bootstrap(alloc util.IDAllocator, 44 tn pb.TNState, log pb.LogState) ([]pb.ScheduleCommand, error) { 45 logCommands, err := bm.bootstrapLogService(alloc, log) 46 tnCommands := bm.bootstrapTN(alloc, tn) 47 if err != nil { 48 return nil, err 49 } 50 51 commands := append(logCommands, tnCommands...) 52 for _, command := range commands { 53 runtime.ProcessLevelRuntime().SubLogger(runtime.SystemInit).Info("schedule command generated", 54 zap.String("command", command.LogString())) 55 } 56 if len(commands) != 0 { 57 runtime.ProcessLevelRuntime().SubLogger(runtime.SystemInit).Info("schedule command generated") 58 } 59 return commands, nil 60 } 61 62 func (bm *Manager) bootstrapLogService(alloc util.IDAllocator, 63 log pb.LogState) (commands []pb.ScheduleCommand, err error) { 64 logStores := logStoresSortedByTick(log.Stores) 65 66 for _, shardRecord := range bm.cluster.LogShards { 67 // skip HAKeeper shard 68 if shardRecord.ShardID == 0 { 69 continue 70 } 71 72 if shardRecord.NumberOfReplicas > uint64(len(logStores)) { 73 return nil, moerr.NewInternalErrorNoCtx("not enough log stores") 74 } 75 76 initialMembers := make(map[uint64]string) 77 for i := uint64(0); i < shardRecord.NumberOfReplicas; i++ { 78 replicaID, ok := alloc.Next() 79 if !ok { 80 return nil, moerr.NewInternalErrorNoCtx("id allocator error") 81 } 82 83 initialMembers[replicaID] = logStores[i] 84 } 85 86 for replicaID, uuid := range initialMembers { 87 commands = append(commands, 88 pb.ScheduleCommand{ 89 UUID: uuid, 90 Bootstrapping: true, 91 ConfigChange: &pb.ConfigChange{ 92 Replica: pb.Replica{ 93 UUID: uuid, 94 ShardID: shardRecord.ShardID, 95 ReplicaID: replicaID, 96 }, 97 ChangeType: pb.StartReplica, 98 InitialMembers: initialMembers, 99 }, 100 ServiceType: pb.LogService, 101 }) 102 } 103 } 104 return 105 } 106 107 func (bm *Manager) bootstrapTN(alloc util.IDAllocator, tn pb.TNState) (commands []pb.ScheduleCommand) { 108 tnStores := tnStoresSortedByTick(tn.Stores) 109 if len(tnStores) < len(bm.cluster.TNShards) { 110 return nil 111 } 112 113 for i, tnRecord := range bm.cluster.TNShards { 114 if i >= len(tnStores) { 115 i = i % len(tnStores) 116 } 117 replicaID, ok := alloc.Next() 118 if !ok { 119 return nil 120 } 121 122 commands = append(commands, pb.ScheduleCommand{ 123 UUID: tnStores[i], 124 Bootstrapping: true, 125 ConfigChange: &pb.ConfigChange{ 126 Replica: pb.Replica{ 127 UUID: tnStores[i], 128 ShardID: tnRecord.ShardID, 129 ReplicaID: replicaID, 130 LogShardID: tnRecord.LogShardID, 131 }, 132 ChangeType: pb.StartReplica, 133 }, 134 ServiceType: pb.TNService, 135 }) 136 } 137 138 return 139 } 140 141 func (bm *Manager) CheckBootstrap(log pb.LogState) bool { 142 for _, shardRecord := range bm.cluster.LogShards { 143 shardInfo, ok := log.Shards[shardRecord.ShardID] 144 if !ok { 145 return false 146 } 147 148 if uint64(len(shardInfo.Replicas))*2 <= shardRecord.NumberOfReplicas { 149 return false 150 } 151 } 152 153 return true 154 } 155 156 func logStoresSortedByTick(logStores map[string]pb.LogStoreInfo) []string { 157 uuidSlice := make([]string, 0, len(logStores)) 158 159 for uuid := range logStores { 160 uuidSlice = append(uuidSlice, uuid) 161 } 162 163 sort.Slice(uuidSlice, func(i, j int) bool { 164 return logStores[uuidSlice[i]].Tick > logStores[uuidSlice[j]].Tick 165 }) 166 167 return uuidSlice 168 } 169 170 func tnStoresSortedByTick(tnStores map[string]pb.TNStoreInfo) []string { 171 uuidSlice := make([]string, 0, len(tnStores)) 172 for uuid := range tnStores { 173 uuidSlice = append(uuidSlice, uuid) 174 } 175 176 sort.Slice(uuidSlice, func(i, j int) bool { 177 return tnStores[uuidSlice[i]].Tick > tnStores[uuidSlice[j]].Tick 178 }) 179 180 return uuidSlice 181 }