github.com/matrixorigin/matrixone@v0.7.0/pkg/logservice/service_commands.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  	"context"
    19  	"fmt"
    20  	"reflect"
    21  	"time"
    22  
    23  	"go.uber.org/zap"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/hakeeper"
    26  	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    27  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    28  )
    29  
    30  func (s *Service) handleCommands(cmds []pb.ScheduleCommand) {
    31  	for _, cmd := range cmds {
    32  		s.runtime.Logger().Info(fmt.Sprintf("%s applying cmd: %s", s.ID(), cmd.LogString()))
    33  		if cmd.GetConfigChange() != nil {
    34  			s.runtime.Logger().Debug("applying schedule command:", zap.String("command", cmd.LogString()))
    35  			switch cmd.ConfigChange.ChangeType {
    36  			case pb.AddReplica:
    37  				s.handleAddReplica(cmd)
    38  			case pb.RemoveReplica:
    39  				s.handleRemoveReplica(cmd)
    40  			case pb.StartReplica:
    41  				s.handleStartReplica(cmd)
    42  			case pb.StopReplica:
    43  				s.handleStopReplica(cmd)
    44  			case pb.KillZombie:
    45  				s.handleKillZombie(cmd)
    46  			default:
    47  				panic("unknown config change cmd type")
    48  			}
    49  		} else if cmd.GetShutdownStore() != nil {
    50  			s.handleShutdownStore(cmd)
    51  		} else if cmd.GetCreateTaskService() != nil {
    52  			s.createTaskService(cmd.CreateTaskService)
    53  		} else {
    54  			panic("unknown schedule command type")
    55  		}
    56  	}
    57  }
    58  
    59  func (s *Service) handleAddReplica(cmd pb.ScheduleCommand) {
    60  	shardID := cmd.ConfigChange.Replica.ShardID
    61  	replicaID := cmd.ConfigChange.Replica.ReplicaID
    62  	epoch := cmd.ConfigChange.Replica.Epoch
    63  	target := cmd.ConfigChange.Replica.UUID
    64  	if err := s.store.addReplica(shardID, replicaID, target, epoch); err != nil {
    65  		s.runtime.Logger().Error("failed to add replica", zap.Error(err))
    66  	}
    67  }
    68  
    69  func (s *Service) handleRemoveReplica(cmd pb.ScheduleCommand) {
    70  	shardID := cmd.ConfigChange.Replica.ShardID
    71  	replicaID := cmd.ConfigChange.Replica.ReplicaID
    72  	epoch := cmd.ConfigChange.Replica.Epoch
    73  	if err := s.store.removeReplica(shardID, replicaID, epoch); err != nil {
    74  		s.runtime.Logger().Error("failed to remove replica", zap.Error(err))
    75  	}
    76  }
    77  
    78  func (s *Service) handleStartReplica(cmd pb.ScheduleCommand) {
    79  	shardID := cmd.ConfigChange.Replica.ShardID
    80  	replicaID := cmd.ConfigChange.Replica.ReplicaID
    81  	join := len(cmd.ConfigChange.InitialMembers) == 0
    82  	if shardID == hakeeper.DefaultHAKeeperShardID {
    83  		if err := s.store.startHAKeeperReplica(replicaID,
    84  			cmd.ConfigChange.InitialMembers, join); err != nil {
    85  			s.runtime.Logger().Error("failed to start HAKeeper replica", zap.Error(err))
    86  		}
    87  	} else {
    88  		if err := s.store.startReplica(shardID,
    89  			replicaID, cmd.ConfigChange.InitialMembers, join); err != nil {
    90  			s.runtime.Logger().Error("failed to start log replica", zap.Error(err))
    91  		}
    92  	}
    93  }
    94  
    95  func (s *Service) handleStopReplica(cmd pb.ScheduleCommand) {
    96  	shardID := cmd.ConfigChange.Replica.ShardID
    97  	replicaID := cmd.ConfigChange.Replica.ReplicaID
    98  	if err := s.store.stopReplica(shardID, replicaID); err != nil {
    99  		s.runtime.Logger().Error("failed to stop replica", zap.Error(err))
   100  	}
   101  }
   102  
   103  func (s *Service) handleKillZombie(cmd pb.ScheduleCommand) {
   104  	shardID := cmd.ConfigChange.Replica.ShardID
   105  	replicaID := cmd.ConfigChange.Replica.ReplicaID
   106  	s.handleStopReplica(cmd)
   107  	s.store.removeMetadata(shardID, replicaID)
   108  }
   109  
   110  func (s *Service) handleShutdownStore(_ pb.ScheduleCommand) {
   111  	if err := s.Close(); err != nil {
   112  		s.runtime.Logger().Error("failed to shutdown replica", zap.Error(err))
   113  	}
   114  }
   115  
   116  func (s *Service) heartbeatWorker(ctx context.Context) {
   117  	// TODO: check tick interval
   118  	if s.cfg.HeartbeatInterval.Duration == 0 {
   119  		panic("invalid heartbeat interval")
   120  	}
   121  	defer func() {
   122  		s.runtime.Logger().Info("heartbeat worker stopped")
   123  	}()
   124  	ticker := time.NewTicker(s.cfg.HeartbeatInterval.Duration)
   125  	defer ticker.Stop()
   126  	ctx, span := trace.Start(ctx, "heartbeatWorker")
   127  	defer span.End()
   128  
   129  	for {
   130  		select {
   131  		case <-ctx.Done():
   132  			return
   133  		case <-ticker.C:
   134  			s.heartbeat(ctx)
   135  			// I'd call this an ugly hack to just workaround select's
   136  			// policy of randomly picking a ready channel from the case list.
   137  			select {
   138  			case <-ctx.Done():
   139  				return
   140  			default:
   141  			}
   142  		}
   143  	}
   144  }
   145  
   146  func (s *Service) heartbeat(ctx context.Context) {
   147  	ctx2, cancel := context.WithTimeout(ctx, 3*time.Second)
   148  	defer cancel()
   149  
   150  	if s.haClient == nil {
   151  		if reflect.DeepEqual(s.cfg.HAKeeperClientConfig, HAKeeperClientConfig{}) {
   152  			panic("empty HAKeeper client config")
   153  		}
   154  		cc, err := NewLogHAKeeperClient(ctx2, s.cfg.GetHAKeeperClientConfig())
   155  		if err != nil {
   156  			s.runtime.Logger().Error("failed to create HAKeeper client", zap.Error(err))
   157  			return
   158  		}
   159  		s.haClient = cc
   160  	}
   161  
   162  	hb := s.store.getHeartbeatMessage()
   163  	hb.TaskServiceCreated = s.taskServiceCreated()
   164  	cb, err := s.haClient.SendLogHeartbeat(ctx2, hb)
   165  	if err != nil {
   166  		s.runtime.Logger().Error("failed to send log service heartbeat", zap.Error(err))
   167  		return
   168  	}
   169  	s.handleCommands(cb.Commands)
   170  }