// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package drainer import ( "github.com/hashicorp/nomad/nomad/structs" ) const ( // defaultMaxIdsPerTxn is the maximum number of IDs that can be included in a // single Raft transaction. This is to ensure that the Raft message // does not become too large. defaultMaxIdsPerTxn = (1024 * 256) / 36 // 0.25 MB of ids. ) // partitionIds takes a set of IDs and returns a partitioned view of them such // that no batch would result in an overly large raft transaction. func partitionIds(maxIds int, ids []string) [][]string { index := 0 total := len(ids) var partitions [][]string for remaining := total - index; remaining > 0; remaining = total - index { if remaining < maxIds { partitions = append(partitions, ids[index:]) break } else { partitions = append(partitions, ids[index:index+maxIds]) index += maxIds } } return partitions } // transitionTuple is used to group desired transitions and evals type transitionTuple struct { Transitions map[string]*structs.DesiredTransition Evals []*structs.Evaluation } // partitionAllocDrain returns a list of alloc transitions and evals to apply // in a single raft transaction.This is necessary to ensure that the Raft // transaction does not become too large. func partitionAllocDrain(maxIds int, transitions map[string]*structs.DesiredTransition, evals []*structs.Evaluation) []*transitionTuple { // Determine a stable ordering of the transitioning allocs allocs := make([]string, 0, len(transitions)) for id := range transitions { allocs = append(allocs, id) } var requests []*transitionTuple submittedEvals, submittedTrans := 0, 0 for submittedEvals != len(evals) || submittedTrans != len(transitions) { req := &transitionTuple{ Transitions: make(map[string]*structs.DesiredTransition), } requests = append(requests, req) available := maxIds // Add the allocs first if remaining := len(allocs) - submittedTrans; remaining > 0 { if remaining <= available { for _, id := range allocs[submittedTrans:] { req.Transitions[id] = transitions[id] } available -= remaining submittedTrans += remaining } else { for _, id := range allocs[submittedTrans : submittedTrans+available] { req.Transitions[id] = transitions[id] } submittedTrans += available // Exhausted space so skip adding evals continue } } // Add the evals if remaining := len(evals) - submittedEvals; remaining > 0 { if remaining <= available { req.Evals = evals[submittedEvals:] submittedEvals += remaining } else { req.Evals = evals[submittedEvals : submittedEvals+available] submittedEvals += available } } } return requests }