get rid of session workers, new util.PutBytes/GetBytes logic

This commit is contained in:
Arceliar 2019-07-27 18:10:32 -05:00
parent 39245f8134
commit e0a3055c2f
6 changed files with 100 additions and 109 deletions

View file

@ -13,33 +13,25 @@ type Cancellation interface {
Error() error
}
var CancellationFinalized = errors.New("finalizer called")
var CancellationTimeoutError = errors.New("timeout")
func CancellationFinalizer(c Cancellation) {
c.Cancel(errors.New("finalizer called"))
c.Cancel(CancellationFinalized)
}
type cancellation struct {
signal chan error
cancel chan struct{}
errMtx sync.RWMutex
mutex sync.RWMutex
err error
}
func (c *cancellation) worker() {
// Launch this in a separate goroutine when creating a cancellation
err := <-c.signal
c.errMtx.Lock()
c.err = err
c.errMtx.Unlock()
close(c.cancel)
done bool
}
func NewCancellation() Cancellation {
c := cancellation{
signal: make(chan error),
cancel: make(chan struct{}),
}
runtime.SetFinalizer(&c, CancellationFinalizer)
go c.worker()
return &c
}
@ -48,18 +40,22 @@ func (c *cancellation) Finished() <-chan struct{} {
}
func (c *cancellation) Cancel(err error) error {
select {
case c.signal <- err:
c.mutex.Lock()
defer c.mutex.Unlock()
if c.done {
return c.err
} else {
c.err = err
c.done = true
close(c.cancel)
return nil
case <-c.cancel:
return c.Error()
}
}
func (c *cancellation) Error() error {
c.errMtx.RLock()
c.mutex.RLock()
err := c.err
c.errMtx.RUnlock()
c.mutex.RUnlock()
return err
}
@ -75,8 +71,6 @@ func CancellationChild(parent Cancellation) Cancellation {
return child
}
var CancellationTimeoutError = errors.New("timeout")
func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancellation {
child := CancellationChild(parent)
go func() {

View file

@ -3,6 +3,7 @@ package util
// These are misc. utility functions that didn't really fit anywhere else
import "runtime"
import "sync"
import "time"
// A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere.
@ -21,29 +22,27 @@ func UnlockThread() {
}
// This is used to buffer recently used slices of bytes, to prevent allocations in the hot loops.
// It's used like a sync.Pool, but with a fixed size and typechecked without type casts to/from interface{} (which were making the profiles look ugly).
var byteStore chan []byte
var byteStoreMutex sync.Mutex
var byteStore [][]byte
func init() {
byteStore = make(chan []byte, 32)
}
// Gets an empty slice from the byte store, if one is available, or else returns a new nil slice.
// Gets an empty slice from the byte store.
func GetBytes() []byte {
select {
case bs := <-byteStore:
return bs[:0]
default:
byteStoreMutex.Lock()
defer byteStoreMutex.Unlock()
if len(byteStore) > 0 {
var bs []byte
bs, byteStore = byteStore[len(byteStore)-1][:0], byteStore[:len(byteStore)-1]
return bs
} else {
return nil
}
}
// Puts a slice in the store, if there's room, or else returns and lets the slice get collected.
// Puts a slice in the store.
func PutBytes(bs []byte) {
select {
case byteStore <- bs:
default:
}
byteStoreMutex.Lock()
defer byteStoreMutex.Unlock()
byteStore = append(byteStore, bs)
}
// This is a workaround to go's broken timer implementation