github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/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  )
    11  
    12  var (
    13  	errorInsufficientAvailableMemory = errors.New(
    14  		"insufficient available memory")
    15  	errorInsufficientUnallocatedMemory = errors.New(
    16  		"insufficient unallocated memory")
    17  	errorUnableToAllocatedMemory = errors.New("unable to allocate memory")
    18  )
    19  
    20  func checkAvailableMemory(memoryInMiB uint64) error {
    21  	if memInfo, err := meminfo.GetMemInfo(); err != nil {
    22  		return err
    23  	} else {
    24  		if memoryInMiB >= memInfo.Available>>20 {
    25  			return errorInsufficientAvailableMemory
    26  		}
    27  		return nil
    28  	}
    29  }
    30  
    31  func tryAllocateMemory(memoryInMiB uint64) <-chan error {
    32  	channel := make(chan error, 1)
    33  	executable, err := os.Executable()
    34  	if err != nil {
    35  		channel <- err
    36  		return channel
    37  	}
    38  	cmd := exec.Command(executable, "-testMemoryAvailable",
    39  		strconv.FormatUint(memoryInMiB, 10))
    40  	go func() {
    41  		if err := cmd.Run(); err != nil {
    42  			if _, ok := err.(*exec.ExitError); ok {
    43  				channel <- errorUnableToAllocatedMemory
    44  			} else {
    45  				channel <- err
    46  			}
    47  		} else {
    48  			channel <- nil
    49  		}
    50  	}()
    51  	return channel
    52  }
    53  
    54  func (m *Manager) getUnallocatedMemoryInMiB() uint64 {
    55  	m.mutex.RLock()
    56  	defer m.mutex.RUnlock()
    57  	return m.getUnallocatedMemoryInMiBWithLock()
    58  }
    59  
    60  func (m *Manager) getUnallocatedMemoryInMiBWithLock() uint64 {
    61  	unallocated := int64(m.memTotalInMiB)
    62  	for _, vm := range m.vms {
    63  		unallocated -= int64(vm.MemoryInMiB)
    64  	}
    65  	if unallocated < 0 {
    66  		return 0
    67  	}
    68  	return uint64(unallocated)
    69  }
    70  
    71  func (m *Manager) checkSufficientMemoryWithLock(memoryInMiB uint64) error {
    72  	if memoryInMiB > m.getUnallocatedMemoryInMiBWithLock() {
    73  		return errorInsufficientUnallocatedMemory
    74  	}
    75  	return checkAvailableMemory(memoryInMiB)
    76  }