config: use dense indices for VMs

CreateVMConfig uses fileutil.ProcessTempDir to assign indices to VMs.
fileutil.ProcessTempDir generates unique indices globally across several processes.
This was required for old vm/qemu code that used the index to choose unique ssh port for the VM.
Now vm/qemu does not use index as port and this global index assignment started
causing problems for adb and gce. Adb really needs indexes to be dense --
index is used to choose adb device id (if we have 2 devices, index 3 causes
out of bounds panic). For gce it leads to creation of unnecessary VM instances
(if I set count=4, I want at most 4 VMs created).

Don't use fileutil.ProcessTempDir-generated index in CreateVMConfig
and instead just use the dense indices passed by caller.
This commit is contained in:
Dmitry Vyukov 2016-11-25 17:11:56 +01:00
parent 9604794dce
commit 9d672cd451
3 changed files with 14 additions and 29 deletions

View File

@ -250,7 +250,7 @@ func CreateVMConfig(cfg *Config, index int) (*vm.Config, error) {
if index < 0 || index >= cfg.Count {
return nil, fmt.Errorf("invalid VM index %v (count %v)", index, cfg.Count)
}
workdir, index, err := fileutil.ProcessTempDir(cfg.Workdir)
workdir, err := fileutil.ProcessTempDir(cfg.Workdir)
if err != nil {
return nil, fmt.Errorf("failed to create instance temp dir: %v", err)
}

View File

@ -59,15 +59,15 @@ func WriteTempFile(data []byte) (string, error) {
// ProcessTempDir creates a new temp dir in where and returns its path and an unique index.
// It also cleans up old, unused temp dirs after dead processes.
func ProcessTempDir(where string) (string, int, error) {
func ProcessTempDir(where string) (string, error) {
lk := filepath.Join(where, "instance-lock")
lkf, err := syscall.Open(lk, syscall.O_RDWR|syscall.O_CREAT, 0600)
if err != nil {
return "", 0, err
return "", err
}
defer syscall.Close(lkf)
if err := syscall.Flock(lkf, syscall.LOCK_EX); err != nil {
return "", 0, err
return "", err
}
defer syscall.Flock(lkf, syscall.LOCK_UN)
@ -95,14 +95,14 @@ func ProcessTempDir(where string) (string, int, error) {
continue
}
if err != nil {
return "", 0, err
return "", err
}
if err := ioutil.WriteFile(pidfile, []byte(strconv.Itoa(syscall.Getpid())), 0600); err != nil {
return "", 0, err
return "", err
}
return path, i, nil
return path, nil
}
return "", 0, fmt.Errorf("too many live instances")
return "", fmt.Errorf("too many live instances")
}
// UmountAll recurusively unmounts all mounts in dir.

View File

@ -4,7 +4,6 @@
package fileutil
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
@ -25,13 +24,10 @@ func TestProcessTempDir(t *testing.T) {
// Pre-create half of the instances with stale pid.
var dirs []string
for i := 0; i < P/2; i++ {
dir, idx, err := ProcessTempDir(tmp)
dir, err := ProcessTempDir(tmp)
if err != nil {
t.Fatalf("failed to create process temp dir")
}
if idx != i {
t.Fatalf("unexpected index: want %v, got %v", i, idx)
}
dirs = append(dirs, dir)
}
for _, dir := range dirs {
@ -41,34 +37,23 @@ func TestProcessTempDir(t *testing.T) {
}
// Now request a bunch of instances concurrently.
done := make(chan bool)
indices := make(map[int]bool)
allDirs := make(map[string]bool)
var mu sync.Mutex
for p := 0; p < P; p++ {
go func() {
defer func() {
done <- true
}()
dir, idx, err := ProcessTempDir(tmp)
dir, err := ProcessTempDir(tmp)
if err != nil {
t.Fatalf("failed to create process temp dir")
}
mu.Lock()
present := indices[idx]
indices[idx] = true
present := allDirs[dir]
allDirs[dir] = true
mu.Unlock()
if present {
t.Fatalf("duplicate index %v", idx)
}
data := []byte(strconv.Itoa(idx))
if err := ioutil.WriteFile(filepath.Join(dir, "data"), data, 0600); err != nil {
t.Fatalf("failed to write data file: %v", err)
}
data1, err := ioutil.ReadFile(filepath.Join(dir, "data"))
if err != nil {
t.Fatalf("failed to read data file: %v", err)
}
if bytes.Compare(data, data1) != 0 {
t.Fatalf("corrupted data file")
t.Fatalf("duplicate dir %v", dir)
}
}()
}