github.com/matrixorigin/matrixone@v0.7.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  
    22  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    23  )
    24  
    25  const (
    26  	// NoLeader is the replica ID of the leader node.
    27  	NoLeader uint64 = 0
    28  	// HeaderSize is the size of the header for each logservice and
    29  	// hakeeper command.
    30  	HeaderSize = 4
    31  )
    32  
    33  // ResizePayload resizes the payload length to length bytes.
    34  func (m *LogRecord) ResizePayload(length int) {
    35  	m.Data = m.Data[:HeaderSize+8+length]
    36  }
    37  
    38  // Payload returns the payload byte slice.
    39  func (m *LogRecord) Payload() []byte {
    40  	return m.Data[HeaderSize+8:]
    41  }
    42  
    43  // NewRSMState creates a new HAKeeperRSMState instance.
    44  func NewRSMState() HAKeeperRSMState {
    45  	return HAKeeperRSMState{
    46  		ScheduleCommands: make(map[string]CommandBatch),
    47  		LogShards:        make(map[string]uint64),
    48  		CNState:          NewCNState(),
    49  		DNState:          NewDNState(),
    50  		LogState:         NewLogState(),
    51  		ClusterInfo:      newClusterInfo(),
    52  	}
    53  }
    54  
    55  func newClusterInfo() ClusterInfo {
    56  	return ClusterInfo{
    57  		DNShards:  make([]metadata.DNShardRecord, 0),
    58  		LogShards: make([]metadata.LogShardRecord, 0),
    59  	}
    60  }
    61  
    62  // NewCNState creates a new CNState.
    63  func NewCNState() CNState {
    64  	return CNState{
    65  		Stores: make(map[string]CNStoreInfo),
    66  	}
    67  }
    68  
    69  // Update applies the incoming CNStoreHeartbeat into HAKeeper. Tick is the
    70  // current tick of the HAKeeper which is used as the timestamp of the heartbeat.
    71  func (s *CNState) Update(hb CNStoreHeartbeat, tick uint64) {
    72  	storeInfo, ok := s.Stores[hb.UUID]
    73  	if !ok {
    74  		storeInfo = CNStoreInfo{}
    75  	}
    76  	storeInfo.Tick = tick
    77  	storeInfo.ServiceAddress = hb.ServiceAddress
    78  	storeInfo.SQLAddress = hb.SQLAddress
    79  	storeInfo.Role = hb.Role
    80  	storeInfo.TaskServiceCreated = hb.TaskServiceCreated
    81  	s.Stores[hb.UUID] = storeInfo
    82  }
    83  
    84  // NewDNState creates a new DNState.
    85  func NewDNState() DNState {
    86  	return DNState{
    87  		Stores: make(map[string]DNStoreInfo),
    88  	}
    89  }
    90  
    91  // Update applies the incoming DNStoreHeartbeat into HAKeeper. Tick is the
    92  // current tick of the HAKeeper which is used as the timestamp of the heartbeat.
    93  func (s *DNState) Update(hb DNStoreHeartbeat, tick uint64) {
    94  	storeInfo, ok := s.Stores[hb.UUID]
    95  	if !ok {
    96  		storeInfo = DNStoreInfo{}
    97  	}
    98  	storeInfo.Tick = tick
    99  	storeInfo.Shards = hb.Shards
   100  	storeInfo.ServiceAddress = hb.ServiceAddress
   101  	storeInfo.LogtailServerAddress = hb.LogtailServerAddress
   102  	storeInfo.TaskServiceCreated = hb.TaskServiceCreated
   103  	s.Stores[hb.UUID] = storeInfo
   104  }
   105  
   106  // NewLogState creates a new LogState.
   107  func NewLogState() LogState {
   108  	return LogState{
   109  		Shards: make(map[uint64]LogShardInfo),
   110  		Stores: make(map[string]LogStoreInfo),
   111  	}
   112  }
   113  
   114  // Update applies the incoming heartbeat message to the LogState with the
   115  // specified tick used as the timestamp.
   116  func (s *LogState) Update(hb LogStoreHeartbeat, tick uint64) {
   117  	s.updateStores(hb, tick)
   118  	s.updateShards(hb)
   119  }
   120  
   121  func (s *LogState) updateStores(hb LogStoreHeartbeat, tick uint64) {
   122  	storeInfo, ok := s.Stores[hb.UUID]
   123  	if !ok {
   124  		storeInfo = LogStoreInfo{}
   125  	}
   126  	storeInfo.Tick = tick
   127  	storeInfo.RaftAddress = hb.RaftAddress
   128  	storeInfo.ServiceAddress = hb.ServiceAddress
   129  	storeInfo.GossipAddress = hb.GossipAddress
   130  	storeInfo.Replicas = hb.Replicas
   131  	storeInfo.TaskServiceCreated = hb.TaskServiceCreated
   132  	s.Stores[hb.UUID] = storeInfo
   133  }
   134  
   135  func (s *LogState) updateShards(hb LogStoreHeartbeat) {
   136  	for _, incoming := range hb.Replicas {
   137  		recorded, ok := s.Shards[incoming.ShardID]
   138  		if !ok {
   139  			recorded = LogShardInfo{
   140  				ShardID:  incoming.ShardID,
   141  				Replicas: make(map[uint64]string),
   142  			}
   143  		}
   144  
   145  		if incoming.Epoch > recorded.Epoch {
   146  			recorded.Epoch = incoming.Epoch
   147  			recorded.Replicas = incoming.Replicas
   148  		} else if incoming.Epoch == recorded.Epoch && incoming.Epoch > 0 {
   149  			if !reflect.DeepEqual(recorded.Replicas, incoming.Replicas) {
   150  				panic("inconsistent replicas")
   151  			}
   152  		}
   153  
   154  		if incoming.Term > recorded.Term && incoming.LeaderID != NoLeader {
   155  			recorded.Term = incoming.Term
   156  			recorded.LeaderID = incoming.LeaderID
   157  		}
   158  
   159  		s.Shards[incoming.ShardID] = recorded
   160  	}
   161  }
   162  
   163  // LogString returns "ServiceType/ConfigChangeType UUID RepUuid:RepShardID:RepID InitialMembers".
   164  // Do not add CN's StartTaskRunner info to log string, because there has user and password.
   165  func (m *ScheduleCommand) LogString() string {
   166  	c := func(s string) string {
   167  		if len(s) > 6 {
   168  			return s[:6]
   169  		}
   170  		return s
   171  	}
   172  
   173  	serviceType := map[ServiceType]string{
   174  		LogService: "L",
   175  		DNService:  "D",
   176  		CNService:  "C",
   177  	}[m.ServiceType]
   178  
   179  	target := c(m.UUID)
   180  	if m.ShutdownStore != nil {
   181  		return fmt.Sprintf("%s/shutdown %s", serviceType, target)
   182  	}
   183  	if m.CreateTaskService != nil {
   184  		return fmt.Sprintf("%s/CreateTask %s", serviceType, target)
   185  	}
   186  	if m.ConfigChange == nil {
   187  		return fmt.Sprintf("%s/unknown command %s", serviceType, m.String())
   188  	}
   189  
   190  	configChangeType := "Unknown"
   191  	if m.ConfigChange != nil {
   192  		configChangeType = map[ConfigChangeType]string{
   193  			AddReplica:    "Add",
   194  			RemoveReplica: "Remove",
   195  			StartReplica:  "Start",
   196  			StopReplica:   "Stop",
   197  			KillZombie:    "Kill",
   198  		}[m.ConfigChange.ChangeType]
   199  	}
   200  
   201  	replica := c(m.ConfigChange.Replica.UUID)
   202  	s := fmt.Sprintf("%s/%s %s %s:%d:%d:%d",
   203  		serviceType, configChangeType, target, replica,
   204  		m.ConfigChange.Replica.ShardID,
   205  		m.ConfigChange.Replica.ReplicaID,
   206  		m.ConfigChange.Replica.Epoch)
   207  
   208  	if len(m.ConfigChange.InitialMembers) != 0 {
   209  		initMembers := make([]string, 0, len(m.ConfigChange.InitialMembers))
   210  		for repId, uuid := range m.ConfigChange.InitialMembers {
   211  			initMembers = append(initMembers, fmt.Sprintf("%d:%s", repId, c(uuid)))
   212  		}
   213  		sort.Strings(initMembers)
   214  		s += fmt.Sprintf(" %v", initMembers)
   215  	}
   216  
   217  	return s
   218  }