package pool import ( "sync" "sync/atomic" ) type connList struct { cns []*Conn mx sync.Mutex len int32 // atomic size int32 } func newConnList(size int) *connList { return &connList{ cns: make([]*Conn, 0, size), size: int32(size), } } func (l *connList) Len() int { return int(atomic.LoadInt32(&l.len)) } // Reserve reserves place in the list and returns true on success. The // caller must add or remove connection if place was reserved. func (l *connList) Reserve() bool { len := atomic.AddInt32(&l.len, 1) reserved := len <= l.size if !reserved { atomic.AddInt32(&l.len, -1) } return reserved } // Add adds connection to the list. The caller must reserve place first. func (l *connList) Add(cn *Conn) { l.mx.Lock() l.cns = append(l.cns, cn) l.mx.Unlock() } // Remove closes connection and removes it from the list. func (l *connList) Remove(cn *Conn) error { defer l.mx.Unlock() l.mx.Lock() if cn == nil { atomic.AddInt32(&l.len, -1) return nil } for i, c := range l.cns { if c == cn { l.cns = append(l.cns[:i], l.cns[i+1:]...) atomic.AddInt32(&l.len, -1) return cn.Close() } } if l.closed() { return nil } panic("conn not found in the list") } func (l *connList) Replace(cn, newcn *Conn) error { defer l.mx.Unlock() l.mx.Lock() for i, c := range l.cns { if c == cn { l.cns[i] = newcn return cn.Close() } } if l.closed() { return newcn.Close() } panic("conn not found in the list") } func (l *connList) Close() (retErr error) { l.mx.Lock() for _, c := range l.cns { if err := c.Close(); err != nil { retErr = err } } l.cns = nil atomic.StoreInt32(&l.len, 0) l.mx.Unlock() return retErr } func (l *connList) closed() bool { return l.cns == nil }