github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/strategy/fill.go (about)

     1  package strategy
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  
     7  	"github.com/cockroachdb/errors"
     8  	"github.com/projecteru2/core/log"
     9  	"github.com/projecteru2/core/types"
    10  	"github.com/projecteru2/core/utils"
    11  )
    12  
    13  // FillPlan deploy workload each node
    14  // 根据之前部署的策略每一台补充到 N 个,已经超过 N 个的节点视为已满足
    15  // need 是每台上限, limit 是限制节点数, 保证最终状态至少有 limit*need 个实例
    16  // limit = 0 代表对所有节点进行填充
    17  func FillPlan(ctx context.Context, infos []Info, need, _, limit int) (_ map[string]int, err error) {
    18  	log.WithFunc("strategy.FillPlan").Debugf(ctx, "need %d limit %d infos %+v", need, limit, infos)
    19  	scheduleInfosLength := len(infos)
    20  	if limit == 0 {
    21  		limit = scheduleInfosLength
    22  	}
    23  	if scheduleInfosLength < limit {
    24  		return nil, errors.Wrapf(types.ErrInsufficientResource, "node len %d cannot alloc a fill node plan", scheduleInfosLength)
    25  	}
    26  	sort.Slice(infos, func(i, j int) bool {
    27  		if infos[i].Count == infos[j].Count {
    28  			return infos[i].Capacity > infos[j].Capacity
    29  		}
    30  		return infos[i].Count > infos[j].Count
    31  	})
    32  	deployMap, toDeploy := make(map[string]int), 0
    33  	for _, info := range infos {
    34  		if info.Count+info.Capacity >= need {
    35  			deployMap[info.Nodename] += utils.Max(need-info.Count, 0)
    36  			toDeploy += deployMap[info.Nodename]
    37  			limit--
    38  			if limit == 0 {
    39  				if toDeploy == 0 {
    40  					err = types.ErrAlreadyFilled
    41  				}
    42  				return deployMap, err
    43  			}
    44  		}
    45  	}
    46  	return nil, errors.Wrapf(types.ErrInsufficientResource, "not enough nodes that can fill up to %d instances, require %d nodes", need, limit)
    47  }