Prevent race conditions when generating archives
This commit is contained in:
parent
b2d34cf8e7
commit
7e1b7e7f36
|
@ -21,6 +21,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -510,17 +511,19 @@ func (d *DockerEnvironment) EnableResourcePolling() error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.Resources.Lock()
|
||||||
s.Resources.CpuAbsolute = s.Resources.CalculateAbsoluteCpu(&v.PreCPUStats, &v.CPUStats)
|
s.Resources.CpuAbsolute = s.Resources.CalculateAbsoluteCpu(&v.PreCPUStats, &v.CPUStats)
|
||||||
s.Resources.Memory = s.Resources.CalculateDockerMemory(v.MemoryStats)
|
s.Resources.Memory = s.Resources.CalculateDockerMemory(v.MemoryStats)
|
||||||
s.Resources.MemoryLimit = v.MemoryStats.Limit
|
s.Resources.MemoryLimit = v.MemoryStats.Limit
|
||||||
|
s.Resources.Unlock()
|
||||||
|
|
||||||
// Why you ask? This already has the logic for caching disk space in use and then
|
// Why you ask? This already has the logic for caching disk space in use and then
|
||||||
// also handles pushing that value to the resources object automatically.
|
// also handles pushing that value to the resources object automatically.
|
||||||
s.Filesystem.HasSpaceAvailable()
|
s.Filesystem.HasSpaceAvailable()
|
||||||
|
|
||||||
for _, nw := range v.Networks {
|
for _, nw := range v.Networks {
|
||||||
s.Resources.Network.RxBytes += nw.RxBytes
|
atomic.AddUint64(&s.Resources.Network.RxBytes, nw.RxBytes)
|
||||||
s.Resources.Network.TxBytes += nw.TxBytes
|
atomic.AddUint64(&s.Resources.Network.TxBytes, nw.TxBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ := json.Marshal(s.Resources)
|
b, _ := json.Marshal(s.Resources)
|
||||||
|
@ -539,10 +542,7 @@ func (d *DockerEnvironment) DisableResourcePolling() error {
|
||||||
|
|
||||||
err := d.stats.Close()
|
err := d.stats.Close()
|
||||||
|
|
||||||
d.Server.Resources.CpuAbsolute = 0
|
d.Server.Resources.Empty()
|
||||||
d.Server.Resources.Memory = 0
|
|
||||||
d.Server.Resources.Network.TxBytes = 0
|
|
||||||
d.Server.Resources.Network.RxBytes = 0
|
|
||||||
|
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,9 @@ import (
|
||||||
var InvalidPathResolution = errors.New("invalid path resolution")
|
var InvalidPathResolution = errors.New("invalid path resolution")
|
||||||
|
|
||||||
type Filesystem struct {
|
type Filesystem struct {
|
||||||
// The server object associated with this Filesystem.
|
|
||||||
Server *Server
|
Server *Server
|
||||||
|
|
||||||
Configuration *config.SystemConfiguration
|
Configuration *config.SystemConfiguration
|
||||||
|
cacheDiskMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the root path that contains all of a server's data.
|
// Returns the root path that contains all of a server's data.
|
||||||
|
@ -171,7 +170,9 @@ func (fs *Filesystem) HasSpaceAvailable() bool {
|
||||||
|
|
||||||
// Determine if their folder size, in bytes, is smaller than the amount of space they've
|
// Determine if their folder size, in bytes, is smaller than the amount of space they've
|
||||||
// been allocated.
|
// been allocated.
|
||||||
|
fs.Server.Resources.Lock()
|
||||||
fs.Server.Resources.Disk = size
|
fs.Server.Resources.Disk = size
|
||||||
|
fs.Server.Resources.Unlock()
|
||||||
|
|
||||||
// If space is -1 or 0 just return true, means they're allowed unlimited.
|
// If space is -1 or 0 just return true, means they're allowed unlimited.
|
||||||
//
|
//
|
||||||
|
@ -190,6 +191,15 @@ func (fs *Filesystem) HasSpaceAvailable() bool {
|
||||||
// excessive IO usage. We will only walk the filesystem and determine the size of the directory if there
|
// excessive IO usage. We will only walk the filesystem and determine the size of the directory if there
|
||||||
// is no longer a cached value.
|
// is no longer a cached value.
|
||||||
func (fs *Filesystem) getCachedDiskUsage() (int64, error) {
|
func (fs *Filesystem) getCachedDiskUsage() (int64, error) {
|
||||||
|
// Obtain an exclusive lock on this process so that we don't unintentionally run it at the same
|
||||||
|
// time as another running process. Once the lock is available it'll read from the cache for the
|
||||||
|
// second call rather than hitting the disk in parallel.
|
||||||
|
//
|
||||||
|
// This effectively the same speed as running this call in parallel since this cache will return
|
||||||
|
// instantly on the second call.
|
||||||
|
fs.cacheDiskMu.Lock()
|
||||||
|
defer fs.cacheDiskMu.Unlock()
|
||||||
|
|
||||||
if x, exists := fs.Server.Cache.Get("disk_used"); exists {
|
if x, exists := fs.Server.Cache.Get("disk_used"); exists {
|
||||||
return x.(int64), nil
|
return x.(int64), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,15 @@ package server
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"math"
|
"math"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Defines the current resource usage for a given server instance. If a server is offline you
|
// Defines the current resource usage for a given server instance. If a server is offline you
|
||||||
// should obviously expect memory and CPU usage to be 0. However, disk will always be returned
|
// should obviously expect memory and CPU usage to be 0. However, disk will always be returned
|
||||||
// since that is not dependent on the server being running to collect that data.
|
// since that is not dependent on the server being running to collect that data.
|
||||||
type ResourceUsage struct {
|
type ResourceUsage struct {
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
// The total amount of memory, in bytes, that this server instance is consuming. This is
|
// The total amount of memory, in bytes, that this server instance is consuming. This is
|
||||||
// calculated slightly differently than just using the raw Memory field that the stats
|
// calculated slightly differently than just using the raw Memory field that the stats
|
||||||
// return from the container, so please check the code setting this value for how that
|
// return from the container, so please check the code setting this value for how that
|
||||||
|
@ -31,6 +34,18 @@ type ResourceUsage struct {
|
||||||
} `json:"network"`
|
} `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resets the usages values to zero, used when a server is stopped to ensure we don't hold
|
||||||
|
// onto any values incorrectly.
|
||||||
|
func (ru *ResourceUsage) Empty() {
|
||||||
|
ru.Lock()
|
||||||
|
defer ru.Unlock()
|
||||||
|
|
||||||
|
ru.Memory = 0
|
||||||
|
ru.CpuAbsolute = 0
|
||||||
|
ru.Network.TxBytes = 0
|
||||||
|
ru.Network.RxBytes = 0
|
||||||
|
}
|
||||||
|
|
||||||
// The "docker stats" CLI call does not return the same value as the types.MemoryStats.Usage
|
// The "docker stats" CLI call does not return the same value as the types.MemoryStats.Usage
|
||||||
// value which can be rather confusing to people trying to compare panel usage to
|
// value which can be rather confusing to people trying to compare panel usage to
|
||||||
// their stats output.
|
// their stats output.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user