2025-05-22 23:29:50 +08:00
|
|
|
package pool
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"mayfly-go/pkg/logx"
|
2025-05-23 17:26:12 +08:00
|
|
|
"sync"
|
2025-05-22 23:29:50 +08:00
|
|
|
|
|
|
|
|
"golang.org/x/sync/singleflight"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type PoolGroup[T Conn] struct {
|
2025-05-23 17:26:12 +08:00
|
|
|
mu sync.RWMutex
|
2025-05-22 23:29:50 +08:00
|
|
|
poolGroup map[string]Pool[T]
|
|
|
|
|
createGroup singleflight.Group
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewPoolGroup[T Conn]() *PoolGroup[T] {
|
|
|
|
|
return &PoolGroup[T]{
|
|
|
|
|
poolGroup: make(map[string]Pool[T]),
|
|
|
|
|
createGroup: singleflight.Group{},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pg *PoolGroup[T]) GetOrCreate(
|
|
|
|
|
key string,
|
|
|
|
|
poolFactory func() Pool[T],
|
|
|
|
|
opts ...Option,
|
|
|
|
|
) (Pool[T], error) {
|
2025-05-23 17:26:12 +08:00
|
|
|
// 先尝试读锁获取
|
|
|
|
|
pg.mu.RLock()
|
2025-05-22 23:29:50 +08:00
|
|
|
if p, ok := pg.poolGroup[key]; ok {
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.RUnlock()
|
2025-05-22 23:29:50 +08:00
|
|
|
return p, nil
|
|
|
|
|
}
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.RUnlock()
|
2025-05-22 23:29:50 +08:00
|
|
|
|
2025-05-23 17:26:12 +08:00
|
|
|
// 使用 singleflight 确保并发安全
|
2025-05-22 23:29:50 +08:00
|
|
|
v, err, _ := pg.createGroup.Do(key, func() (any, error) {
|
2025-05-23 17:26:12 +08:00
|
|
|
// 再次检查,避免在等待期间其他 goroutine 已创建
|
|
|
|
|
pg.mu.RLock()
|
|
|
|
|
if p, ok := pg.poolGroup[key]; ok {
|
|
|
|
|
pg.mu.RUnlock()
|
|
|
|
|
return p, nil
|
|
|
|
|
}
|
|
|
|
|
pg.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
// 创建新池
|
2025-05-22 23:29:50 +08:00
|
|
|
logx.Infof("pool group - create pool, key: %s", key)
|
|
|
|
|
p := poolFactory()
|
2025-05-23 17:26:12 +08:00
|
|
|
|
|
|
|
|
// 写入时加写锁
|
|
|
|
|
pg.mu.Lock()
|
2025-05-22 23:29:50 +08:00
|
|
|
pg.poolGroup[key] = p
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.Unlock()
|
|
|
|
|
|
2025-05-22 23:29:50 +08:00
|
|
|
return p, nil
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.(Pool[T]), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetChanPool 获取或创建 ChannelPool 类型连接池
|
|
|
|
|
func (pg *PoolGroup[T]) GetChanPool(key string, factory func() (T, error), opts ...Option) (Pool[T], error) {
|
|
|
|
|
return pg.GetOrCreate(key, func() Pool[T] {
|
|
|
|
|
return NewChannelPool(factory, opts...)
|
|
|
|
|
}, opts...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetCachePool 获取或创建 CachePool 类型连接池
|
|
|
|
|
func (pg *PoolGroup[T]) GetCachePool(key string, factory func() (T, error), opts ...Option) (Pool[T], error) {
|
|
|
|
|
return pg.GetOrCreate(key, func() Pool[T] {
|
|
|
|
|
return NewCachePool(factory, opts...)
|
|
|
|
|
}, opts...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pg *PoolGroup[T]) Close(key string) error {
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.Lock()
|
|
|
|
|
defer pg.mu.Unlock()
|
|
|
|
|
|
2025-05-22 23:29:50 +08:00
|
|
|
if p, ok := pg.poolGroup[key]; ok {
|
|
|
|
|
logx.Infof("pool group - close pool, key: %s", key)
|
|
|
|
|
p.Close()
|
|
|
|
|
pg.createGroup.Forget(key)
|
|
|
|
|
delete(pg.poolGroup, key)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pg *PoolGroup[T]) CloseAll() {
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.Lock()
|
|
|
|
|
defer pg.mu.Unlock()
|
|
|
|
|
|
2025-05-22 23:29:50 +08:00
|
|
|
for key := range pg.poolGroup {
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.poolGroup[key].Close()
|
|
|
|
|
pg.createGroup.Forget(key)
|
2025-05-22 23:29:50 +08:00
|
|
|
}
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.poolGroup = make(map[string]Pool[T])
|
2025-05-22 23:29:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pg *PoolGroup[T]) AllPool() map[string]Pool[T] {
|
2025-05-23 17:26:12 +08:00
|
|
|
pg.mu.RLock()
|
|
|
|
|
defer pg.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
// 返回 map 的副本,避免外部修改
|
|
|
|
|
pools := make(map[string]Pool[T], len(pg.poolGroup))
|
|
|
|
|
for k, v := range pg.poolGroup {
|
|
|
|
|
pools[k] = v
|
|
|
|
|
}
|
|
|
|
|
return pools
|
2025-05-22 23:29:50 +08:00
|
|
|
}
|