/** * */ package com.trendrr.beanstalk; import java.util.Date; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @author dustin * */ public class BeanstalkPool { protected Log log = LogFactory.getLog(BeanstalkPool.class); Set<BeanstalkClient> clients = new HashSet<BeanstalkClient>(); int maxClients = 30; long maxUseTime = 20*60*1000; //max checkout time is 20 minutes. long maxIdleTime = 20*60*1000; //connection will be removed after no use. private String addr; private int port; private String tube = null; /** * setup a new pool. * * @param addr address of the beanstalkd server to connection to * @param port port of the beanstalkd server * @param maxPoolSize maximum number of clients allowed in the pool (0 for infinity) * @param tube All operations for the client will work on the tube. */ public BeanstalkPool(String addr, int port, int maxPoolSize, String tube) { this.addr = addr; this.port = port; this.maxClients = maxPoolSize; this.tube = tube; } /** * setup a new pool. * * @param addr address of the beanstalkd server to connection to * @param port port of the beanstalkd server * @param maxPoolSize maximum number of clients allowed in the pool (0 for infinity) */ public BeanstalkPool(String addr, int port, int maxPoolSize) { this(addr, port, maxPoolSize, null); } /** * returns the number of active clients in the pool * @return */ public int getPoolSize() { return this.clients.size(); } /** * * This gets a client from the pool. will throw a BeanstalkException if * there are more then the maximum number of clients checked out. * * @return */ public synchronized BeanstalkClient getClient() throws BeanstalkException{ /* * synchronized, but should be fast as the client initialization code happens lazily. */ Set<BeanstalkClient> toRemove = new HashSet<BeanstalkClient>(); Date max = new Date(new Date().getTime() - this.maxUseTime); Date maxIdle = new Date(new Date().getTime() - this.maxIdleTime); BeanstalkClient returnClient = null; try { /* * Here we iterate over all the clients and reap any that need reaping. * TODO: we could restrict this to only loop over once every minute or so. * for now I don't see it being a huge problem. */ for (BeanstalkClient client : clients) { if (client.inUseSince != null && client.inUseSince.before(max)) { client.reap = true; } if (client.lastUsed != null && client.lastUsed.before(maxIdle)) { client.reap = true; } if (client.con != null && ! client.con.isOpen()) { client.reap = true; } if (client.reap) { toRemove.add(client); } else if (returnClient == null && client.inUseSince == null) { //found the useable client. client.inUseSince = new Date(); client.lastUsed = new Date(); //reap old connections returnClient = client; } } } finally { for (BeanstalkClient c : toRemove) { log.debug("REAPING Client: " + c); c.pool = null; this.clients.remove(c); c.close(); } } if (returnClient != null) return returnClient; //add a new client if they are all closed. if (this.maxClients > 0 && this.clients.size() >= this.maxClients) { log.error("Too many clients in use!"); throw new BeanstalkException("To many clients in use"); } BeanstalkClient client = new BeanstalkClient(this.addr, this.port, this.tube, this); this.clients.add(client); client.inUseSince = new Date(); return client; } /** * returns a client to the pool * @param client */ public synchronized void done(BeanstalkClient client) { client.inUseSince = null; } }