Started LDAP support
This commit is contained in:
113
util/genpool/genpool.go
Normal file
113
util/genpool/genpool.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package genpool
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrPoolClosed = errors.New("pool already closed")
|
||||
)
|
||||
|
||||
type getResp[Item interface{}] struct {
|
||||
Item *Item
|
||||
err error
|
||||
}
|
||||
|
||||
type poolReq[Item interface{}] struct {
|
||||
get chan<- getResp[Item]
|
||||
ret *Item
|
||||
}
|
||||
|
||||
type PoolManager[Item interface{}] interface {
|
||||
Destroy(*Item)
|
||||
Create() (*Item, error)
|
||||
Validate(*Item) bool
|
||||
}
|
||||
|
||||
type poolBackend[Item interface{}] struct {
|
||||
manager PoolManager[Item]
|
||||
pool []*Item
|
||||
}
|
||||
|
||||
func (b *poolBackend[Item]) run(ch <-chan poolReq[Item]) {
|
||||
defer func() {
|
||||
for _, item := range b.pool {
|
||||
b.manager.Destroy(item)
|
||||
}
|
||||
}()
|
||||
for req := range ch {
|
||||
if req.get != nil {
|
||||
// fetch an item
|
||||
for {
|
||||
if len(b.pool) > 0 {
|
||||
item := b.pool[len(b.pool)-1]
|
||||
b.pool = b.pool[:len(b.pool)-1]
|
||||
if b.manager.Validate(item) {
|
||||
req.get <- getResp[Item]{
|
||||
Item: item,
|
||||
err: nil,
|
||||
}
|
||||
break
|
||||
} else {
|
||||
b.manager.Destroy(item)
|
||||
}
|
||||
} else {
|
||||
// last item
|
||||
item, err := b.manager.Create()
|
||||
req.get <- getResp[Item]{
|
||||
Item: item,
|
||||
err: err,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.ret != nil {
|
||||
// return an item to the pool
|
||||
if cap(b.pool) > len(b.pool) {
|
||||
b.pool = append(b.pool, req.ret)
|
||||
} else {
|
||||
b.manager.Destroy(req.ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type Pool[Item interface{}] struct {
|
||||
req chan<- poolReq[Item]
|
||||
}
|
||||
|
||||
func NewPool[Item interface{}](manager PoolManager[Item], capacity int) Pool[Item] {
|
||||
cmdChan := make(chan poolReq[Item])
|
||||
backend := poolBackend[Item]{
|
||||
manager: manager,
|
||||
pool: make([]*Item, 0, capacity),
|
||||
}
|
||||
go backend.run(cmdChan)
|
||||
return Pool[Item]{
|
||||
req: cmdChan,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool[Item]) Get() (*Item, error) {
|
||||
retCh := make(chan getResp[Item])
|
||||
p.req <- poolReq[Item]{
|
||||
get: retCh,
|
||||
}
|
||||
item, ok := <-retCh
|
||||
if ok {
|
||||
return item.Item, item.err
|
||||
} else {
|
||||
return nil, ErrPoolClosed
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool[Item]) Put(item *Item) {
|
||||
p.req <- poolReq[Item]{
|
||||
ret: item,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool[Item]) Close() {
|
||||
close(p.req)
|
||||
p.req = nil
|
||||
}
|
||||
Reference in New Issue
Block a user