github.com/sandwich-go/boost@v1.3.29/xpool/reference.go (about)

     1  package xpool
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"sync/atomic"
     7  )
     8  
     9  // Reference 引用
    10  type Reference interface {
    11  	set(interface{})
    12  	incr()
    13  
    14  	// Decr 引用计数减一,当引用为0时,会添入对象池中
    15  	Decr()
    16  }
    17  
    18  // ReferencePool 引用池
    19  type ReferencePool interface {
    20  	// Get 获取对象
    21  	Get() interface{}
    22  	// Stats 池子状态
    23  	Stats() ReferencePoolStats
    24  }
    25  
    26  // ReferencePoolStats 引用池子状态
    27  type ReferencePoolStats struct {
    28  	Released   uint32
    29  	Allocated  uint32
    30  	Referenced uint32
    31  }
    32  
    33  func (s ReferencePoolStats) String() string {
    34  	return fmt.Sprintf("Released: %d, Allocated: %d, Referenced: %d", s.Released, s.Allocated, s.Referenced)
    35  }
    36  
    37  type reference struct {
    38  	count    *uint32           // 引用计数
    39  	pool     *sync.Pool        // 释放的目标池
    40  	released *uint32           // 释放次数
    41  	instance interface{}       // 目标对象
    42  	reset    func(interface{}) // 重置函数
    43  	id       uint32            // 唯一标记
    44  }
    45  
    46  func (c *reference) set(i interface{}) { c.instance = i }
    47  func (c *reference) incr()             { atomic.AddUint32(c.count, 1) }
    48  
    49  // Decr 减少引用计数
    50  func (c *reference) Decr() {
    51  	if atomic.LoadUint32(c.count) == 0 {
    52  		return
    53  	}
    54  	if atomic.AddUint32(c.count, ^uint32(0)) == 0 {
    55  		atomic.AddUint32(c.released, 1)
    56  		if c.reset != nil {
    57  			c.reset(c.instance)
    58  		}
    59  		c.pool.Put(c.instance)
    60  		c.instance = nil
    61  	}
    62  }
    63  
    64  type referencePool struct {
    65  	*sync.Pool
    66  	released   uint32
    67  	allocated  uint32
    68  	referenced uint32
    69  }
    70  
    71  func NewReferencePool(builder func(Reference) Reference, reset func(interface{})) ReferencePool {
    72  	p := new(referencePool)
    73  	p.Pool = new(sync.Pool)
    74  	p.Pool.New = func() interface{} {
    75  		atomic.AddUint32(&p.allocated, 1)
    76  		return builder(&reference{
    77  			count:    new(uint32),
    78  			pool:     p.Pool,
    79  			released: &p.released,
    80  			reset:    reset,
    81  			id:       p.allocated,
    82  		})
    83  	}
    84  	return p
    85  }
    86  
    87  func (p *referencePool) Get() interface{} {
    88  	c := p.Pool.Get().(Reference)
    89  	c.set(c)
    90  	atomic.AddUint32(&p.referenced, 1)
    91  	c.incr()
    92  	return c
    93  }
    94  
    95  func (p *referencePool) Stats() ReferencePoolStats {
    96  	return ReferencePoolStats{
    97  		Allocated:  atomic.LoadUint32(&p.allocated),
    98  		Referenced: atomic.LoadUint32(&p.referenced),
    99  		Released:   atomic.LoadUint32(&p.released),
   100  	}
   101  }