Less racey logic for resource usage
This commit is contained in:
parent
0c93e5ed02
commit
3495fb1c76
|
@ -61,7 +61,7 @@ func (e *Environment) pollResources(ctx context.Context) error {
|
||||||
atomic.AddUint64(&tx, nw.RxBytes)
|
atomic.AddUint64(&tx, nw.RxBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := &environment.Stats{
|
st := environment.Stats{
|
||||||
Memory: calculateDockerMemory(v.MemoryStats),
|
Memory: calculateDockerMemory(v.MemoryStats),
|
||||||
MemoryLimit: v.MemoryStats.Limit,
|
MemoryLimit: v.MemoryStats.Limit,
|
||||||
CpuAbsolute: calculateDockerAbsoluteCpu(&v.PreCPUStats, &v.CPUStats),
|
CpuAbsolute: calculateDockerAbsoluteCpu(&v.PreCPUStats, &v.CPUStats),
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package environment
|
package environment
|
||||||
|
|
||||||
import "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 Stats struct {
|
type Stats struct {
|
||||||
mu 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
|
||||||
|
@ -33,15 +29,3 @@ type Stats struct {
|
||||||
TxBytes uint64 `json:"tx_bytes"`
|
TxBytes uint64 `json:"tx_bytes"`
|
||||||
} `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 (s *Stats) Empty() {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
|
|
||||||
s.Memory = 0
|
|
||||||
s.CpuAbsolute = 0
|
|
||||||
s.Network.TxBytes = 0
|
|
||||||
s.Network.RxBytes = 0
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ func getServer(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := GetServer(c.Param("server"))
|
||||||
|
|
||||||
c.JSON(http.StatusOK, serverProcData{
|
c.JSON(http.StatusOK, serverProcData{
|
||||||
ResourceUsage: *s.Proc(),
|
ResourceUsage: s.Proc(),
|
||||||
Suspended: s.IsSuspended(),
|
Suspended: s.IsSuspended(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"github.com/pterodactyl/wings/environment"
|
"github.com/pterodactyl/wings/environment"
|
||||||
"github.com/pterodactyl/wings/system"
|
"github.com/pterodactyl/wings/system"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -26,32 +25,27 @@ type ResourceUsage struct {
|
||||||
Disk int64 `json:"disk_bytes"`
|
Disk int64 `json:"disk_bytes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom marshaler to ensure that the object is locked when we're converting it to JSON in
|
// Returns the current resource usage stats for the server instance. This returns
|
||||||
// order to avoid race conditions.
|
// a copy of the tracked resources, so making any changes to the response will not
|
||||||
func (ru *ResourceUsage) MarshalJSON() ([]byte, error) {
|
// have the desired outcome for you most likely.
|
||||||
ru.mu.Lock()
|
func (s *Server) Proc() ResourceUsage {
|
||||||
defer ru.mu.Unlock()
|
s.resources.mu.Lock()
|
||||||
|
defer s.resources.mu.Unlock()
|
||||||
// Alias the resource usage so that we don't infinitely recurse when marshaling the struct.
|
|
||||||
type alias ResourceUsage
|
|
||||||
|
|
||||||
return json.Marshal((*alias)(ru))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the resource usage stats for the server instance. If the server is not running, only the
|
|
||||||
// disk space currently used will be returned. When the server is running all of the other stats will
|
|
||||||
// be returned.
|
|
||||||
//
|
|
||||||
// When a process is stopped all of the stats are zeroed out except for the disk.
|
|
||||||
func (s *Server) Proc() *ResourceUsage {
|
|
||||||
// Store the updated disk usage when requesting process usage.
|
// Store the updated disk usage when requesting process usage.
|
||||||
atomic.StoreInt64(&s.resources.Disk, s.Filesystem().CachedUsage())
|
atomic.StoreInt64(&s.resources.Disk, s.Filesystem().CachedUsage())
|
||||||
|
//goland:noinspection GoVetCopyLock
|
||||||
|
return s.resources
|
||||||
|
}
|
||||||
|
|
||||||
// Acquire a lock before attempting to return the value of resources.
|
// Resets the usages values to zero, used when a server is stopped to ensure we don't hold
|
||||||
s.resources.mu.RLock()
|
// onto any values incorrectly.
|
||||||
defer s.resources.mu.RUnlock()
|
func (ru *ResourceUsage) Reset() {
|
||||||
|
ru.mu.Lock()
|
||||||
return &s.resources
|
defer ru.mu.Unlock()
|
||||||
|
ru.Memory = 0
|
||||||
|
ru.CpuAbsolute = 0
|
||||||
|
ru.Network.TxBytes = 0
|
||||||
|
ru.Network.RxBytes = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) emitProcUsage() {
|
func (s *Server) emitProcUsage() {
|
||||||
|
|
|
@ -62,11 +62,11 @@ func saveServerStates() error {
|
||||||
// Sets the state of the server internally. This function handles crash detection as
|
// Sets the state of the server internally. This function handles crash detection as
|
||||||
// well as reporting to event listeners for the server.
|
// well as reporting to event listeners for the server.
|
||||||
func (s *Server) OnStateChange() {
|
func (s *Server) OnStateChange() {
|
||||||
prevState := s.Proc().State.Load()
|
prevState := s.resources.State.Load()
|
||||||
|
|
||||||
st := s.Environment.State()
|
st := s.Environment.State()
|
||||||
// Update the currently tracked state for the server.
|
// Update the currently tracked state for the server.
|
||||||
s.Proc().State.Store(st)
|
s.resources.State.Store(st)
|
||||||
|
|
||||||
// Emit the event to any listeners that are currently registered.
|
// Emit the event to any listeners that are currently registered.
|
||||||
if prevState != s.Environment.State() {
|
if prevState != s.Environment.State() {
|
||||||
|
@ -91,10 +91,7 @@ func (s *Server) OnStateChange() {
|
||||||
// Reset the resource usage to 0 when the process fully stops so that all of the UI
|
// Reset the resource usage to 0 when the process fully stops so that all of the UI
|
||||||
// views in the Panel correctly display 0.
|
// views in the Panel correctly display 0.
|
||||||
if st == environment.ProcessOfflineState {
|
if st == environment.ProcessOfflineState {
|
||||||
s.resources.mu.Lock()
|
s.resources.Reset()
|
||||||
s.resources.Empty()
|
|
||||||
s.resources.mu.Unlock()
|
|
||||||
|
|
||||||
s.emitProcUsage()
|
s.emitProcUsage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user