github.com/Cloud-Foundations/Dominator@v0.3.4/hypervisor/manager/memory.go (about) 1 package manager 2 3 import ( 4 "errors" 5 "os" 6 "os/exec" 7 "strconv" 8 9 "github.com/Cloud-Foundations/Dominator/lib/meminfo" 10 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 11 ) 12 13 var ( 14 errorInsufficientAvailableMemory = errors.New( 15 "insufficient available memory") 16 errorInsufficientUnallocatedMemory = errors.New( 17 "insufficient unallocated memory") 18 errorUnableToAllocatedMemory = errors.New("unable to allocate memory") 19 ) 20 21 func checkAvailableMemory(memoryInMiB uint64) error { 22 if memInfo, err := meminfo.GetMemInfo(); err != nil { 23 return err 24 } else { 25 if memoryInMiB >= memInfo.Available>>20 { 26 return errorInsufficientAvailableMemory 27 } 28 return nil 29 } 30 } 31 32 func getVmInfoMemoryInMiB(vmInfo proto.VmInfo) uint64 { 33 var memoryTotal uint64 34 for _, volume := range vmInfo.Volumes { 35 if volume.Type == proto.VolumeTypeMemory { 36 memoryTotal += volume.Size 37 } 38 } 39 memoryInMiB := memoryTotal >> 20 40 if memoryInMiB<<20 < memoryTotal { 41 memoryInMiB += 1 42 } 43 return vmInfo.MemoryInMiB + memoryInMiB 44 } 45 46 func tryAllocateMemory(memoryInMiB uint64) <-chan error { 47 channel := make(chan error, 1) 48 executable, err := os.Executable() 49 if err != nil { 50 channel <- err 51 return channel 52 } 53 cmd := exec.Command(executable, "-testMemoryAvailable", 54 strconv.FormatUint(memoryInMiB, 10)) 55 go func() { 56 if err := cmd.Run(); err != nil { 57 if _, ok := err.(*exec.ExitError); ok { 58 channel <- errorUnableToAllocatedMemory 59 } else { 60 channel <- err 61 } 62 } else { 63 channel <- nil 64 } 65 }() 66 return channel 67 } 68 69 // This will grab the Manager lock and the lock for each VM. 70 func (m *Manager) getUnallocatedMemoryInMiB() uint64 { 71 m.mutex.RLock() 72 defer m.mutex.RUnlock() 73 return m.getUnallocatedMemoryInMiBWithLock(nil) 74 } 75 76 // This will grab the lock for each VM, except a specified VM which should 77 // already be locked. 78 func (m *Manager) getUnallocatedMemoryInMiBWithLock(locked *vmInfoType) uint64 { 79 unallocated := int64(m.memTotalInMiB) 80 for _, vm := range m.vms { 81 unallocated -= int64(vm.getMemoryInMiB(vm != locked)) 82 } 83 if unallocated < 0 { 84 return 0 85 } 86 return uint64(unallocated) 87 } 88 89 // This will grab the lock for each VM, except a specified VM which should 90 // already be locked. 91 func (m *Manager) checkSufficientMemoryWithLock(memoryInMiB uint64, 92 locked *vmInfoType) error { 93 if memoryInMiB > m.getUnallocatedMemoryInMiBWithLock(locked) { 94 return errorInsufficientUnallocatedMemory 95 } 96 return checkAvailableMemory(memoryInMiB) 97 } 98 99 func (vm *vmInfoType) getMemoryInMiB(grabLock bool) uint64 { 100 if grabLock { 101 vm.mutex.RLock() 102 defer vm.mutex.RUnlock() 103 } 104 return getVmInfoMemoryInMiB(vm.VmInfo) 105 }