mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 03:42:26 -05:00
- github.com/ncruces/go-sqlite3 - codeberg.org/gruf/go-mempool - codeberg.org/gruf/go-structr (changes related on the above) * - codeberg.org/gruf/go-mutexes (changes related on the above) * * this is largely just fiddling around with package internals in structr and mutexes to rely on changes in mempool, which added a new concurrency-safe pool Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4468 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
111 lines
2.3 KiB
Go
111 lines
2.3 KiB
Go
package mempool
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// SimplePool provides a type-safe form
|
|
// of UnsafePool using generics.
|
|
//
|
|
// Note it is NOT safe for concurrent
|
|
// use, you must protect it yourself!
|
|
type SimplePool[T any] struct {
|
|
UnsafeSimplePool
|
|
|
|
// New is an optionally provided
|
|
// allocator used when no value
|
|
// is available for use in pool.
|
|
New func() T
|
|
|
|
// Reset is an optionally provided
|
|
// value resetting function called
|
|
// on passed value to Put().
|
|
Reset func(T) bool
|
|
}
|
|
|
|
func (p *SimplePool[T]) Get() T {
|
|
if ptr := p.UnsafeSimplePool.Get(); ptr != nil {
|
|
return *(*T)(ptr)
|
|
}
|
|
var t T
|
|
if p.New != nil {
|
|
t = p.New()
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (p *SimplePool[T]) Put(t T) {
|
|
if p.Reset != nil && !p.Reset(t) {
|
|
return
|
|
}
|
|
ptr := unsafe.Pointer(&t)
|
|
p.UnsafeSimplePool.Put(ptr)
|
|
}
|
|
|
|
// UnsafeSimplePool provides an incredibly
|
|
// simple memory pool implementation
|
|
// that stores ptrs to memory values,
|
|
// and regularly flushes internal pool
|
|
// structures according to CheckGC().
|
|
//
|
|
// Note it is NOT safe for concurrent
|
|
// use, you must protect it yourself!
|
|
type UnsafeSimplePool struct {
|
|
|
|
// Check determines how often to flush
|
|
// internal pools based on underlying
|
|
// current and victim pool sizes. It gets
|
|
// called on every pool Put() operation.
|
|
//
|
|
// A flush will start a new current
|
|
// pool, make victim the old current,
|
|
// and drop the existing victim pool.
|
|
Check func(current, victim int) bool
|
|
|
|
current []unsafe.Pointer
|
|
victim []unsafe.Pointer
|
|
}
|
|
|
|
func (p *UnsafeSimplePool) Get() unsafe.Pointer {
|
|
// First try current list.
|
|
if len(p.current) > 0 {
|
|
ptr := p.current[len(p.current)-1]
|
|
p.current = p.current[:len(p.current)-1]
|
|
return ptr
|
|
}
|
|
|
|
// Fallback to victim.
|
|
if len(p.victim) > 0 {
|
|
ptr := p.victim[len(p.victim)-1]
|
|
p.victim = p.victim[:len(p.victim)-1]
|
|
return ptr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *UnsafeSimplePool) Put(ptr unsafe.Pointer) {
|
|
p.current = append(p.current, ptr)
|
|
|
|
// Get GC check func.
|
|
if p.Check == nil {
|
|
p.Check = defaultCheck
|
|
}
|
|
|
|
if p.Check(len(p.current), len(p.victim)) {
|
|
p.GC() // garbage collection time!
|
|
}
|
|
}
|
|
|
|
func (p *UnsafeSimplePool) GC() {
|
|
p.victim = p.current
|
|
p.current = nil
|
|
}
|
|
|
|
func (p *UnsafeSimplePool) Size() int {
|
|
return len(p.current) + len(p.victim)
|
|
}
|
|
|
|
func defaultCheck(current, victim int) bool {
|
|
return current-victim > 128 || victim > 256
|
|
}
|