Less racey logic for resource usage

This commit is contained in:
Dane Everitt
2020-12-16 22:03:35 -08:00
parent 0c93e5ed02
commit 3495fb1c76
5 changed files with 23 additions and 48 deletions

View File

@@ -1,7 +1,6 @@
package server
import (
"encoding/json"
"github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/system"
"sync"
@@ -26,32 +25,27 @@ type ResourceUsage struct {
Disk int64 `json:"disk_bytes"`
}
// Custom marshaler to ensure that the object is locked when we're converting it to JSON in
// order to avoid race conditions.
func (ru *ResourceUsage) MarshalJSON() ([]byte, error) {
ru.mu.Lock()
defer ru.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 {
// Returns the current resource usage stats for the server instance. This returns
// a copy of the tracked resources, so making any changes to the response will not
// have the desired outcome for you most likely.
func (s *Server) Proc() ResourceUsage {
s.resources.mu.Lock()
defer s.resources.mu.Unlock()
// Store the updated disk usage when requesting process usage.
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.
s.resources.mu.RLock()
defer s.resources.mu.RUnlock()
return &s.resources
// 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) Reset() {
ru.mu.Lock()
defer ru.mu.Unlock()
ru.Memory = 0
ru.CpuAbsolute = 0
ru.Network.TxBytes = 0
ru.Network.RxBytes = 0
}
func (s *Server) emitProcUsage() {

View File

@@ -62,11 +62,11 @@ func saveServerStates() error {
// Sets the state of the server internally. This function handles crash detection as
// well as reporting to event listeners for the server.
func (s *Server) OnStateChange() {
prevState := s.Proc().State.Load()
prevState := s.resources.State.Load()
st := s.Environment.State()
// 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.
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
// views in the Panel correctly display 0.
if st == environment.ProcessOfflineState {
s.resources.mu.Lock()
s.resources.Empty()
s.resources.mu.Unlock()
s.resources.Reset()
s.emitProcUsage()
}