github.com/matrixorigin/matrixone@v1.2.0/pkg/pb/logservice/logservice.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 logservice 16 17 import ( 18 "fmt" 19 "reflect" 20 "sort" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 24 ) 25 26 const ( 27 // NoLeader is the replica ID of the leader node. 28 NoLeader uint64 = 0 29 // HeaderSize is the size of the header for each logservice and 30 // hakeeper command. 31 HeaderSize = 4 32 ) 33 34 // ResizePayload resizes the payload length to length bytes. 35 func (m *LogRecord) ResizePayload(length int) { 36 m.Data = m.Data[:HeaderSize+8+length] 37 } 38 39 // Payload returns the payload byte slice. 40 func (m *LogRecord) Payload() []byte { 41 return m.Data[HeaderSize+8:] 42 } 43 44 // NewRSMState creates a new HAKeeperRSMState instance. 45 func NewRSMState() HAKeeperRSMState { 46 return HAKeeperRSMState{ 47 NextIDByKey: make(map[string]uint64), 48 ScheduleCommands: make(map[string]CommandBatch), 49 LogShards: make(map[string]uint64), 50 CNState: NewCNState(), 51 TNState: NewTNState(), 52 LogState: NewLogState(), 53 ProxyState: NewProxyState(), 54 ClusterInfo: newClusterInfo(), 55 } 56 } 57 58 func newClusterInfo() ClusterInfo { 59 return ClusterInfo{ 60 TNShards: make([]metadata.TNShardRecord, 0), 61 LogShards: make([]metadata.LogShardRecord, 0), 62 } 63 } 64 65 // NewCNState creates a new CNState. 66 func NewCNState() CNState { 67 return CNState{ 68 Stores: make(map[string]CNStoreInfo), 69 } 70 } 71 72 // Update applies the incoming CNStoreHeartbeat into HAKeeper. Tick is the 73 // current tick of the HAKeeper which is used as the timestamp of the heartbeat. 74 func (s *CNState) Update(hb CNStoreHeartbeat, tick uint64) { 75 storeInfo, ok := s.Stores[hb.UUID] 76 if !ok { 77 storeInfo = CNStoreInfo{} 78 storeInfo.Labels = make(map[string]metadata.LabelList) 79 storeInfo.UpTime = time.Now().UnixNano() 80 } 81 if storeInfo.WorkState == metadata.WorkState_Unknown { // set init value 82 v, ok := metadata.WorkState_value[metadata.ToTitle(hb.InitWorkState)] 83 if !ok || v == int32(metadata.WorkState_Unknown) { 84 storeInfo.WorkState = metadata.WorkState_Working 85 } else { 86 storeInfo.WorkState = metadata.WorkState(v) 87 } 88 } 89 storeInfo.Tick = tick 90 storeInfo.ServiceAddress = hb.ServiceAddress 91 storeInfo.SQLAddress = hb.SQLAddress 92 storeInfo.LockServiceAddress = hb.LockServiceAddress 93 storeInfo.Role = hb.Role 94 storeInfo.TaskServiceCreated = hb.TaskServiceCreated 95 storeInfo.QueryAddress = hb.QueryAddress 96 storeInfo.GossipAddress = hb.GossipAddress 97 storeInfo.GossipJoined = hb.GossipJoined 98 if hb.ConfigData != nil { 99 storeInfo.ConfigData = hb.ConfigData 100 } 101 storeInfo.Resource = hb.Resource 102 s.Stores[hb.UUID] = storeInfo 103 } 104 105 // UpdateLabel updates labels of CN store. 106 func (s *CNState) UpdateLabel(label CNStoreLabel) { 107 storeInfo, ok := s.Stores[label.UUID] 108 // If the CN store does not exist, we should do nothing and wait for 109 // CN heartbeat. 110 if !ok { 111 return 112 } 113 storeInfo.Labels = label.Labels 114 s.Stores[label.UUID] = storeInfo 115 } 116 117 // UpdateWorkState updates work state of CN store. 118 func (s *CNState) UpdateWorkState(state CNWorkState) { 119 if state.GetState() == metadata.WorkState_Unknown { 120 state.State = metadata.WorkState_Working 121 } 122 storeInfo, ok := s.Stores[state.UUID] 123 // If the CN store does not exist, we should do nothing and wait for 124 // CN heartbeat. 125 if !ok { 126 return 127 } 128 storeInfo.WorkState = state.State 129 s.Stores[state.UUID] = storeInfo 130 } 131 132 // PatchCNStore updates work state and labels of CN store. 133 func (s *CNState) PatchCNStore(stateLabel CNStateLabel) { 134 if stateLabel.GetState() == metadata.WorkState_Unknown { 135 stateLabel.State = metadata.WorkState_Working 136 } 137 storeInfo, ok := s.Stores[stateLabel.UUID] 138 // If the CN store does not exist, we should do nothing and wait for 139 // CN heartbeat. 140 if !ok { 141 return 142 } 143 storeInfo.WorkState = stateLabel.State 144 if stateLabel.Labels != nil { 145 storeInfo.Labels = stateLabel.Labels 146 } 147 s.Stores[stateLabel.UUID] = storeInfo 148 } 149 150 // NewTNState creates a new DNState. 151 func NewTNState() TNState { 152 return TNState{ 153 Stores: make(map[string]TNStoreInfo), 154 } 155 } 156 157 // Update applies the incoming DNStoreHeartbeat into HAKeeper. Tick is the 158 // current tick of the HAKeeper which is used as the timestamp of the heartbeat. 159 func (s *TNState) Update(hb TNStoreHeartbeat, tick uint64) { 160 storeInfo, ok := s.Stores[hb.UUID] 161 if !ok { 162 storeInfo = TNStoreInfo{} 163 } 164 storeInfo.Tick = tick 165 storeInfo.Shards = hb.Shards 166 storeInfo.ServiceAddress = hb.ServiceAddress 167 storeInfo.LogtailServerAddress = hb.LogtailServerAddress 168 storeInfo.LockServiceAddress = hb.LockServiceAddress 169 storeInfo.TaskServiceCreated = hb.TaskServiceCreated 170 if hb.ConfigData != nil { 171 storeInfo.ConfigData = hb.ConfigData 172 } 173 storeInfo.QueryAddress = hb.QueryAddress 174 s.Stores[hb.UUID] = storeInfo 175 } 176 177 // NewLogState creates a new LogState. 178 func NewLogState() LogState { 179 return LogState{ 180 Shards: make(map[uint64]LogShardInfo), 181 Stores: make(map[string]LogStoreInfo), 182 } 183 } 184 185 // Update applies the incoming heartbeat message to the LogState with the 186 // specified tick used as the timestamp. 187 func (s *LogState) Update(hb LogStoreHeartbeat, tick uint64) { 188 s.updateStores(hb, tick) 189 s.updateShards(hb) 190 } 191 192 func (s *LogState) updateStores(hb LogStoreHeartbeat, tick uint64) { 193 storeInfo, ok := s.Stores[hb.UUID] 194 if !ok { 195 storeInfo = LogStoreInfo{} 196 } 197 storeInfo.Tick = tick 198 storeInfo.RaftAddress = hb.RaftAddress 199 storeInfo.ServiceAddress = hb.ServiceAddress 200 storeInfo.GossipAddress = hb.GossipAddress 201 storeInfo.Replicas = hb.Replicas 202 storeInfo.TaskServiceCreated = hb.TaskServiceCreated 203 if hb.ConfigData != nil { 204 storeInfo.ConfigData = hb.ConfigData 205 } 206 s.Stores[hb.UUID] = storeInfo 207 } 208 209 func (s *LogState) updateShards(hb LogStoreHeartbeat) { 210 for _, incoming := range hb.Replicas { 211 recorded, ok := s.Shards[incoming.ShardID] 212 if !ok { 213 recorded = LogShardInfo{ 214 ShardID: incoming.ShardID, 215 Replicas: make(map[uint64]string), 216 } 217 } 218 219 if incoming.Epoch > recorded.Epoch { 220 recorded.Epoch = incoming.Epoch 221 recorded.Replicas = incoming.Replicas 222 } else if incoming.Epoch == recorded.Epoch && incoming.Epoch > 0 { 223 if !reflect.DeepEqual(recorded.Replicas, incoming.Replicas) { 224 panic(fmt.Sprintf("inconsistent replicas, recorded: %+v, incoming: %+v", 225 recorded, incoming)) 226 } 227 } 228 229 if incoming.Term > recorded.Term && incoming.LeaderID != NoLeader { 230 recorded.Term = incoming.Term 231 recorded.LeaderID = incoming.LeaderID 232 } 233 234 s.Shards[incoming.ShardID] = recorded 235 } 236 } 237 238 // LogString returns "ServiceType/ConfigChangeType UUID RepUuid:RepShardID:RepID InitialMembers". 239 // Do not add CN's StartTaskRunner info to log string, because there has user and password. 240 func (m *ScheduleCommand) LogString() string { 241 c := func(s string) string { 242 return s 243 } 244 245 serviceType := map[ServiceType]string{ 246 LogService: "L", 247 TNService: "D", 248 CNService: "C", 249 ProxyService: "P", 250 }[m.ServiceType] 251 252 target := c(m.UUID) 253 if m.ShutdownStore != nil { 254 return fmt.Sprintf("%s/shutdown %s", serviceType, target) 255 } 256 if m.CreateTaskService != nil { 257 return fmt.Sprintf("%s/CreateTask %s", serviceType, target) 258 } 259 if m.DeleteCNStore != nil { 260 return fmt.Sprintf("%s/DeleteCNStore %s", serviceType, target) 261 } 262 if m.JoinGossipCluster != nil { 263 return fmt.Sprintf("%s/JoinGossipCluster %s", serviceType, target) 264 } 265 if m.DeleteProxyStore != nil { 266 return fmt.Sprintf("%s/DeleteProxyStore %s", serviceType, target) 267 } 268 if m.ConfigChange == nil { 269 return fmt.Sprintf("%s/unknown command %s", serviceType, m.String()) 270 } 271 272 configChangeType := "Unknown" 273 if m.ConfigChange != nil { 274 configChangeType = map[ConfigChangeType]string{ 275 AddReplica: "Add", 276 RemoveReplica: "Remove", 277 StartReplica: "Start", 278 StopReplica: "Stop", 279 KillZombie: "Kill", 280 }[m.ConfigChange.ChangeType] 281 } 282 283 replica := c(m.ConfigChange.Replica.UUID) 284 s := fmt.Sprintf("%s/%s %s %s:%d:%d:%d", 285 serviceType, configChangeType, target, replica, 286 m.ConfigChange.Replica.ShardID, 287 m.ConfigChange.Replica.ReplicaID, 288 m.ConfigChange.Replica.Epoch) 289 290 if len(m.ConfigChange.InitialMembers) != 0 { 291 initMembers := make([]string, 0, len(m.ConfigChange.InitialMembers)) 292 for repId, uuid := range m.ConfigChange.InitialMembers { 293 initMembers = append(initMembers, fmt.Sprintf("%d:%s", repId, c(uuid))) 294 } 295 sort.Strings(initMembers) 296 s += fmt.Sprintf(" %v", initMembers) 297 } 298 299 return s 300 } 301 302 // NewProxyState creates a new ProxyState. 303 func NewProxyState() ProxyState { 304 return ProxyState{ 305 Stores: make(map[string]ProxyStore), 306 } 307 } 308 309 func (s *ProxyState) Update(hb ProxyHeartbeat, tick uint64) { 310 storeInfo, ok := s.Stores[hb.UUID] 311 if !ok { 312 storeInfo = ProxyStore{} 313 } 314 storeInfo.UUID = hb.UUID 315 storeInfo.Tick = tick 316 storeInfo.ListenAddress = hb.ListenAddress 317 if hb.ConfigData != nil { 318 storeInfo.ConfigData = hb.ConfigData 319 } 320 s.Stores[hb.UUID] = storeInfo 321 }