Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Comment on lines +440 to +441
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR. Really saved us when we encountered this issue in production )

If anyone else comes across this pull request, I suggest adding this line so that the IP address in the logs is updated as well.

Suggested change
socketAddress = resolvedAddress;
getLogger().info("node address changed from %s to %s",
socketAddress = resolvedAddress;
connection.setName("Memcached IO over " + connection);
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);
}
}