Permalink
Browse files

Merge branch 'master' of https://github.com/catrope/netcomp

  • Loading branch information...
2 parents f64c433 + c2f69e1 commit d74a74099fe0f29fae9672f20b70f36dd1ca5553 @roy-t roy-t committed Apr 11, 2011
Showing with 251 additions and 0 deletions.
  1. +6 −0 BasicCache.java
  2. +32 −0 CacheServer.java
  3. +86 −0 HashBalancer.java
  4. +22 −0 HashBalancerTest.java
  5. +5 −0 ICache.java
  6. +44 −0 Main.java
  7. +55 −0 RemoteCache.java
  8. +1 −0 StubCache.java
View
@@ -32,6 +32,12 @@ public BasicCache()
this(50);
}
+ public void clear()
+ {
+ map.clear();
+ list.clear();
+ }
+
public String get(String key)
{
// retrieve the value from the map
View
@@ -0,0 +1,32 @@
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ * RMI wrapper for a cache server
+ */
+public class CacheServer extends UnicastRemoteObject implements ICache
+{
+ private static final long serialVersionUID = 1L;
+
+ final ICache localCache;
+
+ public CacheServer(ICache localCache) throws RemoteException
+ {
+ this.localCache = localCache;
+ }
+
+ public void clear()
+ {
+ localCache.clear();
+ }
+
+ public String get(String key)
+ {
+ return localCache.get(key);
+ }
+
+ public void set(String key, String val)
+ {
+ localCache.set(key, val);
+ }
+}
View
@@ -0,0 +1,86 @@
+import java.math.BigInteger;
+import java.security.*;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.Vector;
+
+/**
+ * Manages a set of caching servers and load balances them using key hashing
+ * @author Roan Kattouw
+ */
+public class HashBalancer {
+ protected Vector<String> servers;
+
+ /**
+ * Constructor
+ * @param servers Vector of server names
+ */
+ public HashBalancer(Vector<String> servers) {
+ this.servers = new Vector<String>(servers);
+ }
+
+ /**
+ * Constructor
+ * @param servers Array of server names
+ */
+ public HashBalancer(String[] servers) {
+ this.servers = new Vector<String>(Arrays.asList(servers));
+ }
+
+ /**
+ * Get a list of all servers managed by this object
+ * @return Vector of server names
+ */
+ public Vector<String> getServers() {
+ return servers;
+ }
+
+ /**
+ * Get the number of servers managed by this object.
+ */
+ public int getNumberOfServers() {
+ return servers.size();
+ }
+
+ /**
+ * Add a server to be managed by this object
+ * @param srv Server name
+ */
+ public void addServer(String srv) {
+ servers.add(srv);
+ }
+
+ /**
+ * Remove a server from this object
+ * @param srv Server name
+ */
+ public void removeServer(String srv) {
+ servers.remove(srv);
+ }
+
+ /**
+ * Find out which server should have a given key. This is the
+ * hash-based load balancing part
+ * @param key Cache key
+ * @return Server name
+ */
+ public String getServerForKey(String key) {
+ return servers.get(getIndexForKey(key));
+ }
+
+ protected int getIndexForKey(String key) {
+ try {
+ byte[] byteArr = key.getBytes("UTF-8");
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] hash = md.digest(byteArr);
+ BigInteger h = new BigInteger(1, hash);
+ return h.mod(BigInteger.valueOf(servers.size())).intValue();
+ } catch(Exception e) {
+ // Java throws some stupid exceptions in case UTF-8 or MD5
+ // aren't supported. This is never realistically gonna happen,
+ // but just in case let's use a randomized balancer in that case.
+ Random generator = new Random();
+ return generator.nextInt(servers.size());
+ }
+ }
+}
View
@@ -0,0 +1,22 @@
+import junit.framework.TestCase;
+
+
+public class HashBalancerTest extends TestCase {
+
+ public void testGetIndexForKey() {
+ // Use 16 servers, so the server name is equal to
+ // the final hex digit of the MD5 hash of the key
+ String[] servers = {"0", "1", "2", "3", "4", "5", "6",
+ "7", "8", "9", "a", "b", "c", "d", "e", "f"
+ };
+
+ HashBalancer hb = new HashBalancer(servers);
+ assertEquals("8", hb.getServerForKey("foo"));
+ assertEquals("2", hb.getServerForKey("bar"));
+ assertEquals("8", hb.getServerForKey("baz"));
+ assertEquals("e", hb.getServerForKey("Roan"));
+ assertEquals("f", hb.getServerForKey("Jan Paul"));
+ assertEquals("8", hb.getServerForKey("Roy"));
+ }
+
+}
View
@@ -14,4 +14,9 @@
* Store a string in the cache.
*/
public void set(String key, String val);
+
+ /**
+ * Clear the cache.
+ */
+ public void clear();
}
View
@@ -0,0 +1,44 @@
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+import java.util.Vector;
+
+public class Main
+{
+ ICache cache;
+
+ /**
+ * Init using "java Main configfile.txt serverId cacheSize"
+ * where configfile.txt is a newline separated list of RMI
+ * paths, serverId is an integer that denotes the current
+ * instance (by referring to a line in configfile.txt) and
+ * cacheSize is the size of the local cache.
+ *
+ * If anything fails, a basic cache is used that doesn't use
+ * RMI.
+ */
+ public Main(String[] args)
+ {
+ try {
+ Scanner scanner = new Scanner(new FileInputStream(args[1]));
+ Vector<String> serverNames = new Vector<String>();
+
+ while (scanner.hasNextLine()) {
+ serverNames.add(scanner.nextLine());
+ }
+
+ cache = new RemoteCache((String[])serverNames.toArray(), Integer.parseInt(args[2]), new BasicCache(Integer.parseInt(args[3])));
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("Using basic cache...");
+ cache = new BasicCache();
+ }
+
+ // TODO: instantiate HTTP server
+ }
+
+ public static void main(String[] args)
+ {
+ new Main(args);
+ }
+}
View
@@ -0,0 +1,55 @@
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.RemoteException;
+
+public class RemoteCache implements ICache
+{
+ CacheServer cache;
+ HashBalancer hb;
+
+ public RemoteCache(String[] serverNames, int localId, ICache localCache)
+ {
+ try {
+ cache = new CacheServer(localCache);
+ Naming.rebind(serverNames[localId], cache);
+ hb = new HashBalancer(serverNames);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void clear()
+ {
+ for (String server : hb.getServers())
+ {
+ try {
+ ((ICache)Naming.lookup(server)).clear();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public String get(String key)
+ {
+ return getCacheServer(key).get(key);
+ }
+
+ public void set(String key, String val)
+ {
+ getCacheServer(key).set(key, val);
+ }
+
+ private ICache getCacheServer(String key)
+ {
+ try {
+ return (ICache)Naming.lookup(hb.getServerForKey(key));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
View
@@ -5,4 +5,5 @@
{
public String get(String key) { return null; }
public void set(String key, String val) {}
+ public void clear() {}
}

0 comments on commit d74a740

Please sign in to comment.