<commit_before>package pttbbs

import (
	"code.google.com/p/vitess/go/memcache"
	"log"
	"time"
)

type MemcacheConnPool struct {
	idle            chan connectResult
	drop            chan error
	req             chan int
	nrOpen, maxOpen int
	nrWait          int
	server          string
}

type connectResult struct {
	conn *memcache.Connection
	err  error
}

func NewMemcacheConnPool(server string, maxOpen int) *MemcacheConnPool {
	m := &MemcacheConnPool{
		idle:    make(chan connectResult),
		drop:    make(chan error),
		req:     make(chan int),
		nrOpen:  0,
		maxOpen: maxOpen,
		nrWait:  0,
		server:  server,
	}
	go m.manager()
	return m
}

func (m *MemcacheConnPool) GetConn() (*memcache.Connection, error) {
	var r connectResult
	select {
	case r = <-m.idle:
	default:
		m.req <- 1
		r = <-m.idle
		m.req <- -1
	}
	if r.err != nil {
		m.DropConn(r.conn)
	}
	return r.conn, r.err
}

func (m *MemcacheConnPool) ReleaseConn(c *memcache.Connection, err error) {
	if err != nil {
		if me, ok := err.(memcache.MemcacheError); ok {
			log.Printf("MemcacheConnPool: dropping bad connection to %s due to error: %s\n",
				m.server, me.Error())
			m.DropConn(c)
			return
		}
	}
	go func(c *memcache.Connection) {
		select {
		case m.idle <- connectResult{conn: c, err: nil}:
			// Somebody got it
		case <-time.After(time.Second * 10):
			// Timeout, close it
			m.DropConn(c)
		}
	}(c)
}

func (m *MemcacheConnPool) DropConn(c *memcache.Connection) {
	m.drop <- nil
	if c != nil {
		c.Close()
	}
}

func (m *MemcacheConnPool) manager() {
	for {
		select {
		case <-m.drop:
			m.nrOpen--
		case i := <-m.req:
			m.nrWait += i
		}
		for i := m.nrWait; i > 0 && m.nrOpen < m.maxOpen; i-- {
			m.nrOpen++
			go m.connect()
		}
	}
}

func (m *MemcacheConnPool) connect() {
	if c, err := memcache.Connect(m.server); err != nil {
		m.idle <- connectResult{conn: c, err: err}
	} else {
		m.ReleaseConn(c, nil)
	}
}
<commit_msg>Reorder import paths.<commit_after>package pttbbs

import (
	"log"
	"time"

	"code.google.com/p/vitess/go/memcache"
)

type MemcacheConnPool struct {
	idle            chan connectResult
	drop            chan error
	req             chan int
	nrOpen, maxOpen int
	nrWait          int
	server          string
}

type connectResult struct {
	conn *memcache.Connection
	err  error
}

func NewMemcacheConnPool(server string, maxOpen int) *MemcacheConnPool {
	m := &MemcacheConnPool{
		idle:    make(chan connectResult),
		drop:    make(chan error),
		req:     make(chan int),
		nrOpen:  0,
		maxOpen: maxOpen,
		nrWait:  0,
		server:  server,
	}
	go m.manager()
	return m
}

func (m *MemcacheConnPool) GetConn() (*memcache.Connection, error) {
	var r connectResult
	select {
	case r = <-m.idle:
	default:
		m.req <- 1
		r = <-m.idle
		m.req <- -1
	}
	if r.err != nil {
		m.DropConn(r.conn)
	}
	return r.conn, r.err
}

func (m *MemcacheConnPool) ReleaseConn(c *memcache.Connection, err error) {
	if err != nil {
		if me, ok := err.(memcache.MemcacheError); ok {
			log.Printf("MemcacheConnPool: dropping bad connection to %s due to error: %s\n",
				m.server, me.Error())
			m.DropConn(c)
			return
		}
	}
	go func(c *memcache.Connection) {
		select {
		case m.idle <- connectResult{conn: c, err: nil}:
			// Somebody got it
		case <-time.After(time.Second * 10):
			// Timeout, close it
			m.DropConn(c)
		}
	}(c)
}

func (m *MemcacheConnPool) DropConn(c *memcache.Connection) {
	m.drop <- nil
	if c != nil {
		c.Close()
	}
}

func (m *MemcacheConnPool) manager() {
	for {
		select {
		case <-m.drop:
			m.nrOpen--
		case i := <-m.req:
			m.nrWait += i
		}
		for i := m.nrWait; i > 0 && m.nrOpen < m.maxOpen; i-- {
			m.nrOpen++
			go m.connect()
		}
	}
}

func (m *MemcacheConnPool) connect() {
	if c, err := memcache.Connect(m.server); err != nil {
		m.idle <- connectResult{conn: c, err: err}
	} else {
		m.ReleaseConn(c, nil)
	}
}

{'fraction_non_alphanumeric': 0.1452325279293323, 'fraction_numerical': 0.0036373083917900753, 'mean_word_length': 2.6912751677852347, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1732206', 'n_tokens_mistral': 1641, 'n_tokens_neox': 1519, 'n_words': 386}