diff --git a/Makefile b/Makefile index 9c1d2bae76..4d765fab64 100644 --- a/Makefile +++ b/Makefile @@ -211,6 +211,19 @@ cluster-enabled yes cluster-config-file /tmp/redis_cluster_node5.conf endef +# UDS REDIS NODES +define REDIS_UDS +daemonize yes +protected-mode no +port 0 +pidfile /tmp/redis_uds.pid +logfile /tmp/redis_uds.log +unixsocket /tmp/redis_6379.sock +unixsocketperm 777 +save "" +appendonly no +endef + #STUNNEL define STUNNEL_CONF cert = src/test/resources/private.pem @@ -236,6 +249,7 @@ export REDIS_CLUSTER_NODE2_CONF export REDIS_CLUSTER_NODE3_CONF export REDIS_CLUSTER_NODE4_CONF export REDIS_CLUSTER_NODE5_CONF +export REDIS_UDS export STUNNEL_CONF export STUNNEL_BIN @@ -265,6 +279,7 @@ start: stunnel cleanup echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE4_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE5_CONF" | redis-server - + echo "$$REDIS_UDS" | redis-server - cleanup: - rm -vf /tmp/redis_cluster_node*.conf 2>/dev/null @@ -291,6 +306,7 @@ stop: kill `cat /tmp/redis_cluster_node3.pid` || true kill `cat /tmp/redis_cluster_node4.pid` || true kill `cat /tmp/redis_cluster_node5.pid` || true + kill `cat /tmp/redis_uds.pid` || true kill `cat /tmp/stunnel.pid` || true rm -f /tmp/sentinel1.conf rm -f /tmp/sentinel2.conf diff --git a/pom.xml b/pom.xml index 4f9e8bebb5..08f62d591f 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385 localhost:26379,localhost:26380,localhost:26381 localhost:7379,localhost:7380,localhost:7381,localhost:7382,localhost:7383,localhost:7384,localhost:7385 + /tmp/redis_6379.sock github @@ -64,6 +65,11 @@ jar compile + + com.kohlschutter.junixsocket + junixsocket-native-common + 2.0.4 + junit diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index a818eff8c5..306273f87a 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -13,6 +13,7 @@ import static redis.clients.jedis.Protocol.Keyword.STORE; import static redis.clients.jedis.Protocol.Keyword.WITHSCORES; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -49,6 +50,10 @@ public BinaryClient(final String host) { super(host); } + public BinaryClient(final File unixDomainSocket) { + super(unixDomainSocket); + } + public BinaryClient(final String host, final int port) { super(host, port); } diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 85c5b97829..9d8e2578c3 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -3,6 +3,7 @@ import static redis.clients.jedis.Protocol.toByteArray; import java.io.Closeable; +import java.io.File; import java.io.Serializable; import java.net.URI; import java.util.AbstractMap; @@ -56,6 +57,10 @@ public BinaryJedis(final String host) { } } + public BinaryJedis(final File unixDomainSocket) { + client = new Client(unixDomainSocket); + } + public BinaryJedis(final HostAndPort hp) { this(hp.getHost(), hp.getPort()); } diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 40a6c7cd4d..e567c203a2 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -2,6 +2,7 @@ import static redis.clients.jedis.Protocol.toByteArray; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -30,6 +31,10 @@ public Client(final String host) { super(host); } + public Client(final File unixDomainSocket) { + super(unixDomainSocket); + } + public Client(final String host, final int port) { super(host, port); } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 2ae106867f..6291288eca 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -1,9 +1,11 @@ package redis.clients.jedis; import java.io.Closeable; +import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.SocketAddress; import java.net.SocketException; import java.util.ArrayList; import java.util.List; @@ -13,6 +15,8 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import org.newsclub.net.unix.AFUNIXSocket; +import org.newsclub.net.unix.AFUNIXSocketAddress; import redis.clients.jedis.commands.ProtocolCommand; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisDataException; @@ -37,6 +41,7 @@ public class Connection implements Closeable { private SSLSocketFactory sslSocketFactory; private SSLParameters sslParameters; private HostnameVerifier hostnameVerifier; + private File unixDomainSocket; public Connection() { } @@ -45,6 +50,10 @@ public Connection(final String host) { this.host = host; } + public Connection(final File unixDomainSocket) { + this.unixDomainSocket = unixDomainSocket; + } + public Connection(final String host, final int port) { this.host = host; this.port = port; @@ -166,19 +175,27 @@ public void setPort(final int port) { public void connect() { if (!isConnected()) { try { - socket = new Socket(); - // ->@wjw_add - socket.setReuseAddress(true); - socket.setKeepAlive(true); // Will monitor the TCP connection is - // valid - socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to - // ensure timely delivery of data - socket.setSoLinger(true, 0); // Control calls close () method, - // the underlying socket is closed - // immediately - // <-@wjw_add - - socket.connect(new InetSocketAddress(host, port), connectionTimeout); + SocketAddress socketAddress; + if (unixDomainSocket == null) { + socket = new Socket(); + // ->@wjw_add + socket.setReuseAddress(true); + socket.setKeepAlive(true); // Will monitor the TCP connection is + // valid + socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to + // ensure timely delivery of data + socket.setSoLinger(true, 0); // Control calls close () method, + // the underlying socket is closed + // immediately + // <-@wjw_add + socketAddress = new InetSocketAddress(host, port); + } else { + // unix domain socket doesn't support above options + socket = AFUNIXSocket.newStrictInstance(); + socketAddress = new AFUNIXSocketAddress(unixDomainSocket); + } + + socket.connect(socketAddress, connectionTimeout); socket.setSoTimeout(soTimeout); if (ssl) { @@ -201,8 +218,13 @@ public void connect() { inputStream = new RedisInputStream(socket.getInputStream()); } catch (IOException ex) { broken = true; - throw new JedisConnectionException("Failed connecting to host " - + host + ":" + port, ex); + if (unixDomainSocket == null) { + throw new JedisConnectionException("Failed connecting to host " + + host + ":" + port, ex); + } else { + throw new JedisConnectionException("Failed connecting to socket " + + unixDomainSocket, ex); + } } } } diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index e83e891672..284730126d 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -1,5 +1,6 @@ package redis.clients.jedis; +import java.io.File; import java.net.URI; import java.util.AbstractMap; import java.util.ArrayList; @@ -42,6 +43,10 @@ public Jedis(final String host) { super(host); } + public Jedis(final File unixDomainSocket) { + super(unixDomainSocket); + } + public Jedis(final HostAndPort hp) { super(hp); } diff --git a/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java b/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java index ced599cc05..01e9b8a109 100644 --- a/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java +++ b/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java @@ -1,5 +1,6 @@ package redis.clients.jedis.tests; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -10,6 +11,7 @@ public final class HostAndPortUtil { private static List redisHostAndPortList = new ArrayList(); private static List sentinelHostAndPortList = new ArrayList(); private static List clusterHostAndPortList = new ArrayList(); + private static List redisUDSList = new ArrayList(); private HostAndPortUtil(){ throw new InstantiationError( "Must not instantiate this class" ); @@ -36,13 +38,17 @@ private HostAndPortUtil(){ clusterHostAndPortList.add(new HostAndPort("localhost", 7383)); clusterHostAndPortList.add(new HostAndPort("localhost", 7384)); + redisUDSList.add(new File("/tmp/redis_6379.sock")); + String envRedisHosts = System.getProperty("redis-hosts"); String envSentinelHosts = System.getProperty("sentinel-hosts"); String envClusterHosts = System.getProperty("cluster-hosts"); + String envUDSHosts = System.getProperty("uds-hosts"); redisHostAndPortList = parseHosts(envRedisHosts, redisHostAndPortList); sentinelHostAndPortList = parseHosts(envSentinelHosts, sentinelHostAndPortList); clusterHostAndPortList = parseHosts(envClusterHosts, clusterHostAndPortList); + redisUDSList = parseUDSHosts(envUDSHosts, redisUDSList); } public static List parseHosts(String envHosts, @@ -80,6 +86,19 @@ public static List parseHosts(String envHosts, return existingHostsAndPorts; } + public static List parseUDSHosts(String envHosts, List existingUDSHosts) { + if (null != envHosts && 0 < envHosts.length()) { + + String[] hostDefs = envHosts.split(","); + + List envUDSHosts = new ArrayList<>(); + for (String hostDef : hostDefs) { + envUDSHosts.add(new File(hostDef)); + } + } + return existingUDSHosts; + } + public static List getRedisServers() { return redisHostAndPortList; } @@ -91,4 +110,8 @@ public static List getSentinelServers() { public static List getClusterServers() { return clusterHostAndPortList; } + + public static List getUDSServers() { + return redisUDSList; + } } diff --git a/src/test/java/redis/clients/jedis/tests/UDSTest.java b/src/test/java/redis/clients/jedis/tests/UDSTest.java new file mode 100644 index 0000000000..2cb3fb32f9 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tests/UDSTest.java @@ -0,0 +1,18 @@ +package redis.clients.jedis.tests; + +import org.junit.Test; +import redis.clients.jedis.Jedis; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +public class UDSTest { + protected static File udsHost = HostAndPortUtil.getUDSServers().get(0); + @Test + public void testCompareTo() { + Jedis jedis = new Jedis(udsHost); + assertEquals("PONG", jedis.ping()); + jedis.close(); + } +}