mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 06:52: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
 | |
| }
 |