Skip to content
Merged
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
13 changes: 9 additions & 4 deletions src/main/java/net/spy/memcached/ArcusKetamaNodeLocator.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,10 @@ private void removeHash(MemcachedNode node) {
for (int h = 0; h < 4; h++) {
Long k = getKetamaHashPoint(digest, h);
SortedSet<MemcachedNode> nodeSet = ketamaNodes.get(k);
assert nodeSet != null;
if (nodeSet == null) {
// The hash point is duplicated in the node itself and already removed.
continue;
}
nodeSet.remove(node);
if (nodeSet.isEmpty()) {
ketamaNodes.remove(k);
Expand Down Expand Up @@ -384,12 +387,14 @@ private void removeHashOfAlter(MemcachedNode node) {
}
} else {
nodeSet = ketamaNodes.get(k);
assert nodeSet != null;
boolean removed = nodeSet.remove(node);
if (nodeSet == null) {
// The hash point is duplicated in the node itself and already removed.
continue;
}
nodeSet.remove(node);
if (nodeSet.isEmpty()) {
ketamaNodes.remove(k);
}
assert removed;
}
}
}
Expand Down
71 changes: 71 additions & 0 deletions src/test/java/net/spy/memcached/ArcusKetamaHashingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
Expand All @@ -13,6 +15,7 @@
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ArcusKetamaHashingTest {
Expand Down Expand Up @@ -60,6 +63,74 @@ void testHashCollision() {
runThisManyNodes(stringNode1, stringNode2);
}

@Test
void testRemoveNodeWithDuplicateHashPointInSelf() {
/* "127.0.7.1:12932" has a duplicate hash point in its own hash points. */
List<MemcachedNode> nodes = createNodes(
AddrUtil.getAddresses(Arrays.asList("127.0.0.1:11211", "127.0.0.2:11211")));
MemcachedNode dupNode = new MockMemcachedNode(
new InetSocketAddress("127.0.7.1", 12932));

ArcusKetamaNodeLocator locator =
new ArcusKetamaNodeLocator(nodes, new ArcusKetamaNodeLocatorConfiguration());
locator.update(Collections.singletonList(dupNode),
Collections.<MemcachedNode>emptyList());
assertTrue(locator.getAll().contains(dupNode));

locator.update(Collections.<MemcachedNode>emptyList(),
Collections.singletonList(dupNode));
assertFalse(locator.getAll().contains(dupNode));
assertNoHashPointOf(locator, dupNode);
}

@Test
void testRemoveJoiningAlterNodeWithDuplicateHashPointInSelf() {
/* "127.0.7.1:12932" has a duplicate hash point in its own hash points. */
List<MemcachedNode> nodes = createNodes(
AddrUtil.getAddresses(Arrays.asList("127.0.0.1:11211", "127.0.0.2:11211")));
MemcachedNode dupNode = new MockMemcachedNode(
new InetSocketAddress("127.0.7.1", 12932));

ArcusKetamaNodeLocator locator =
new ArcusKetamaNodeLocator(nodes, new ArcusKetamaNodeLocatorConfiguration());
locator.prepareMigration(Collections.singletonList(dupNode), MigrationType.JOIN);
assertTrue(locator.getAlterAll().contains(dupNode));

locator.updateAlter(Collections.<MemcachedNode>emptyList(),
Collections.singletonList(dupNode));
assertTrue(locator.getAlterAll().isEmpty());
assertNoHashPointOf(locator, dupNode);
}

@Test
void testRemoveLeavingAlterNodeWithDuplicateHashPointInSelf() {
/* "127.0.7.1:12932" has a duplicate hash point in its own hash points. */
List<MemcachedNode> nodes = createNodes(
AddrUtil.getAddresses(Arrays.asList("127.0.0.1:11211", "127.0.0.2:11211")));
MemcachedNode dupNode = new MockMemcachedNode(
new InetSocketAddress("127.0.7.1", 12932));

ArcusKetamaNodeLocator locator =
new ArcusKetamaNodeLocator(nodes, new ArcusKetamaNodeLocatorConfiguration());
locator.update(Collections.singletonList(dupNode),
Collections.<MemcachedNode>emptyList());
locator.prepareMigration(Collections.singletonList(dupNode), MigrationType.LEAVE);
assertTrue(locator.getAlterAll().contains(dupNode));

locator.updateAlter(Collections.<MemcachedNode>emptyList(),
Collections.singletonList(dupNode));
assertTrue(locator.getAlterAll().isEmpty());
assertNoHashPointOf(locator, dupNode);
}

private void assertNoHashPointOf(ArcusKetamaNodeLocator locator, MemcachedNode target) {
for (SortedSet<MemcachedNode> nodeSet : locator.getKetamaNodes().values()) {
for (MemcachedNode node : nodeSet) {
assertNotSame(target, node);
}
}
}

/**
* Simulate dropping from stringNode1 to stringNode2.
* Ensure hashing is consistent between the the two scenarios.
Expand Down
Loading