diff --git a/src/main/java/com/couchbase/client/vbucket/VBucketNodeLocator.java b/src/main/java/com/couchbase/client/vbucket/VBucketNodeLocator.java index 6e993f52..2cca5ade 100644 --- a/src/main/java/com/couchbase/client/vbucket/VBucketNodeLocator.java +++ b/src/main/java/com/couchbase/client/vbucket/VBucketNodeLocator.java @@ -71,6 +71,15 @@ public MemcachedNode getPrimary(String k) { Map nodesMap = totConfig.getNodesMap(); int vbucket = config.getVbucketByKey(k); int serverNumber = config.getMaster(vbucket); + + if(serverNumber == -1) { + throw new RuntimeException("The key "+ k +" pointed to vbucket "+ vbucket + + ", for which no server is responsible in the cluster map. This " + + "can be an indication that either no replica is defined for a " + + "failed server or more nodes have been failed over than replicas " + + "defined."); + } + String server = config.getServer(serverNumber); // choose appropriate MemcachedNode according to config data MemcachedNode pNode = nodesMap.get(server); diff --git a/src/test/java/com/couchbase/client/vbucket/VBucketNodeLocatorTest.java b/src/test/java/com/couchbase/client/vbucket/VBucketNodeLocatorTest.java index b9227d60..b6504c58 100644 --- a/src/test/java/com/couchbase/client/vbucket/VBucketNodeLocatorTest.java +++ b/src/test/java/com/couchbase/client/vbucket/VBucketNodeLocatorTest.java @@ -30,7 +30,7 @@ import java.util.Arrays; import junit.framework.TestCase; - +import org.junit.Test; import net.spy.memcached.MemcachedNode; import static org.easymock.EasyMock.createMock; @@ -62,6 +62,24 @@ public class VBucketNodeLocatorTest extends TestCase { + " [1, 2, 0],\n" + " [2, 1, -1],\n" + " [1, 2, 0]\n" + " ]\n" + "}" + "}"; + private static final String NO_REPLICA_CONFIG_IN_ENVELOPE = + "{ \"otherKeyThatIsIgnored\": 12345,\n" + + "\"nodes\": [\n" + + "{\n" + + "\"clusterCompatibility\": 1,\n" + + "\"clusterMembership\": \"active\"\n," + + "\"couchApiBase\": \"http://10.2.1.67:5984/\"\n" + + "}\n" + + "],\n" + + "\"vBucketServerMap\": \n" + + "{\n" + + " \"hashAlgorithm\": \"CRC\",\n" + + " \"numReplicas\": 0,\n" + + " \"serverList\": [\"127.0.0.1:11211\", \"127.0.0.1:11210\"],\n" + + " \"vBucketMap\":\n" + " [\n" + " [-1],\n" + + " [-1],\n" + " [0],\n" + " [0]\n" + + " ]\n" + "}" + "}"; + public void testGetPrimary() { MemcachedNode node1 = createMock(MemcachedNode.class); MemcachedNode node2 = createMock(MemcachedNode.class); @@ -104,4 +122,27 @@ public void testGetAlternative() { locator.getAlternative("k1", Arrays.asList(primary)); alternative.getSocketAddress(); } + + @Test + public void testNoMasterServerForVbucket() { + MemcachedNodeMockImpl node1 = new MemcachedNodeMockImpl(); + MemcachedNodeMockImpl node2 = new MemcachedNodeMockImpl(); + node1.setSocketAddress(new InetSocketAddress("127.0.0.1", 11211)); + node2.setSocketAddress(new InetSocketAddress("127.0.0.1", 11210)); + + ConfigFactory configFactory = new DefaultConfigFactory(); + Config config = configFactory.create(NO_REPLICA_CONFIG_IN_ENVELOPE); + + VBucketNodeLocator locator = new VBucketNodeLocator( + Arrays.asList((MemcachedNode) node1, node2), + config); + + boolean success = false; + try { + MemcachedNode primary = locator.getPrimary("key1"); + } catch(RuntimeException e) { + success = true; + } + assertTrue("No RuntimeException thrown when vbucket master is -1", success); + } }