container/output: export suspendable writer
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m12s
Test / Hakurei (push) Successful in 3m13s
Test / Hpkg (push) Successful in 4m1s
Test / Sandbox (race detector) (push) Successful in 4m34s
Test / Hakurei (race detector) (push) Successful in 5m14s
Test / Flake checks (push) Successful in 1m27s
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m12s
Test / Hakurei (push) Successful in 3m13s
Test / Hpkg (push) Successful in 4m1s
Test / Sandbox (race detector) (push) Successful in 4m34s
Test / Hakurei (race detector) (push) Successful in 5m14s
Test / Flake checks (push) Successful in 1m27s
This is quite useful for other packages as well. This change prepares internal/hlog for removal. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -2,69 +2,17 @@
|
||||
package hlog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container"
|
||||
)
|
||||
|
||||
const (
|
||||
bufSize = 4 * 1024
|
||||
bufSizeMax = 16 * 1024 * 1024
|
||||
)
|
||||
|
||||
var o = &suspendable{w: os.Stderr}
|
||||
var o = &container.Suspendable{Downstream: os.Stderr}
|
||||
|
||||
// Prepare configures the system logger for [Suspend] and [Resume] to take effect.
|
||||
func Prepare(prefix string) { log.SetPrefix(prefix + ": "); log.SetFlags(0); log.SetOutput(o) }
|
||||
|
||||
type suspendable struct {
|
||||
w io.Writer
|
||||
s atomic.Bool
|
||||
|
||||
buf bytes.Buffer
|
||||
bufOnce sync.Once
|
||||
bufMu sync.Mutex
|
||||
dropped int
|
||||
}
|
||||
|
||||
func (s *suspendable) Write(p []byte) (n int, err error) {
|
||||
if !s.s.Load() {
|
||||
return s.w.Write(p)
|
||||
}
|
||||
s.bufOnce.Do(func() { s.prepareBuf() })
|
||||
|
||||
s.bufMu.Lock()
|
||||
defer s.bufMu.Unlock()
|
||||
|
||||
if l := len(p); s.buf.Len()+l > bufSizeMax {
|
||||
s.dropped += l
|
||||
return 0, syscall.ENOMEM
|
||||
}
|
||||
return s.buf.Write(p)
|
||||
}
|
||||
|
||||
func (s *suspendable) prepareBuf() { s.buf.Grow(bufSize) }
|
||||
func (s *suspendable) Suspend() bool { return o.s.CompareAndSwap(false, true) }
|
||||
func (s *suspendable) Resume() (resumed bool, dropped uintptr, n int64, err error) {
|
||||
if o.s.CompareAndSwap(true, false) {
|
||||
o.bufMu.Lock()
|
||||
defer o.bufMu.Unlock()
|
||||
|
||||
resumed = true
|
||||
dropped = uintptr(o.dropped)
|
||||
|
||||
o.dropped = 0
|
||||
n, err = io.Copy(s.w, &s.buf)
|
||||
s.buf = bytes.Buffer{}
|
||||
s.prepareBuf()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Suspend() bool { return o.Suspend() }
|
||||
func Resume() bool {
|
||||
resumed, dropped, _, err := o.Resume()
|
||||
|
||||
Reference in New Issue
Block a user