Added LLD projects

This commit is contained in:
Your Name
2020-07-15 18:02:38 +05:30
commit 0d2fabc962
135 changed files with 3319 additions and 0 deletions

3
service-orchestrator/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

13
service-orchestrator/.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="service-orchestrator" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

14
service-orchestrator/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
service-orchestrator/.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
service-orchestrator/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>service-orchestrator</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />

View File

@@ -0,0 +1,33 @@
import models.Node;
import models.Request;
import models.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class LoadBalancer {
private final Map<String, Service> services;
private final Map<String, Node> nodes;
public LoadBalancer() {
this.services = new ConcurrentHashMap<>();
this.nodes = new ConcurrentHashMap<>();
}
public void register(Service service) {
services.put(service.getId(), service);
}
public void addNode(String serviceId, Node node) {
nodes.put(node.getId(), node);
services.get(serviceId).getRouter().addNode(node);
}
public void removeNode(String serviceId, String nodeId) {
services.get(serviceId).getRouter().removeNode(nodes.remove(nodeId));
}
public Node getHandler(Request request) {
return services.get(request.getServiceId()).getRouter().getAssignedNode(request);
}
}

View File

@@ -0,0 +1,57 @@
package algorithms;
import models.Node;
import models.Request;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
public class ConsistentHashing implements Router {
private final Map<Node, List<Long>> nodePositions;
private final ConcurrentSkipListMap<Long, Node> nodeMappings;
private final Function<String, Long> hashFunction;
private final int pointMultiplier;
public ConsistentHashing(final Function<String, Long> hashFunction,
final int pointMultiplier) {
if (pointMultiplier == 0) {
throw new IllegalArgumentException();
}
this.pointMultiplier = pointMultiplier;
this.hashFunction = hashFunction;
this.nodePositions = new ConcurrentHashMap<>();
this.nodeMappings = new ConcurrentSkipListMap<>();
}
public void addNode(Node node) {
nodePositions.put(node, new CopyOnWriteArrayList<>());
for (int i = 0; i < pointMultiplier; i++) {
for (int j = 0; j < node.getWeight(); j++) {
final var point = hashFunction.apply((i * pointMultiplier + j) + node.getId());
nodePositions.get(node).add(point);
nodeMappings.put(point, node);
}
}
}
public void removeNode(Node node) {
for (final Long point : nodePositions.remove(node)) {
nodeMappings.remove(point);
}
}
public Node getAssignedNode(Request request) {
final var key = hashFunction.apply(request.getId());
final var entry = nodeMappings.higherEntry(key);
if (entry == null) {
return nodeMappings.firstEntry().getValue();
} else {
return entry.getValue();
}
}
}

View File

@@ -0,0 +1,12 @@
package algorithms;
import models.Node;
import models.Request;
public interface Router {
void addNode(Node node);
void removeNode(Node node);
Node getAssignedNode(Request request);
}

View File

@@ -0,0 +1,47 @@
package algorithms;
import models.Node;
import models.Request;
import java.util.ArrayList;
import java.util.List;
public class WeightedRoundRobin implements Router {
private final List<Node> nodes;
private int assignTo;
private int currentNodeAssignments;
private final Object lock;
public WeightedRoundRobin() {
this.nodes = new ArrayList<>();
this.assignTo = 0;
this.lock = new Object();
}
public void addNode(Node node) {
synchronized (this.lock) {
nodes.add(node);
}
}
public void removeNode(Node node) {
synchronized (this.lock) {
nodes.remove(node);
assignTo--;
currentNodeAssignments = 0;
}
}
public Node getAssignedNode(Request request) {
synchronized (this.lock) {
assignTo = assignTo % nodes.size();
final var currentNode = nodes.get(assignTo);
currentNodeAssignments++;
if (currentNodeAssignments == currentNode.getWeight()) {
assignTo++;
currentNodeAssignments = 0;
}
return currentNode;
}
}
}

View File

