Files
nomad/drivers/docker/cpuset.go

88 lines
2.0 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package docker
import (
"os"
"path/filepath"
"time"
"github.com/hashicorp/nomad/client/lib/cgroupslib"
"github.com/hashicorp/nomad/helper"
)
const (
// cpusetSyncPeriod is how often we check to see if the cpuset of a task
// needs to be updated - if there is no work to do, no action is taken
cpusetSyncPeriod = 3 * time.Second
)
// cpuset is used to manage the cpuset.cpus interface file in the cgroup that
// docker daemon creates for the container being run by the task driver. we
// must do this hack because docker does not allow specifying a pre-existing
// cgroup in which to run the container (i.e. one that we control).
type cpuset struct {
doneCh <-chan bool
source string
destination string
previous string
sync func(string, string)
}
func (c *cpuset) watch() {
if c.sync == nil {
// use the real thing if we are not doing tests
c.sync = c.copyCpuset
}
ticks, cancel := helper.NewSafeTimer(cpusetSyncPeriod)
defer cancel()
for {
select {
case <-c.doneCh:
return
case <-ticks.C:
c.sync(c.source, c.destination)
ticks.Reset(cpusetSyncPeriod)
}
}
}
func effectiveCpusetFile() string {
switch cgroupslib.GetMode() {
case cgroupslib.CG1:
return "cpuset.effective_cpus"
default:
return "cpuset.cpus.effective"
}
}
func (c *cpuset) copyCpuset(source, destination string) {
source = filepath.Join(source, effectiveCpusetFile())
destination = filepath.Join(destination, "cpuset.cpus")
// read the current value of usable cores
b, err := os.ReadFile(source)
if err != nil {
return
}
// if the current value is the same as the value we wrote last,
// there is nothing to do
current := string(b)
if current == c.previous {
return
}
// otherwise write the new value
err = os.WriteFile(destination, b, 0o644)
if err != nil {
return
}
// we wrote a new value; store that value so we do not write it again
c.previous = current
}