Skip to content

Commit

Permalink
Resolve hostname of node again during reconnection
Browse files Browse the repository at this point in the history
This is essential when memcached cluster is built on cloud infra, e.g.
k8s, where nodes move and their ips vary.
  • Loading branch information
bigmarvin committed Aug 31, 2020
1 parent eb5d6ee commit 812fa63
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/main/java/net/spy/memcached/MemcachedConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ private void attemptReconnects() {
ch.configureBlocking(false);
ch.socket().setTcpNoDelay(!connectionFactory.useNagleAlgorithm());
int ops = 0;
if (ch.connect(node.getSocketAddress())) {
if (ch.connect(node.getSocketAddress(true))) {
connected(node);
addedQueue.offer(node);
getLogger().info("Immediately reconnected to %s", node);
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/spy/memcached/MemcachedNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ public interface MemcachedNode {
*/
SocketAddress getSocketAddress();

/**
* Get the SocketAddress of the server to which this node is connected, and resolve it again if specified.
*
* @param resolve whether to resolve and update the address
* @return The SocketAddress of the server to which this node is connected
*/
SocketAddress getSocketAddress(boolean resolve);

/**
* True if this node is <q>active.</q> i.e. is is currently connected and
* expected to be able to process requests
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/spy/memcached/MemcachedNodeROImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public SocketAddress getSocketAddress() {
return root.getSocketAddress();
}

public SocketAddress getSocketAddress(boolean resolve) {
return root.getSocketAddress(resolve);
}

public ByteBuffer getWbuf() {
throw new UnsupportedOperationException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package net.spy.memcached.protocol;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
Expand Down Expand Up @@ -51,7 +52,7 @@
public abstract class TCPMemcachedNodeImpl extends SpyObject implements
MemcachedNode {

private final SocketAddress socketAddress;
private SocketAddress socketAddress;
private final ByteBuffer rbuf;
private final ByteBuffer wbuf;
protected final BlockingQueue<Operation> writeQ;
Expand Down Expand Up @@ -426,6 +427,22 @@ public final ByteBuffer getWbuf() {
* @see net.spy.memcached.MemcachedNode#getSocketAddress()
*/
public final SocketAddress getSocketAddress() {
return getSocketAddress(false);
}

public final SocketAddress getSocketAddress(boolean resolve) {
if (resolve && socketAddress instanceof InetSocketAddress) {
InetSocketAddress originalAddress = (InetSocketAddress) socketAddress;
InetSocketAddress resolvedAddress = new InetSocketAddress(
originalAddress.getHostName(), originalAddress.getPort());

if (!originalAddress.equals(resolvedAddress)) {
socketAddress = resolvedAddress;
getLogger().info("node address changed from %s to %s",
originalAddress, resolvedAddress);
}
}

return socketAddress;
}

Expand Down
4 changes: 4 additions & 0 deletions src/test/java/net/spy/memcached/MockMemcachedNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public SocketAddress getSocketAddress() {
return socketAddress;
}

public SocketAddress getSocketAddress(boolean resolve) {
return socketAddress; // sufficiently good
}

public MockMemcachedNode(InetSocketAddress socketAddress) {
this.socketAddress = socketAddress;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.spy.memcached.protocol.binary;

import junit.framework.Assert;
import net.spy.memcached.DefaultConnectionFactory;
import net.spy.memcached.MemcachedNode;
import net.spy.memcached.ops.Operation;
import org.junit.Test;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class AddressResolutionTest {
@Test
public void testResolveAddressWithHostname() throws Exception {
BlockingQueue<Operation> queue = new ArrayBlockingQueue<>(1);
MemcachedNode node = new BinaryMemcachedNodeImpl(new InetSocketAddress("memcached.org", 80),
SocketChannel.open(), 1024, queue, queue, queue, 1024L, false,
1024, 1024, new DefaultConnectionFactory());
SocketAddress originalSocketAddress = node.getSocketAddress();
SocketAddress resolvedSocketAddress = node.getSocketAddress(true);
Assert.assertEquals("socket address with hostname couldn't be resolved",
originalSocketAddress, resolvedSocketAddress);
}

@Test
public void testResolveAddressWithAddress() throws Exception {
BlockingQueue<Operation> queue = new ArrayBlockingQueue<>(1);
MemcachedNode node = new BinaryMemcachedNodeImpl(
new InetSocketAddress(InetAddress.getByName("memcached.org"), 80),
SocketChannel.open(), 1024, queue, queue, queue, 1024L, false,
1024, 1024, new DefaultConnectionFactory());
SocketAddress originalSocketAddress = node.getSocketAddress();
SocketAddress resolvedSocketAddress = node.getSocketAddress(true);
Assert.assertEquals("socket address with address couldn't be resolved",
originalSocketAddress, resolvedSocketAddress);
}

@Test
public void testResolveAddressWithAddressAsHostname() throws Exception {
BlockingQueue<Operation> queue = new ArrayBlockingQueue<>(1);
MemcachedNode node = new BinaryMemcachedNodeImpl(
new InetSocketAddress(InetAddress.getByName("memcached.org").getHostAddress(), 80),
SocketChannel.open(), 1024, queue, queue, queue, 1024L, false,
1024, 1024, new DefaultConnectionFactory());
SocketAddress originalSocketAddress = node.getSocketAddress();
SocketAddress resolvedSocketAddress = node.getSocketAddress(true);
Assert.assertEquals("socket address with address as hostname couldn't be resolved",
originalSocketAddress, resolvedSocketAddress);
}
}

0 comments on commit 812fa63

Please sign in to comment.