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  }