2019-05-22 23:16:55 +02:00
|
|
|
package memory
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
2019-06-28 14:34:24 +02:00
|
|
|
"os/exec"
|
2019-05-22 23:16:55 +02:00
|
|
|
"strconv"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
|
|
|
)
|
|
|
|
|
2019-10-16 23:49:54 +02:00
|
|
|
const maxInt = int(^uint(0) >> 1)
|
|
|
|
|
2019-05-22 23:16:55 +02:00
|
|
|
func sysTotalMemory() int {
|
|
|
|
var si syscall.Sysinfo_t
|
|
|
|
if err := syscall.Sysinfo(&si); err != nil {
|
|
|
|
logger.Panicf("FATAL: error in syscall.Sysinfo: %s", err)
|
|
|
|
}
|
2019-10-16 23:49:54 +02:00
|
|
|
totalMem := maxInt
|
|
|
|
if uint64(maxInt)/uint64(si.Totalram) > uint64(si.Unit) {
|
|
|
|
totalMem = int(uint64(si.Totalram) * uint64(si.Unit))
|
|
|
|
}
|
2019-05-22 23:16:55 +02:00
|
|
|
|
|
|
|
// Try determining the amount of memory inside docker container.
|
|
|
|
// See https://stackoverflow.com/questions/42187085/check-mem-limit-within-a-docker-container .
|
|
|
|
data, err := ioutil.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes")
|
2019-06-28 14:34:24 +02:00
|
|
|
if err != nil {
|
|
|
|
// Try determining the amount of memory inside lxc container.
|
|
|
|
mem, err := readLXCMemoryLimit(totalMem)
|
|
|
|
if err != nil {
|
|
|
|
return totalMem
|
|
|
|
}
|
|
|
|
return mem
|
|
|
|
}
|
|
|
|
mem, err := readPositiveInt(data, totalMem)
|
2019-05-22 23:16:55 +02:00
|
|
|
if err != nil {
|
|
|
|
return totalMem
|
|
|
|
}
|
2019-06-28 17:08:09 +02:00
|
|
|
if mem != totalMem {
|
|
|
|
return mem
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try reading LXC memory limit, since it looks like the cgroup limit doesn't work
|
|
|
|
mem, err = readLXCMemoryLimit(totalMem)
|
|
|
|
if err != nil {
|
|
|
|
return totalMem
|
|
|
|
}
|
2019-06-28 14:34:24 +02:00
|
|
|
return mem
|
|
|
|
}
|
|
|
|
|
|
|
|
func readLXCMemoryLimit(totalMem int) (int, error) {
|
|
|
|
// Read memory limit according to https://unix.stackexchange.com/questions/242718/how-to-find-out-how-much-memory-lxc-container-is-allowed-to-consume
|
|
|
|
// This should properly determine the limit inside lxc container.
|
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/84
|
|
|
|
cmd := exec.Command("/bin/sh", "-c",
|
2019-07-01 13:01:10 +02:00
|
|
|
`cat /sys/fs/cgroup/memory$(cat /proc/self/cgroup | grep memory | cut -d: -f3)/memory.limit_in_bytes`)
|
2019-06-28 14:34:24 +02:00
|
|
|
data, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return readPositiveInt(data, totalMem)
|
|
|
|
}
|
|
|
|
|
|
|
|
func readPositiveInt(data []byte, maxN int) (int, error) {
|
2019-05-22 23:16:55 +02:00
|
|
|
for len(data) > 0 && data[len(data)-1] == '\n' {
|
|
|
|
data = data[:len(data)-1]
|
|
|
|
}
|
2019-06-28 14:34:24 +02:00
|
|
|
n, err := strconv.ParseUint(string(data), 10, 64)
|
2019-05-22 23:16:55 +02:00
|
|
|
if err != nil {
|
2019-06-28 14:34:24 +02:00
|
|
|
return 0, err
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
2019-06-28 14:34:24 +02:00
|
|
|
if int64(n) < 0 || int64(int(n)) != int64(n) {
|
|
|
|
// Int overflow.
|
|
|
|
return maxN, nil
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
2019-06-28 14:34:24 +02:00
|
|
|
ni := int(n)
|
|
|
|
if ni > maxN {
|
|
|
|
return maxN, nil
|
|
|
|
}
|
|
|
|
return ni, nil
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|