@@ -0,0 +1,45 @@
package models;
import java.util.Objects;
public class Node {
private final String id;
private final int weight;
private final String ipAddress;
public Node(String id, String ipAddress) {
this(id, ipAddress, 1);
}
public Node(String id, String ipAddress, int weight) {
this.id = id;
this.weight = weight;
this.ipAddress = ipAddress;
}
public String getId() {
return id;
}
public int getWeight() {
return weight;
}
public String getIpAddress() {
return ipAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
return id.equals(node.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,26 @@
package models;
public class Request {
private final String id;
private final String serviceId;
private final String method;
public Request(String id, String serviceId, String method) {
this.id = id;
this.serviceId = serviceId;
this.method = method;
}
public String getId() {
return id;
}
public String getServiceId() {
return serviceId;
}
public String getMethod() {
return method;
}
}

View File

@@ -0,0 +1,27 @@
package models;
import algorithms.Router;
public class Service {
private final Router router;
private final String id;
private final String[] methods;
public Service(String id, Router router, String[] methods) {
this.router = router;
this.id = id;
this.methods = methods;
}
public Router getRouter() {
return router;
}
public String getId() {
return id;
}
public String[] getMethods() {
return methods;
}
}

View File

@@ -0,0 +1,70 @@
import algorithms.ConsistentHashing;
import algorithms.WeightedRoundRobin;
import models.Node;
import models.Request;
import models.Service;
import org.junit.Assert;
import org.junit.Test;
public class LBTester {
@Test
public void LBDefaultBehaviour() {
LoadBalancer loadBalancer = new LoadBalancer();
final var consistentHashing = new ConsistentHashing(point -> (long) Math.abs(point.hashCode()) % 100, 1);
final String profileServiceId = "profile", smsServiceId = "sms", emailServiceId = "email";
loadBalancer.register(new Service(profileServiceId, consistentHashing, new String[]{"addProfile", "deleteProfile", "updateProfile"}));
loadBalancer.register(new Service(smsServiceId, new WeightedRoundRobin(), new String[]{"sendSms", "addTemplate", "getSMSForUser"}));
loadBalancer.register(new Service(emailServiceId, new WeightedRoundRobin(), new String[]{"sendEmail", "addTemplate", "getSMSForUser"}));
final Node pNode1 = new Node("51", "35.45.55.65", 2), pNode2 = new Node("22", "35.45.55.66", 3);
loadBalancer.addNode(profileServiceId, pNode1);
loadBalancer.addNode(profileServiceId, pNode2);
final Node sNode1 = new Node("13", "35.45.55.67"), sNode2 = new Node("64", "35.45.55.68");
loadBalancer.addNode(smsServiceId, sNode1);
loadBalancer.addNode(smsServiceId, sNode2);
final Node eNode1 = new Node("node-35", "35.45.55.69", 2), eNode2 = new Node("node-76", "35.45.55.70");
loadBalancer.addNode(emailServiceId, eNode1);
loadBalancer.addNode(emailServiceId, eNode2);
var profileNode1 = loadBalancer.getHandler(new Request("r-123", profileServiceId, "addProfile"));
var profileNode2 = loadBalancer.getHandler(new Request("r-244", profileServiceId, "addProfile"));
var profileNode3 = loadBalancer.getHandler(new Request("r-659", profileServiceId, "addProfile"));
var profileNode4 = loadBalancer.getHandler(new Request("r-73", profileServiceId, "addProfile"));
Assert.assertEquals(pNode1, profileNode1);
Assert.assertEquals(pNode1, profileNode2);
Assert.assertEquals(pNode2, profileNode3);
Assert.assertEquals(pNode1, profileNode4);
loadBalancer.removeNode(profileServiceId, pNode1.getId());
profileNode1 = loadBalancer.getHandler(new Request("r-123", profileServiceId, "addProfile"));
profileNode2 = loadBalancer.getHandler(new Request("r-244", profileServiceId, "addProfile"));
profileNode3 = loadBalancer.getHandler(new Request("r-659", profileServiceId, "addProfile"));
profileNode4 = loadBalancer.getHandler(new Request("r-73", profileServiceId, "addProfile"));
Assert.assertEquals(pNode2, profileNode1);
Assert.assertEquals(pNode2, profileNode2);
Assert.assertEquals(pNode2, profileNode3);
Assert.assertEquals(pNode2, profileNode4);
final var smsNode1 = loadBalancer.getHandler(new Request("r-124", smsServiceId, "addTemplate"));
final var smsNode2 = loadBalancer.getHandler(new Request("r-1214", smsServiceId, "addTemplate"));
final var smsNode3 = loadBalancer.getHandler(new Request("r-4", smsServiceId, "addTemplate"));
Assert.assertEquals(sNode1, smsNode1);
Assert.assertEquals(sNode2, smsNode2);
Assert.assertEquals(sNode1, smsNode3);
final var emailNode1 = loadBalancer.getHandler(new Request("r-1232", emailServiceId, "addTemplate"));
final var emailNode2 = loadBalancer.getHandler(new Request("r-4134", emailServiceId, "addTemplate"));
final var emailNode3 = loadBalancer.getHandler(new Request("r-23432", emailServiceId, "addTemplate"));
final var emailNode4 = loadBalancer.getHandler(new Request("r-5345", emailServiceId, "addTemplate"));
Assert.assertEquals(eNode1, emailNode1);
Assert.assertEquals(eNode1, emailNode2);
Assert.assertEquals(eNode2, emailNode3);
Assert.assertEquals(eNode1, emailNode4);
}
}

View File

@@ -0,0 +1,140 @@
import algorithms.ConsistentHashing;
import algorithms.Router;
import algorithms.WeightedRoundRobin;
import models.Node;
import models.Request;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class RouterTester {
String ipAddress = "127.0.0.1", serviceId = "service", method = "method";
@Test
public void defaultRoundRobin() {
final Router router = new WeightedRoundRobin();
final Node node1 = newNode("node-1"), node2 = newNode("node-2"), node3 = newNode("node-3");
router.addNode(node1);
router.addNode(node2);
router.addNode(node3);
Assert.assertEquals(node1, router.getAssignedNode(newRequest("r-123")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-124")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-125")));
router.removeNode(node1);
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-125")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-126")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-127")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-128")));
final Node node4 = new Node("node-4", ipAddress, 2);
router.addNode(node4);
Assert.assertEquals(node4, router.getAssignedNode(newRequest("r-129")));
Assert.assertEquals(node4, router.getAssignedNode(newRequest("r-130")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-131")));
}
@Test
public void defaultConsistentHashing() {
final List<Long> hashes = new ArrayList<>();
hashes.add(1L);
hashes.add(11L);
hashes.add(21L);
hashes.add(31L);
final Function<String, Long> hashFunction = id -> {
if (id.contains("000000")) {
return hashes.remove(0);
} else {
return Long.parseLong(id);
}
};
final Router router = new ConsistentHashing(hashFunction, 1);
final Node node1 = newNode("1000000"), node2 = newNode("2000000"), node3 = newNode("3000000");
router.addNode(node1);
router.addNode(node2);
router.addNode(node3);
Assert.assertEquals(node1, router.getAssignedNode(newRequest("35")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("5")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("15")));
router.removeNode(node1);
Assert.assertEquals(node2, router.getAssignedNode(newRequest("22")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("12")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("23")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("13")));
final Node node4 = newNode("4000000");
router.addNode(node4);
Assert.assertEquals(node4, router.getAssignedNode(newRequest("25")));
}
@Test(expected = IllegalArgumentException.class)
public void consistentHashingConstruction() {
new ConsistentHashing(Long::valueOf, 0);
}
@Test
public void consistentHashingWithWeights() {
final List<Long> hashes = new ArrayList<>();
hashes.add(1L); // remaining is node 1
hashes.add(21L); // 12 to 21 is for node 1
hashes.add(11L); // 2 to 11 is for node 2
hashes.add(41L); // 32 to 41 is for node 2
hashes.add(31L); // 22 to 31 is for node 3
hashes.add(51L); // 42 to 51 is for node 3 --> 10 points
final Function<String, Long> hashFunction = id -> {
//range should be (0, 60)
if (id.contains("000000")) {
return hashes.remove(0);
} else {
return Long.parseLong(id);
}
};
final Router router = new ConsistentHashing(hashFunction, 2);
final Node node1 = newNode("1000000"), node2 = newNode("2000000"), node3 = newNode("3000000");
router.addNode(node1);
router.addNode(node2);
router.addNode(node3);
Assert.assertEquals(node1, router.getAssignedNode(newRequest("55")));
Assert.assertEquals(node1, router.getAssignedNode(newRequest("15")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("8")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("33")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("28")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("47")));
router.removeNode(node1);
// remaining is node 2
// 12 to 21 is now for node 3
Assert.assertEquals(node2, router.getAssignedNode(newRequest("58")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("12")));
Assert.assertEquals(node3, router.getAssignedNode(newRequest("23")));
Assert.assertEquals(node2, router.getAssignedNode(newRequest("54")));
final Node node4 = newNode("4000000");
hashes.add(6L); // 0 to 6 is for node 4, 52 to remaining is for node 4
hashes.add(26L); // 12 to 26 is for node 4
router.addNode(node4);
Assert.assertEquals(node4, router.getAssignedNode(newRequest("15")));
Assert.assertEquals(node4, router.getAssignedNode(newRequest("59")));
Assert.assertEquals(node4, router.getAssignedNode(newRequest("5")));
}
private Request newRequest(String s) {
return new Request(s, serviceId, method);
}
private Node newNode(String s) {
return new Node(s, ipAddress);
}
}

Binary file not shown.

Binary file not shown.