Beispiel #1
0
// NewResourcePool use to create pool for resource
func NewResourcePool(address string, factory GroupFactory, initNum, maxCap int, idleTimeout time.Duration, circuitBreaker *circuit.CircuitBreaker) *ResourcePool {
	if maxCap <= 0 {
		panic(errors.New("invalid of max capacity"))
	}
	var (
		resourcePool *ResourcePool
		err          error
	)
	resourcePool = &ResourcePool{
		factory:     factory,
		resources:   make(chan resourceWrapper, maxCap),
		idleTimeout: idleTimeout,
	}
	for i := 0; i < initNum; i++ {
		var res Resource
		res, err = factory()
		if err != nil {
			continue
		}
		log.Infof(nil, "Init resource %v", res)
		resourcePool.resources <- resourceWrapper{res, time.Now()}
	}
	resourcePool.address = address
	resourcePool.circuitBreaker = circuitBreaker
	return resourcePool
}
Beispiel #2
0
// enqueue is used to do real enqueue op
func (r *ResourcePool) enqueue(ctx context.Context, res Resource) {

	if r.address != res.Address() {
		log.Errorf(ctx, "FATAL: Conn %s back to wrong pool %s\n", r.address, res.Address())
	}

	start := time.Now()
	log.Infof(ctx, "Start enqueue, address: %s, av-size: %d\n", res.Address(), len(r.resources))
	select {
	case r.resources <- resourceWrapper{res, time.Now()}:
		log.Infof(ctx, "Put resource back, address: %s, av-size: %d,  waste-time: %d\n", res.Address(), len(r.resources), time.Now().Sub(start).Nanoseconds())
		return
	default:
		log.Warningf(ctx, "Put resource back failure, because full close it, address: %s, waste-time: %d\n", res.Address(), len(r.resources))
		r.closeConn(ctx, res)
	}

}
Beispiel #3
0
// Get resource from pool
func (r *ResourcePool) get(ctx context.Context, wait bool) (Resource, error) {

	select {
	case <-ctx.Done():
		return nil, ErrTimeout
	default:
	}

	var (
		wrapper resourceWrapper
		err     error
	)

	start := time.Now()
	for {
		select {
		case wrapper = <-r.resources:
			if time.Now().Sub(wrapper.timeUsed) >= r.idleTimeout {
				log.Warningf(ctx, "Get idle timeout resource, address: %s, av-size: %d,  waste-time: %d\n", wrapper.resource.Address(), len(r.resources), time.Now().Sub(start).Nanoseconds())
				r.closeConn(ctx, wrapper.resource)
				continue
			}
			log.Infof(ctx, "Get resouce from pool success, address: %v, av-size: %d,  waste-time: %d\n", wrapper.resource.Address(), len(r.resources), time.Now().Sub(start).Nanoseconds())
			return wrapper.resource, nil
		default:
			log.Warningf(ctx, "Have not enough resource in pool, start create resource, address: %s, av-size: %d\n", r.address, len(r.resources))
			var res Resource
			if res, err = r.factory(); err != nil {
				log.Errorf(ctx, "create resource failure, error: %v", err)
				return nil, err
			}
			log.Infof(ctx, "Create new resource successed, address: %s", res.Address())

			r.enqueue(ctx, res)

			log.Infof(ctx, "New resource back to queue sucessed, address: %s, av-size: %d", res.Address(), len(r.resources))

			continue
		}
	}
}
Beispiel #4
0
func (r *ResourcePool) closeConn(ctx context.Context, resource Resource) {

	if resource == nil {
		return
	}

	err := resource.RawClose()
	if err != nil {
		log.Errorf(ctx, "Close connection but failured, address: %s", r.address)
	}
	log.Infof(ctx, "Close resource: %s", resource.Address())

}
Beispiel #5
0
// Get is used to get resource form group pool
func (p *Group) Get(ctx context.Context) (Resource, error) {
	pool, _, err := p.selectPool(ctx)
	if err == nil {
		return nil, err
	}
	res, err := pool.Get(ctx)
	if err != nil {
		log.Errorf(ctx, "Select pool failure, error: %v", err)
		return nil, err
	}
	log.Infof(ctx, "Selected pool %s with %d\n", res.Address())
	return res, nil
}