github.com/hernad/nomad@v1.6.112/nomad/drainer/drainer_util.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package drainer
     5  
     6  import (
     7  	"github.com/hernad/nomad/nomad/structs"
     8  )
     9  
    10  const (
    11  	// defaultMaxIdsPerTxn is the maximum number of IDs that can be included in a
    12  	// single Raft transaction. This is to ensure that the Raft message
    13  	// does not become too large.
    14  	defaultMaxIdsPerTxn = (1024 * 256) / 36 // 0.25 MB of ids.
    15  )
    16  
    17  // partitionIds takes a set of IDs and returns a partitioned view of them such
    18  // that no batch would result in an overly large raft transaction.
    19  func partitionIds(maxIds int, ids []string) [][]string {
    20  	index := 0
    21  	total := len(ids)
    22  	var partitions [][]string
    23  	for remaining := total - index; remaining > 0; remaining = total - index {
    24  		if remaining < maxIds {
    25  			partitions = append(partitions, ids[index:])
    26  			break
    27  		} else {
    28  			partitions = append(partitions, ids[index:index+maxIds])
    29  			index += maxIds
    30  		}
    31  	}
    32  
    33  	return partitions
    34  }
    35  
    36  // transitionTuple is used to group desired transitions and evals
    37  type transitionTuple struct {
    38  	Transitions map[string]*structs.DesiredTransition
    39  	Evals       []*structs.Evaluation
    40  }
    41  
    42  // partitionAllocDrain returns a list of alloc transitions and evals to apply
    43  // in a single raft transaction.This is necessary to ensure that the Raft
    44  // transaction does not become too large.
    45  func partitionAllocDrain(maxIds int, transitions map[string]*structs.DesiredTransition,
    46  	evals []*structs.Evaluation) []*transitionTuple {
    47  
    48  	// Determine a stable ordering of the transitioning allocs
    49  	allocs := make([]string, 0, len(transitions))
    50  	for id := range transitions {
    51  		allocs = append(allocs, id)
    52  	}
    53  
    54  	var requests []*transitionTuple
    55  	submittedEvals, submittedTrans := 0, 0
    56  	for submittedEvals != len(evals) || submittedTrans != len(transitions) {
    57  		req := &transitionTuple{
    58  			Transitions: make(map[string]*structs.DesiredTransition),
    59  		}
    60  		requests = append(requests, req)
    61  		available := maxIds
    62  
    63  		// Add the allocs first
    64  		if remaining := len(allocs) - submittedTrans; remaining > 0 {
    65  			if remaining <= available {
    66  				for _, id := range allocs[submittedTrans:] {
    67  					req.Transitions[id] = transitions[id]
    68  				}
    69  				available -= remaining
    70  				submittedTrans += remaining
    71  			} else {
    72  				for _, id := range allocs[submittedTrans : submittedTrans+available] {
    73  					req.Transitions[id] = transitions[id]
    74  				}
    75  				submittedTrans += available
    76  
    77  				// Exhausted space so skip adding evals
    78  				continue
    79  			}
    80  
    81  		}
    82  
    83  		// Add the evals
    84  		if remaining := len(evals) - submittedEvals; remaining > 0 {
    85  			if remaining <= available {
    86  				req.Evals = evals[submittedEvals:]
    87  				submittedEvals += remaining
    88  			} else {
    89  				req.Evals = evals[submittedEvals : submittedEvals+available]
    90  				submittedEvals += available
    91  			}
    92  		}
    93  	}
    94  
    95  	return requests
    96  }