Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/catrope/netcomp
Browse files Browse the repository at this point in the history
  • Loading branch information
roy-t committed Apr 11, 2011
2 parents f64c433 + c2f69e1 commit d74a740
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 0 deletions.
6 changes: 6 additions & 0 deletions BasicCache.java
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions CacheServer.java
@@ -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);
}
}
86 changes: 86 additions & 0 deletions HashBalancer.java
@@ -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());
}
}
}
22 changes: 22 additions & 0 deletions HashBalancerTest.java
@@ -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"));
}

}
5 changes: 5 additions & 0 deletions ICache.java
Expand Up @@ -14,4 +14,9 @@ public interface ICache
* Store a string in the cache.
*/
public void set(String key, String val);

/**
* Clear the cache.
*/
public void clear();
}
44 changes: 44 additions & 0 deletions Main.java
@@ -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);
}
}
55 changes: 55 additions & 0 deletions RemoteCache.java
@@ -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;
}
}
1 change: 1 addition & 0 deletions StubCache.java
Expand Up @@ -5,4 +5,5 @@ public class StubCache implements ICache
{
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.