2018-03-10 00:10:38 +00:00
|
|
|
package drainer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
2018-04-02 23:40:47 +00:00
|
|
|
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.
|
2018-03-10 00:10:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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.
|
2018-04-02 23:40:47 +00:00
|
|
|
func partitionIds(maxIds int, ids []string) [][]string {
|
2018-03-10 00:10:38 +00:00
|
|
|
index := 0
|
|
|
|
total := len(ids)
|
|
|
|
var partitions [][]string
|
|
|
|
for remaining := total - index; remaining > 0; remaining = total - index {
|
2018-04-02 23:40:47 +00:00
|
|
|
if remaining < maxIds {
|
2018-03-10 00:10:38 +00:00
|
|
|
partitions = append(partitions, ids[index:])
|
|
|
|
break
|
|
|
|
} else {
|
2018-04-02 23:40:47 +00:00
|
|
|
partitions = append(partitions, ids[index:index+maxIds])
|
|
|
|
index += maxIds
|
2018-03-10 00:10:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return partitions
|
|
|
|
}
|
|
|
|
|
2018-04-02 23:40:47 +00:00
|
|
|
// transitionTuple is used to group desired transitions and evals
|
|
|
|
type transitionTuple struct {
|
|
|
|
Transitions map[string]*structs.DesiredTransition
|
|
|
|
Evals []*structs.Evaluation
|
2018-03-10 00:10:38 +00:00
|
|
|
}
|
|
|
|
|
2018-04-02 23:40:47 +00:00
|
|
|
// partitionAllocDrain returns a list of alloc transitions and evals to apply
|
2018-03-10 00:10:38 +00:00
|
|
|
// in a single raft transaction.This is necessary to ensure that the Raft
|
|
|
|
// transaction does not become too large.
|
2018-04-02 23:40:47 +00:00
|
|
|
func partitionAllocDrain(maxIds int, transitions map[string]*structs.DesiredTransition,
|
|
|
|
evals []*structs.Evaluation) []*transitionTuple {
|
2018-03-10 00:10:38 +00:00
|
|
|
|
2018-04-02 23:40:47 +00:00
|
|
|
// Determine a stable ordering of the transitioning allocs
|
|
|
|
allocs := make([]string, 0, len(transitions))
|
|
|
|
for id := range transitions {
|
2018-03-10 00:10:38 +00:00
|
|
|
allocs = append(allocs, id)
|
|
|
|
}
|
|
|
|
|
2018-04-02 23:40:47 +00:00
|
|
|
var requests []*transitionTuple
|
2018-03-10 00:10:38 +00:00
|
|
|
submittedEvals, submittedTrans := 0, 0
|
2018-04-02 23:40:47 +00:00
|
|
|
for submittedEvals != len(evals) || submittedTrans != len(transitions) {
|
|
|
|
req := &transitionTuple{
|
|
|
|
Transitions: make(map[string]*structs.DesiredTransition),
|
2018-03-10 00:10:38 +00:00
|
|
|
}
|
|
|
|
requests = append(requests, req)
|
2018-04-02 23:40:47 +00:00
|
|
|
available := maxIds
|
2018-03-10 00:10:38 +00:00
|
|
|
|
|
|
|
// Add the allocs first
|
|
|
|
if remaining := len(allocs) - submittedTrans; remaining > 0 {
|
|
|
|
if remaining <= available {
|
|
|
|
for _, id := range allocs[submittedTrans:] {
|
2018-04-02 23:40:47 +00:00
|
|
|
req.Transitions[id] = transitions[id]
|
2018-03-10 00:10:38 +00:00
|
|
|
}
|
|
|
|
available -= remaining
|
|
|
|
submittedTrans += remaining
|
|
|
|
} else {
|
|
|
|
for _, id := range allocs[submittedTrans : submittedTrans+available] {
|
2018-04-02 23:40:47 +00:00
|
|
|
req.Transitions[id] = transitions[id]
|
2018-03-10 00:10:38 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|