Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Jedis 2.0.0 with jmx #362

Closed
wants to merge 4 commits into from

2 participants

@gabeki

I have extended Jedis 2.0 and 1.5.2 JedisPool to have JMX capability for monitoring and live configuration updates.

It has been a year in production and testing. I am not closely following your updates but I am wondering would you be interested in merging this feature to the main.

Please review.

Thanks for your work.

Gabriel Ki and others added some commits
@HeartSaVioR
Collaborator

We're using Commons Pool 2 now, closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 22, 2011
  1. Add Jmx to allow real time host/port update

    Gabriel Ki authored
Commits on Mar 15, 2012
  1. @gabeki

    Merge branch 'jedis-1.5.2-jmx' into jedis-2.0.0-jmx

    gabeki authored
    Conflicts:
    	src/main/java/redis/clients/jedis/Jedis.java
    	src/main/java/redis/clients/jedis/JedisPool.java
Commits on Mar 21, 2012
  1. @gabeki

    Fix one of the constructor

    gabeki authored
Commits on Oct 16, 2012
  1. @gabeki
This page is out of date. Refresh to see the latest.
View
14 pom.xml
@@ -63,6 +63,20 @@
<type>jar</type>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.1</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.1</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
<build>
View
4 src/main/java/redis/clients/jedis/Jedis.java
@@ -27,6 +27,10 @@ public Jedis(JedisShardInfo shardInfo) {
super(shardInfo);
}
+ protected String connectedTo() {
+ return client.getHost() + ":" + client.getPort();
+ }
+
public String ping() {
checkIsInMulti();
client.ping();
View
230 src/main/java/redis/clients/jedis/JedisPool.java
@@ -1,12 +1,26 @@
package redis.clients.jedis;
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import redis.clients.util.Pool;
-public class JedisPool extends Pool<Jedis> {
+public class JedisPool extends Pool<Jedis> implements JedisPoolMXBean {
+
+ protected static Logger logger = LoggerFactory.getLogger(JedisPool.class);
+ private JedisFactory factory;
public JedisPool(final Config poolConfig, final String host) {
this(poolConfig, host, Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
@@ -19,31 +33,190 @@ public JedisPool(String host, int port) {
public JedisPool(final String host) {
this(host, Protocol.DEFAULT_PORT);
}
+
+ /**
+ * Same as {@link #JedisPool(String, int)} except this
+ * constructor will also register itself to jmx with the poolName
+ *
+ * @param host
+ * @param port
+ * @param poolName
+ */
+ public JedisPool(final String host, final int port, final String poolName) {
+ this(host, port);
+ register(poolName);
+ }
- public JedisPool(final Config poolConfig, final String host, int port,
+ public JedisPool(final Config poolConfig, final String host, final int port,
int timeout, final String password) {
+ super();
+ factory = new JedisFactory(host, port,
+ ((timeout > 0) ? timeout : -1), password, Protocol.DEFAULT_DATABASE);
+ init(poolConfig, factory);
+ }
+
+ /**
+ * Same as {@link #JedisPool(Config, String, int, int, String)} except this
+ * constructor will also register itself to jmx with the poolName
+ *
+ * @param poolConfig
+ * @param host
+ * @param port
+ * @param timeout
+ * @param password
+ * @param poolName
+ */
+ public JedisPool(final Config poolConfig, final String host, int port,
+ int timeout, final String password, final String poolName) {
this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE);
}
- public JedisPool(final Config poolConfig, final String host, final int port) {
- this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
+ public JedisPool(final Config poolConfig, final String host, int port,
+ int timeout, final String password, final String poolName, final int database) {
+ this(poolConfig, host, port, timeout, password, database);
+ register(poolName);
}
public JedisPool(final Config poolConfig, final String host, final int port, final int timeout) {
this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE);
}
- public JedisPool(final Config poolConfig, final String host, int port, int timeout, final String password,
- final int database) {
- super(poolConfig, new JedisFactory(host, port, timeout, password, database));
+ public JedisPool(final Config poolConfig, final String host, int port, int timeout,
+ final String password, final int database) {
+ super();
+ factory = new JedisFactory(host, port, timeout, password, database);
+ init(poolConfig, factory);
+ }
+
+ /**
+ * Register itself to jmx
+ * @param poolName
+ */
+ private void register(final String poolName) {
+ final String beanName = this.getClass().getPackage().getName() + ":name=" + poolName;
+ logger.info("Registering JMX " + beanName);
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName on = null;
+ try {
+ on = new ObjectName(beanName);
+ } catch (MalformedObjectNameException e) {
+ logger.warn("Unable to register " + beanName, e);
+ return;
+ } catch (NullPointerException e) {
+ logger.warn("Unable to register " + beanName, e);
+ return;
+ }
+
+ if (!mbs.isRegistered(on)) {
+ try {
+ mbs.registerMBean(this, on);
+ } catch (InstanceAlreadyExistsException e) {
+ logger.warn("Unable to register " + beanName, e);
+ } catch (MBeanRegistrationException e) {
+ logger.warn("Unable to register " + beanName, e);
+ } catch (NotCompliantMBeanException e) {
+ logger.warn("Unable to register " + beanName, e);
+ }
+ }
+ }
+
+ @Override
+ public String getHost() {
+ return factory.getHost();
+ }
+
+ @Override
+ public int getPort() {
+ return factory.getPort();
+ }
+
+ @Override
+ public int getTimeout() {
+ return factory.getTimeout();
+ }
+
+ @Override
+ public WhenExhaustedAction getWhenExhaustedAction() {
+ switch (getWhenExhaustedActionByte()) {
+ case GenericObjectPool.WHEN_EXHAUSTED_FAIL:
+ return WhenExhaustedAction.FAIL;
+ case GenericObjectPool.WHEN_EXHAUSTED_GROW:
+ return WhenExhaustedAction.GROW;
+ case GenericObjectPool.WHEN_EXHAUSTED_BLOCK:
+ default:
+ return WhenExhaustedAction.BLOCK;
+ }
+ }
+
+ @Override
+ public void setWhenExhaustedAction(WhenExhaustedAction whenExhaustedAction) {
+ switch (whenExhaustedAction) {
+ case FAIL:
+ setWhenExhaustedActionByte(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
+ break;
+ case BLOCK:
+ setWhenExhaustedActionByte(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
+ break;
+ case GROW:
+ setWhenExhaustedActionByte(GenericObjectPool.WHEN_EXHAUSTED_GROW);
+ break;
+ default:
+ setWhenExhaustedActionByte(GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION);
+ break;
+ }
+ }
+
+ /**
+ * Get Status as String
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" Host:").append(getHost());
+ sb.append(" Port:").append(getPort());
+ sb.append(" Timeout:").append(getTimeout());
+ sb.append(" NumActive:").append(getNumActive());
+ sb.append(" NumIdle:").append(getNumIdle());
+ sb.append(" Lifo?:").append(getLifo());
+ sb.append(" MaxActive:").append(getMaxActive());
+ sb.append(" MaxIdle:").append(getMaxIdle());
+ sb.append(" MaxWait:").append(getMaxWait());
+ sb.append(" MinEvictableIdleTimeMillis:").append(getMinEvictableIdleTimeMillis());
+ sb.append(" MinIdle:").append(getMinIdle());
+ sb.append(" NumTestsPerEvictionRun:").append(getNumTestsPerEvictionRun());
+ sb.append(" SoftMinEvictableIdleTimeMillis:").append(getSoftMinEvictableIdleTimeMillis());
+ sb.append(" TestOnBorrow?:").append(getTestOnBorrow());
+ sb.append(" TestOnReturn?:").append(getTestOnReturn());
+ sb.append(" TestOnReturn?:").append(getTestOnReturn());
+ sb.append(" TimeBetweenEvictionRunsMillis:").append(getTimeBetweenEvictionRunsMillis());
+ sb.append(" WhenExhaustedAction:").append(getWhenExhaustedAction());
+ return sb.toString();
+ }
+
+ /**
+ * Gracefully reset new host and port
+ *
+ * @param host
+ * @param port
+ */
+ @Override
+ public void updateHostAndPort(final String host, final int port) {
+ // update facotry
+ factory.updateHostAndPort(host, port);
+
+ // Remove the idle Jedis
+ clear();
+
+ // the active ones will be either validated off or timed out if
+ // all of the TestOn* was set to false.
}
/**
* PoolableObjectFactory custom impl.
*/
private static class JedisFactory extends BasePoolableObjectFactory {
- private final String host;
- private final int port;
+ private String host;
+ private int port;
private final int timeout;
private final String password;
private final int database;
@@ -58,12 +231,37 @@ public JedisFactory(final String host, final int port,
this.database = database;
}
+ public void updateHostAndPort(final String host, final int port) {
+ synchronized (this) {
+ this.host = host;
+ this.port = port;
+ }
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ @Override
public Object makeObject() throws Exception {
- final Jedis jedis = new Jedis(this.host, this.port, this.timeout);
+ final Jedis jedis;
+ if (timeout > 0) {
+ jedis = new Jedis(host, port, timeout);
+ } else {
+ jedis = new Jedis(host, port);
+ }
jedis.connect();
- if (null != this.password) {
- jedis.auth(this.password);
+ if (null != password) {
+ jedis.auth(password);
}
if( database != 0 ) {
jedis.select(database);
@@ -72,6 +270,7 @@ public Object makeObject() throws Exception {
return jedis;
}
+ @Override
public void destroyObject(final Object obj) throws Exception {
if (obj instanceof Jedis) {
final Jedis jedis = (Jedis) obj;
@@ -89,9 +288,15 @@ public void destroyObject(final Object obj) throws Exception {
}
}
+ @Override
public boolean validateObject(final Object obj) {
if (obj instanceof Jedis) {
final Jedis jedis = (Jedis) obj;
+ String currentHost = host + ":" + port;
+ if (!jedis.connectedTo().equals(currentHost)) {
+ return false;
+ }
+
try {
return jedis.isConnected() && jedis.ping().equals("PONG");
} catch (final Exception e) {
@@ -101,6 +306,5 @@ public boolean validateObject(final Object obj) {
return false;
}
}
-
}
}
View
42 src/main/java/redis/clients/jedis/JedisPoolMXBean.java
@@ -0,0 +1,42 @@
+package redis.clients.jedis;
+
+public interface JedisPoolMXBean {
+
+ public enum WhenExhaustedAction {FAIL, BLOCK, GROW};
+
+ // Attributes
+ String getHost();
+ int getPort();
+ int getTimeout();
+ int getNumActive();
+ int getNumIdle();
+
+ boolean getLifo();
+ int getMaxActive();
+ int getMaxIdle();
+ long getMaxWait();
+ long getMinEvictableIdleTimeMillis();
+ int getMinIdle();
+ int getNumTestsPerEvictionRun();
+ long getSoftMinEvictableIdleTimeMillis();
+ boolean getTestOnBorrow();
+ boolean getTestOnReturn();
+ boolean getTestWhileIdle();
+ long getTimeBetweenEvictionRunsMillis();
+ WhenExhaustedAction getWhenExhaustedAction();
+
+ // Operations
+ void updateHostAndPort(String host, int port);
+ void setMaxActive(int maxActive);
+ void setMaxIdle(int maxIdle);
+ void setMaxWait(long maxWait);
+ void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis);
+ void setMinIdle(int minIdle);
+ void setNumTestsPerEvictionRun(int numTestsPerEvictionRun);
+ void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis);
+ void setTestOnBorrow(boolean testOnBorrow);
+ void setTestOnReturn(boolean testOnReturn);
+ void setTestWhileIdle(boolean testWhileIdle);
+ void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis);
+ void setWhenExhaustedAction(WhenExhaustedAction whenExhaustedAction);
+}
View
105 src/main/java/redis/clients/util/Pool.java
@@ -7,11 +7,20 @@
import redis.clients.jedis.exceptions.JedisException;
public abstract class Pool<T> {
- private final GenericObjectPool internalPool;
+ private GenericObjectPool internalPool;
public Pool(final GenericObjectPool.Config poolConfig,
PoolableObjectFactory factory) {
- this.internalPool = new GenericObjectPool(factory, poolConfig);
+ init(poolConfig, factory);
+ }
+
+ public Pool() {
+ internalPool = null;
+ }
+
+ protected void init(final GenericObjectPool.Config poolConfig,
+ PoolableObjectFactory factory) {
+ internalPool = new GenericObjectPool(factory, poolConfig);
}
@SuppressWarnings("unchecked")
@@ -49,4 +58,94 @@ public void destroy() {
throw new JedisException("Could not destroy the pool", e);
}
}
-}
+
+ public void clear() {
+ try {
+ internalPool.clear();
+ } catch (Exception e) {
+ throw new JedisException("Could not clear the pool", e);
+ }
+ }
+
+ public int getNumActive() {
+ return internalPool.getNumActive();
+ }
+ public int getNumIdle() {
+ return internalPool.getNumIdle();
+ }
+ public boolean getLifo() {
+ return internalPool.getLifo();
+ }
+ public int getMaxActive() {
+ return internalPool.getMaxActive();
+ }
+ public int getMaxIdle() {
+ return internalPool.getMaxIdle();
+ }
+ public long getMaxWait() {
+ return internalPool.getMaxWait();
+ }
+ public long getMinEvictableIdleTimeMillis() {
+ return internalPool.getMinEvictableIdleTimeMillis();
+ }
+ public int getMinIdle() {
+ return internalPool.getMinIdle();
+ }
+ public int getNumTestsPerEvictionRun() {
+ return internalPool.getNumTestsPerEvictionRun();
+ }
+ public long getSoftMinEvictableIdleTimeMillis() {
+ return internalPool.getSoftMinEvictableIdleTimeMillis();
+ }
+ public boolean getTestOnBorrow() {
+ return internalPool.getTestOnBorrow();
+ }
+ public boolean getTestOnReturn() {
+ return internalPool.getTestOnReturn();
+ }
+ public boolean getTestWhileIdle() {
+ return internalPool.getTestWhileIdle();
+ }
+ public long getTimeBetweenEvictionRunsMillis() {
+ return internalPool.getTimeBetweenEvictionRunsMillis();
+ }
+ public byte getWhenExhaustedActionByte() {
+ return internalPool.getWhenExhaustedAction();
+ }
+ public void setMaxActive(int maxActive) {
+ internalPool.setMaxActive(maxActive);
+ }
+ public void setMaxIdle(int maxIdle) {
+ internalPool.setMaxIdle(maxIdle);
+ }
+ public void setMaxWait(long maxWait) {
+ internalPool.setMaxWait(maxWait);
+ }
+ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
+ internalPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ }
+ public void setMinIdle(int minIdle) {
+ internalPool.setMinIdle(minIdle);
+ }
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ internalPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ }
+ public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
+ internalPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ }
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ internalPool.setTestOnBorrow(testOnBorrow);
+ }
+ public void setTestOnReturn(boolean testOnReturn) {
+ internalPool.setTestOnReturn(testOnReturn);
+ }
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ internalPool.setTestWhileIdle(testWhileIdle);
+ }
+ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
+ internalPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ }
+ public void setWhenExhaustedActionByte(byte whenExhaustedAction) {
+ internalPool.setWhenExhaustedAction(whenExhaustedAction);
+ }
+}
Something went wrong with that request. Please try again.