allow service freeze/unfreeze on a setup (#13707)

an active running speedTest will reject all
new S3 requests to the server, until speedTest
is complete.

this is to ensure that speedTest results are
accurate and trusted.

Co-authored-by: Klaus Post <klauspost@gmail.com>
This commit is contained in:
Harshavardhana
2021-11-23 12:02:16 -08:00
committed by GitHub
parent 142c6b11b3
commit 91e0823ff0
12 changed files with 301 additions and 34 deletions

View File

@@ -31,6 +31,8 @@ const (
serviceRestart serviceSignal = iota // Restarts the server.
serviceStop // Stops the server.
serviceReloadDynamic // Reload dynamic config values.
serviceFreeze // Freeze all S3 API calls.
serviceUnFreeze // Un-Freeze previously frozen S3 API calls.
// Add new service requests here.
)
@@ -65,3 +67,57 @@ func restartProcess() error {
// Re-uses the same pid. This preserves the pid over multiple server-respawns.
return syscall.Exec(argv0, os.Args, os.Environ())
}
// Keep track of number of freeze/unfreeze calls.
const trackFreezeCount = true
// freezeServices will freeze all incoming S3 API calls.
// For each call, unfreezeServices must be called once.
func freezeServices() {
// Use atomics for globalServiceFreeze, so we can read without locking.
if trackFreezeCount {
// We need a lock since we are need the 2 atomic values to remain in sync.
globalServiceFreezeMu.Lock()
// If multiple calls, first one creates channel.
globalServiceFreezeCnt++
if globalServiceFreezeCnt == 1 {
globalServiceFreeze.Store(make(chan struct{}))
}
globalServiceFreezeMu.Unlock()
} else {
// If multiple calls, first one creates channel.
globalServiceFreeze.CompareAndSwap(nil, make(chan struct{}))
}
}
// unfreezeServices will unfreeze all incoming S3 API calls.
// For each call, unfreezeServices must be called once.
func unfreezeServices() {
if trackFreezeCount {
// We need a lock since we need the 2 atomic values to remain in sync.
globalServiceFreezeMu.Lock()
// Close when we reach 0
globalServiceFreezeCnt--
if globalServiceFreezeCnt <= 0 {
// Ensure we only close once.
if val := globalServiceFreeze.Load(); val != nil {
if ch, ok := val.(chan struct{}); ok {
globalServiceFreeze.Store(nil)
close(ch)
}
}
globalServiceFreezeCnt = 0 // Don't risk going negative.
}
globalServiceFreezeMu.Unlock()
} else {
// If multiple calls, first one closes channel.
if val := globalServiceFreeze.Load(); val != nil {
if ch, ok := val.(chan struct{}); ok {
// Ensure we only close once.
if globalServiceFreeze.CompareAndSwap(val, nil) {
close(ch)
}
}
}
}
}