Offline support added
authorAli Younis <ayounis@uci.edu>
Sun, 1 Jan 2017 22:12:10 +0000 (14:12 -0800)
committerAli Younis <ayounis@uci.edu>
Sun, 1 Jan 2017 22:12:10 +0000 (14:12 -0800)
version2/src/java/iotcloud/CloudComm.java
version2/src/java/iotcloud/PendingTransaction.java
version2/src/java/iotcloud/Table.java
version2/src/java/iotcloud/Test.java

index 2db5ad988ecf04f96c0154eef7ab7b7c722b58bd..5ee249d18776a144d5fbc3ee32df8d08b32e3565 100644 (file)
@@ -22,20 +22,19 @@ class CloudComm {
        String password;
        SecureRandom random;
        static final int SALT_SIZE = 8;
+       static final int TIMEOUT_MILLIS = 100;
        byte salt[];
        Table table;
 
        /**
         * Empty Constructor needed for child class.
         */
-
        CloudComm() {
        }
 
        /**
         * Constructor for actual use. Takes in the url and password.
         */
-
        CloudComm(Table _table, String _baseurl, String _password) {
                this.table = _table;
                this.baseurl = _baseurl;
@@ -46,7 +45,6 @@ class CloudComm {
        /**
         * Generates Key from password.
         */
-
        private SecretKeySpec initKey() {
                try {
                        PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
@@ -61,7 +59,6 @@ class CloudComm {
        /**
         * Inits the HMAC generator.
         */
-
        private void initCrypt() {
                try {
                        SecretKeySpec key = initKey();
@@ -81,7 +78,6 @@ class CloudComm {
        /*
         * Builds the URL for the given request.
         */
-
        private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException {
                String reqstring = isput ? "req=putslot" : "req=getslot";
                String urlstr = baseurl + "?" + reqstring + "&seq=" + sequencenumber;
@@ -90,25 +86,28 @@ class CloudComm {
                return new URL(urlstr);
        }
 
-       public void setSalt() throws ServerException{
+       public void setSalt() throws ServerException {
                try {
-                       salt = new byte[SALT_SIZE];
-                       random.nextBytes(salt);
+                       byte[] saltTmp = new byte[SALT_SIZE];
+                       random.nextBytes(saltTmp);
                        URL url = new URL(baseurl + "?req=setsalt");
                        URLConnection con = url.openConnection();
                        HttpURLConnection http = (HttpURLConnection) con;
                        http.setRequestMethod("POST");
-                       http.setFixedLengthStreamingMode(salt.length);
+                       http.setFixedLengthStreamingMode(saltTmp.length);
                        http.setDoOutput(true);
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
                        http.connect();
                        OutputStream os = http.getOutputStream();
-                       os.write(salt);
+                       os.write(saltTmp);
                        int responsecode = http.getResponseCode();
                        if (responsecode != HttpURLConnection.HTTP_OK) {
                                // TODO: Remove this print
                                // System.out.println(responsecode);
                                throw new Error("Invalid response");
                        }
+
+                       salt = saltTmp;
                } catch (Exception e) {
                        e.printStackTrace();
                        throw new ServerException("Failed setting salt");
@@ -137,7 +136,7 @@ class CloudComm {
         * numbers.
         */
 
-       Slot[] putSlot(Slot slot, int max)  throws ServerException{
+       Slot[] putSlot(Slot slot, int max) throws ServerException {
                try {
                        if (salt == null) {
                                getSalt();
@@ -148,6 +147,7 @@ class CloudComm {
                        byte[] bytes = slot.encode(mac);
                        bytes = encryptCipher.doFinal(bytes);
 
+
                        URL url = buildRequest(true, sequencenumber, max);
                        URLConnection con = url.openConnection();
                        HttpURLConnection http = (HttpURLConnection) con;
@@ -155,23 +155,28 @@ class CloudComm {
                        http.setRequestMethod("POST");
                        http.setFixedLengthStreamingMode(bytes.length);
                        http.setDoOutput(true);
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+                       // http.setReadTimeout(TIMEOUT_MILLIS);
                        http.connect();
 
                        OutputStream os = http.getOutputStream();
                        os.write(bytes);
+                       os.flush();
+
 
                        InputStream is = http.getInputStream();
                        DataInputStream dis = new DataInputStream(is);
                        byte[] resptype = new byte[7];
                        dis.readFully(resptype);
+
                        if (Arrays.equals(resptype, "getslot".getBytes()))
                                return processSlots(dis);
                        else if (Arrays.equals(resptype, "putslot".getBytes()))
                                return null;
                        else
                                throw new Error("Bad response to putslot");
+
                } catch (Exception e) {
-                       e.printStackTrace();
                        throw new ServerException("putSlot failed");
                }
        }
@@ -181,7 +186,6 @@ class CloudComm {
         * Request the server to send all slots with the given
         * sequencenumber or newer.
         */
-
        Slot[] getSlots(long sequencenumber) throws ServerException {
                try {
                        if (salt == null) {
@@ -193,11 +197,19 @@ class CloudComm {
                        URLConnection con = url.openConnection();
                        HttpURLConnection http = (HttpURLConnection) con;
                        http.setRequestMethod("POST");
+                       http.setConnectTimeout(TIMEOUT_MILLIS);
+                       // http.setReadTimeout(TIMEOUT_MILLIS);
                        http.connect();
                        InputStream is = http.getInputStream();
-
                        DataInputStream dis = new DataInputStream(is);
 
+                       int responsecode = http.getResponseCode();
+                       if (responsecode != HttpURLConnection.HTTP_OK) {
+                               // TODO: Remove this print
+                               // System.out.println("Code:  " + responsecode);
+                               throw new ServerException("getSlots failed");
+                       }
+
                        byte[] resptype = new byte[7];
                        dis.readFully(resptype);
                        if (!Arrays.equals(resptype, "getslot".getBytes()))
@@ -205,7 +217,7 @@ class CloudComm {
                        else
                                return processSlots(dis);
                } catch (Exception e) {
-                       e.printStackTrace();
+                       // e.printStackTrace();
                        throw new ServerException("getSlots failed");
                }
        }
@@ -214,7 +226,6 @@ class CloudComm {
         * Method that actually handles building Slot objects from the
         * server response.  Shared by both putSlot and getSlots.
         */
-
        private Slot[] processSlots(DataInputStream dis) throws Exception {
                int numberofslots = dis.readInt();
                int[] sizesofslots = new int[numberofslots];
index f80845f99852cbb4445af726978edb7ca1630ea3..578f1eb01212a5cdbce2a3d2c724ee384bcf4ec4 100644 (file)
@@ -1,6 +1,7 @@
 package iotcloud;
 
 import java.util.Set;
+import java.util.Map;
 import java.util.HashSet;
 
 import javax.script.ScriptException;
@@ -92,4 +93,37 @@ class PendingTransaction {
     public Set<KeyValue> getKVGuard() {
         return keyValueGuardSet;
     }
+
+    public boolean evaluateGuard(Map<IoTString, KeyValue> keyValTableCommitted, Map<IoTString, KeyValue> keyValTableSpeculative, Map<IoTString, KeyValue> keyValTablePendingTransSpeculative) {
+        for (KeyValue kvGuard : keyValueGuardSet) {
+
+            // First check if the key is in the speculative table, this is the value of the latest assumption
+            KeyValue kv = keyValTablePendingTransSpeculative.get(kvGuard.getKey());
+
+
+            if (kv == null) {
+                // if it is not in the pending trans table then check the speculative table and use that
+                // value as our latest assumption
+                kv = keyValTableSpeculative.get(kvGuard.getKey());
+            }
+
+
+            if (kv == null) {
+                // if it is not in the speculative table then check the committed table and use that
+                // value as our latest assumption
+                kv = keyValTableCommitted.get(kvGuard.getKey());
+            }
+
+            if (kvGuard.getValue() != null) {
+                if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
+                    return false;
+                }
+            } else {
+                if (kv != null) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }
\ No newline at end of file
index 4f0fe9551e1f817ed87f18dfe9dbb1ef6949e8f4..6aeb28e3628c57f611e56921717e83f924bad66a 100644 (file)
@@ -51,9 +51,10 @@ final public class Table {
 
        private int smallestTableStatusSeen = -1;
        private int largestTableStatusSeen = -1;
+       private int lastSeenPendingTransactionSpeculateIndex = 0;
 
        private PendingTransaction pendingTransBuild = null; // Pending Transaction used in building
-       private Queue<PendingTransaction> pendingTransQueue = null; // Queue of pending transactions
+       private LinkedList<PendingTransaction> pendingTransQueue = null; // Queue of pending transactions
        private Map<Long, Commit> commitMap = null; // List of all the most recent live commits
        private Map<Long, Abort> abortMap = null; // Set of the live aborts
        private Map<IoTString, Commit> committedMapByKey = null; // Table of committed KV
@@ -65,6 +66,7 @@ final public class Table {
        private Map<Long, Commit> newCommitMap = null; // Map of all the new commits
        private Map<Long, Long> lastCommitSeenSeqNumMap = null; // sequence number of the last commit that was seen grouped by arbitrator
        private Map<Long, Long> lastAbortSeenSeqNumMap = null; // sequence number of the last commit that was seen grouped by arbitrator
+       private Map<IoTString, KeyValue> pendingTransSpeculativeTable = null;
 
 
 
@@ -104,6 +106,7 @@ final public class Table {
                newCommitMap = new HashMap<Long, Commit>();
                lastCommitSeenSeqNumMap = new HashMap<Long, Long>();
                lastAbortSeenSeqNumMap = new HashMap<Long, Long>();
+               pendingTransSpeculativeTable = new HashMap<IoTString, KeyValue>();
        }
 
        public void rebuild() throws ServerException {
@@ -161,7 +164,16 @@ final public class Table {
        }
 
        public IoTString getSpeculative(IoTString key) {
-               KeyValue kv = speculativeTable.get(key);
+               KeyValue kv = pendingTransSpeculativeTable.get(key);
+
+               if (kv == null) {
+                       kv = speculativeTable.get(key);
+               }
+
+               if (kv == null) {
+                       kv = commitedTable.get(key);
+               }
+
                if (kv != null) {
                        return kv.getValue();
                } else {
@@ -203,7 +215,12 @@ final public class Table {
                        throw new Error("Not all Key Values Match Arbitrator.");
                }
 
-               KeyValue kv = speculativeTable.get(key);
+               KeyValue kv = pendingTransSpeculativeTable.get(key);
+
+               if (kv == null) {
+                       kv = speculativeTable.get(key);
+               }
+
                if (kv == null) {
                        kv = commitedTable.get(key);
                }
@@ -265,6 +282,21 @@ final public class Table {
                // Add the pending transaction to the queue
                pendingTransQueue.add(pendingTransBuild);
 
+               for (int i = lastSeenPendingTransactionSpeculateIndex; i < pendingTransQueue.size(); i++) {
+                       PendingTransaction pt = pendingTransQueue.get(i);
+
+                       if (pt.evaluateGuard(commitedTable, speculativeTable, pendingTransSpeculativeTable)) {
+
+                               lastSeenPendingTransactionSpeculateIndex = i;
+
+                               for (KeyValue kv : pt.getKVUpdates()) {
+                                       pendingTransSpeculativeTable.put(kv.getKey(), kv);
+                               }
+
+                       }
+               }
+
+
                // Delete since already inserted
                pendingTransBuild = new PendingTransaction();
 
@@ -291,14 +323,13 @@ final public class Table {
                pendingTransBuild.addKV(kv);
        }
 
-       public void update()  throws ServerException {
-
+       public void update() throws ServerException {
                Slot[] newslots = cloud.getSlots(sequencenumber + 1);
-
                validateandupdate(newslots, false);
 
-
                if (!pendingTransQueue.isEmpty()) {
+                       System.out.println("Full Update");
+
                        // We have a pending transaction so do full insertion
 
                        while (!pendingTransQueue.isEmpty()) {
@@ -370,7 +401,7 @@ final public class Table {
                }
        }
 
-       public boolean createNewKey(IoTString keyName, long machineId)  throws ServerException {
+       public boolean createNewKey(IoTString keyName, long machineId) throws ServerException {
 
                while (true) {
                        if (arbitratorTable.get(keyName) != null) {
@@ -394,7 +425,7 @@ final public class Table {
                resizethreshold = resize_lower - 1 + random.nextInt(numslots - resize_lower);
        }
 
-       private boolean tryput(PendingTransaction pendingTrans, boolean resize)  throws ServerException {
+       private boolean tryput(PendingTransaction pendingTrans, boolean resize) throws ServerException {
                Slot s = new Slot(this, sequencenumber + 1, localmachineid, buffer.getSlot(sequencenumber).getHMAC());
 
                int newsize = 0;
@@ -439,7 +470,7 @@ final public class Table {
                return doSendSlotsAndInsert(s, insertedTrans, resize, newsize);
        }
 
-       private boolean tryput(IoTString keyName, long arbMachineid, boolean resize)  throws ServerException {
+       private boolean tryput(IoTString keyName, long arbMachineid, boolean resize) throws ServerException {
                Slot s = new Slot(this, sequencenumber + 1, localmachineid, buffer.getSlot(sequencenumber).getHMAC());
                int newsize = 0;
                if (liveslotcount > resizethreshold) {
@@ -638,18 +669,22 @@ final public class Table {
                int max = 0;
                if (resize)
                        max = newsize;
+
                Slot[] array = cloud.putSlot(s, max);
                if (array == null) {
                        array = new Slot[] {s};
                        rejectedmessagelist.clear();
                }       else {
-                       if (array.length == 0)
-                               throw new Error("Server Error: Did not send any slots");
+                       // if (array.length == 0)
+                       // throw new Error("Server Error: Did not send any slots");
                        rejectedmessagelist.add(s.getSequenceNumber());
                        inserted = false;
                }
 
-               validateandupdate(array, true);
+               if (array.length != 0) {
+                       validateandupdate(array, true);
+               }
+
                return inserted;
        }
 
@@ -699,20 +734,22 @@ final public class Table {
                sequencenumber = newslots[newslots.length - 1].getSequenceNumber();
 
                // Process all on key value pairs
-               proccessAllNewCommits();
+               boolean didCommitOrSpeculate = proccessAllNewCommits();
 
                // Go through all uncommitted transactions and kill the ones that are dead
                deleteDeadUncommittedTransactions();
 
                // Speculate on key value pairs
-               createSpeculativeTable();
+               didCommitOrSpeculate |= createSpeculativeTable();
+
+               createPendingTransactionSpeculativeTable(didCommitOrSpeculate);
        }
 
-       public void proccessAllNewCommits() {
+       public boolean proccessAllNewCommits() {
 
                // Process only if there are commit
                if (newCommitMap.keySet().size() == 0) {
-                       return;
+                       return false;
                }
 
                List<Long> commitSeqNums = new ArrayList<Long>(newCommitMap.keySet());
@@ -720,11 +757,13 @@ final public class Table {
                // Sort from oldest to newest commit
                Collections.sort(commitSeqNums);
 
+               boolean didProcessNewCommit = false;
+
                // Go through each new commit one by one
                for (Long entrySeqNum : commitSeqNums) {
                        Commit entry = newCommitMap.get(entrySeqNum);
 
-                       long lastCommitSeenSeqNum = 0;
+                       long lastCommitSeenSeqNum = -1;
 
                        if (lastCommitSeenSeqNumMap.get(entry.getTransArbitrator()) != null) {
                                lastCommitSeenSeqNum = lastCommitSeenSeqNumMap.get(entry.getTransArbitrator());
@@ -762,35 +801,10 @@ final public class Table {
                                }
                        }
 
-                       // // Remove any old commits
-                       // for (Iterator<Map.Entry<Long, Commit>> i = commitMap.entrySet().iterator(); i.hasNext();) {
-                       //      Commit prevCommit = i.next().getValue();
-                       //      prevCommit.updateLiveKeys(entry.getkeyValueUpdateSet());
-
-                       //      if (!prevCommit.isLive()) {
-                       //              i.remove();
-                       //      }
-                       // }
-
-                       // Remove any old commits
-                       // for (Iterator<Map.Entry<Long, Commit>> i = commitMap.entrySet().iterator(); i.hasNext();) {
-                       //      Commit prevCommit = i.next().getValue();
-
-                       //      if (prevCommit.getTransArbitrator() != entry.getTransArbitrator()) {
-                       //              continue;
-                       //      }
-
-                       //      prevCommit.updateLiveKeys(entry.getkeyValueUpdateSet());
-
-                       //      if (!prevCommit.isLive()) {
-                       //              i.remove();
-                       //      }
-                       // }
-
-
                        // Add the new commit
                        commitMap.put(entry.getTransSequenceNumber(), entry);
                        lastCommitSeenSeqNumMap.put(entry.getTransArbitrator(), entry.getTransSequenceNumber());
+                       didProcessNewCommit = true;
 
                        // Update the committed table list
                        for (KeyValue kv : entry.getkeyValueUpdateSet()) {
@@ -803,6 +817,8 @@ final public class Table {
 
                // Clear the new commits storage so we can use it later
                newCommitMap.clear();
+
+               return didProcessNewCommit;
        }
 
        private void deleteDeadUncommittedTransactions() {
@@ -819,11 +835,9 @@ final public class Table {
                }
        }
 
-       private void createSpeculativeTable() {
-
+       private boolean createSpeculativeTable() {
                if (uncommittedTransactionsMap.keySet().size() == 0) {
-                       //      speculativeTable = commitedTable; // Ok that they are the same object
-                       return;
+                       return false;
                }
 
                Map<IoTString, KeyValue> speculativeTableTmp = new HashMap<IoTString, KeyValue>();
@@ -872,7 +886,29 @@ final public class Table {
                        speculativeTable.put(key, speculativeTableTmp.get(key));
                }
 
-               // speculativeTable = speculativeTableTmp;
+               return true;
+       }
+
+       private void createPendingTransactionSpeculativeTable(boolean didCommitOrSpeculate) {
+
+               if (didCommitOrSpeculate) {
+                       pendingTransSpeculativeTable.clear();
+                       lastSeenPendingTransactionSpeculateIndex = 0;
+
+                       int index = 0;
+                       for (PendingTransaction pt : pendingTransQueue) {
+                               if (pt.evaluateGuard(commitedTable, speculativeTable, pendingTransSpeculativeTable)) {
+
+                                       lastSeenPendingTransactionSpeculateIndex = index;
+                                       index++;
+
+                                       for (KeyValue kv : pt.getKVUpdates()) {
+                                               pendingTransSpeculativeTable.put(kv.getKey(), kv);
+                                       }
+
+                               }
+                       }
+               }
        }
 
        private int expectedsize, currmaxsize;
@@ -1108,7 +1144,7 @@ final public class Table {
 
                if (machineid == localmachineid) {
                        if (lastmsgseqnum != seqnum && !acceptupdatestolocal)
-                               throw new Error("Server Error: Mismatch on local machine sequence number");
+                               throw new Error("Server Error: Mismatch on local machine sequence number, needed: " +  seqnum + " got: " + lastmsgseqnum);
                } else {
                        if (lastmsgseqnum > seqnum)
                                throw new Error("Server Error: Rollback on remote machine sequence number");
@@ -1163,4 +1199,4 @@ final public class Table {
                                throw new Error("Server Error: Invalid HMAC Chain" + currslot + " " + prevslot);
                }
        }
-}
+}
\ No newline at end of file
index 60f9a25e4ab4a79b3c4004b8a3360ca5ceb36c4e..cae1c398247bc7f78703070a45ddf205fd79a9f3 100644 (file)
@@ -8,7 +8,7 @@ package iotcloud;
 
 public class Test {
 
-       public static final  int NUMBER_OF_TESTS = 1000;
+       public static final  int NUMBER_OF_TESTS = 15;
 
        public static void main(String[] args)  throws ServerException {
                if (args[0].equals("2")) {
@@ -23,12 +23,11 @@ public class Test {
                        test6();
                } else if (args[0].equals("7")) {
                        test7();
+               } else if (args[0].equals("8")) {
+                       test8();
+               } else if (args[0].equals("9")) {
+                       test9();
                }
-               // else if (args[0].equals("8")) {
-               //      test8();
-               // } else if (args[0].equals("9")) {
-               //      test9();
-               // }
        }
 
        // static void test9()  throws ServerException {
@@ -673,6 +672,632 @@ public class Test {
        //      }
        // }
 
+       static void test9()  {
+
+               boolean foundError = false;
+
+               // Setup the 2 clients
+               Table t1 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+
+               while (true) {
+                       try {
+                               t1.initTable();
+                               break;
+                       } catch (Exception e) {}
+               }
+
+               Table t2 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351);
+
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {}
+               }
+
+               // Make the Keys
+               System.out.println("Setting up keys");
+               for (int i = 0; i < 4; i++) {
+                       String a = "a" + i;
+                       String b = "b" + i;
+                       String c = "c" + i;
+                       String d = "d" + i;
+                       IoTString ia = new IoTString(a);
+                       IoTString ib = new IoTString(b);
+                       IoTString ic = new IoTString(c);
+                       IoTString id = new IoTString(d);
+                       while (true) {
+                               try {
+                                       t1.createNewKey(ia, 321);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t1.createNewKey(ib, 351);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t2.createNewKey(ic, 321);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t2.createNewKey(id, 351);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+               }
+
+               // Do Updates for the keys
+               System.out.println("Setting Key-Values...");
+
+               System.out.println("Setting b...");
+               for (int t = 0; t < NUMBER_OF_TESTS; t++) {
+                       for (int i = 0; i < 4; i++) {
+                               String keyB = "b" + i;
+                               String valueB = "b" + (i + t);
+
+                               IoTString iKeyB = new IoTString(keyB);
+                               IoTString iValueB = new IoTString(valueB);
+
+                               try {
+                                       t1.startTransaction();
+                                       t1.getSpeculativeAtomic(iKeyB);
+                                       t1.addKV(iKeyB, iValueB);
+                                       t1.commitTransaction();
+                                       System.out.println("Server Success");
+                               } catch (Exception e) {
+                                       System.out.println("Server Fail");
+                               }
+
+                       }
+               }
+
+               System.out.println("Checking b");
+               for (int i = 0; i < 4; i++) {
+
+                       String keyB = "b" + i;
+                       String valueB = "b" + (i + NUMBER_OF_TESTS - 1);
+                       IoTString iKeyB = new IoTString(keyB);
+                       IoTString iValueB = new IoTString(valueB);
+
+                       IoTString testValB1 = t1.getSpeculative(iKeyB);
+                       IoTString testValB2 = t2.getSpeculative(iKeyB);
+
+                       if ((testValB1 == null) || (testValB1.equals(iValueB) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyB + "    " + testValB1);
+                               foundError = true;
+                       }
+
+                       if ((testValB2 != null)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyB + "    " + testValB2);
+                               foundError = true;
+                       }
+               }
+
+               System.out.println("Setting c...");
+               for (int t = 0; t < NUMBER_OF_TESTS; t++) {
+                       for (int i = 0; i < 4; i++) {
+                               String keyC = "c" + i;
+                               String valueC = "c" + (i + t);
+
+                               IoTString iKeyC = new IoTString(keyC);
+                               IoTString iValueC = new IoTString(valueC);
+
+                               try {
+                                       t2.startTransaction();
+                                       t2.getSpeculativeAtomic(iKeyC);
+                                       t2.addKV(iKeyC, iValueC);
+                                       t2.commitTransaction();
+                                       System.out.println("Server Success");
+                               } catch (Exception e) {
+                                       System.out.println("Server Fail");
+                               }
+
+                       }
+               }
+
+               System.out.println("Checking c");
+               for (int i = 0; i < 4; i++) {
+                       String keyC = "c" + i;
+                       String valueC = "c" + (i + NUMBER_OF_TESTS - 1);
+                       IoTString iKeyC = new IoTString(keyC);
+                       IoTString iValueC = new IoTString(valueC);
+
+                       IoTString testValC1 = t1.getSpeculative(iKeyC);
+                       IoTString testValC2 = t2.getSpeculative(iKeyC);
+
+                       if ((testValC1 != null)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyC + "   " + testValC1);
+                               foundError = true;
+                       }
+
+                       if ((testValC2 == null) || (testValC2.equals(iValueC) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyC + "   " + testValC2);
+                               foundError = true;
+                       }
+               }
+
+               System.out.println("Setting a and b...");
+               for (int t = 0; t < NUMBER_OF_TESTS; t++) {
+                       for (int i = 0; i < 4; i++) {
+                               String keyA = "a" + i;
+                               String keyD = "d" + i;
+                               String valueA = "a" + (i + t);
+                               String valueD = "d" + (i + t);
+
+                               IoTString iKeyA = new IoTString(keyA);
+                               IoTString iKeyD = new IoTString(keyD);
+                               IoTString iValueA = new IoTString(valueA);
+                               IoTString iValueD = new IoTString(valueD);
+
+                               try {
+                                       t1.startTransaction();
+                                       t1.addKV(iKeyA, iValueA);
+                                       t1.commitTransaction();
+                                       System.out.println("Server Success");
+
+                               } catch (Exception e) {
+                                       System.out.println("Server Fail");
+                               }
+
+                               try {
+                                       t2.startTransaction();
+                                       t2.addKV(iKeyD, iValueD);
+                                       t2.commitTransaction();
+                                       System.out.println("Server Success");
+
+                               } catch (Exception e) {
+                                       System.out.println("Server Fail");
+                               }
+
+                       }
+               }
+
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+               System.out.println("Updating Clients...");
+
+               try {
+                       Thread.sleep(3000);
+               } catch (Exception e) {
+
+               }
+
+               System.out.println("Updating Clients... T1   first");
+               while (true) {
+                       try {
+                               t1.update();
+                               break;
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                               System.out.println("Fail");
+                       }
+               }
+
+               System.out.println("Updating Clients... T2   first");
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {
+                               System.out.println("Fail");
+                       }
+               }
+
+               System.out.println("Updating Clients... T1   second");
+               while (true) {
+                       try {
+                               t1.update();
+                               break;
+                       } catch (Exception e) {
+                               System.out.println("Fail");
+                       }
+               }
+
+               System.out.println("Updating Clients... T2  second");
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {
+                               System.out.println("Fail");
+                       }
+               }
+
+               System.out.println("Checking Key-Values...");
+               for (int i = 0; i < 4; i++) {
+
+                       String keyA = "a" + i;
+                       String keyB = "b" + i;
+                       String keyC = "c" + i;
+                       String keyD = "d" + i;
+                       String valueA = "a" + (i + NUMBER_OF_TESTS - 1);
+                       String valueB = "b" + (i + NUMBER_OF_TESTS - 1);
+                       String valueC = "c" + (i + NUMBER_OF_TESTS - 1);
+                       String valueD = "d" + (i + NUMBER_OF_TESTS - 1);
+
+                       IoTString iKeyA = new IoTString(keyA);
+                       IoTString iKeyB = new IoTString(keyB);
+                       IoTString iKeyC = new IoTString(keyC);
+                       IoTString iKeyD = new IoTString(keyD);
+                       IoTString iValueA = new IoTString(valueA);
+                       IoTString iValueB = new IoTString(valueB);
+                       IoTString iValueC = new IoTString(valueC);
+                       IoTString iValueD = new IoTString(valueD);
+
+
+                       IoTString testValA1 = t1.getCommitted(iKeyA);
+                       IoTString testValB1 = t1.getCommitted(iKeyB);
+                       IoTString testValC1 = t1.getCommitted(iKeyC);
+                       IoTString testValD1 = t1.getCommitted(iKeyD);
+
+                       IoTString testValA2 = t2.getCommitted(iKeyA);
+                       IoTString testValB2 = t2.getCommitted(iKeyB);
+                       IoTString testValC2 = t2.getCommitted(iKeyC);
+                       IoTString testValD2 = t2.getCommitted(iKeyD);
+
+                       if ((testValA1 == null) || (testValA1.equals(iValueA) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyA + "    " + testValA1 + "    " + iValueA);
+                               foundError = true;
+                       }
+
+                       if ((testValB1 == null) || (testValB1.equals(iValueB) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyB + "    " + testValB1 + "    " + iValueB);
+                               foundError = true;
+                       }
+
+                       if ((testValC1 == null) || (testValC1.equals(iValueC) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyC + "    " + testValC1 + "    " + iValueC);
+                               foundError = true;
+                       }
+
+                       if ((testValD1 == null) || (testValD1.equals(iValueD) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyD + "    " + testValD1 + "    " + iValueD);
+                               foundError = true;
+                       }
+
+                       if ((testValA2 == null) || (testValA2.equals(iValueA) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyA + "    " + testValA2 + "    " + iValueA);
+                               foundError = true;
+                       }
+
+                       if ((testValB2 == null) || (testValB2.equals(iValueB) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyB + "    " + testValB2 + "    " + iValueB);
+                               foundError = true;
+                       }
+
+                       if ((testValC2 == null) || (testValC2.equals(iValueC) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyC + "    " + testValC2 + "    " + iValueC);
+                               foundError = true;
+                       }
+
+                       if ((testValD2 == null) || (testValD2.equals(iValueD) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyD + "    " + testValD2 + "    " + iValueD);
+                               foundError = true;
+                       }
+               }
+
+               if (foundError) {
+                       System.out.println("Found Errors...");
+               } else {
+                       System.out.println("No Errors Found...");
+               }
+       }
+
+       static void test8() {
+               boolean foundError = false;
+
+
+               // Setup the 2 clients
+               Table t1 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+               while (true) {
+                       try {
+                               t1.initTable();
+                               break;
+                       } catch (Exception e) {}
+               }
+
+               Table t2 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351);
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {}
+               }
+
+               // Make the Keys
+               System.out.println("Setting up keys");
+               for (int i = 0; i < NUMBER_OF_TESTS; i++) {
+                       System.out.println(i);
+
+                       String a = "a" + i;
+                       String b = "b" + i;
+                       String c = "c" + i;
+                       String d = "d" + i;
+                       IoTString ia = new IoTString(a);
+                       IoTString ib = new IoTString(b);
+                       IoTString ic = new IoTString(c);
+                       IoTString id = new IoTString(d);
+
+                       while (true) {
+                               try {
+                                       t1.createNewKey(ia, 321);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t1.createNewKey(ib, 351);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t2.createNewKey(ic, 321);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+
+                       while (true) {
+                               try {
+                                       t2.createNewKey(id, 351);
+                                       break;
+                               } catch (Exception e) {}
+                       }
+               }
+
+               // Do Updates for the keys
+               System.out.println("Setting Key-Values...");
+               for (int i = 0; i < NUMBER_OF_TESTS; i++) {
+                       System.out.println(i);
+                       String keyA = "a" + i;
+                       String keyB = "b" + i;
+                       String keyC = "c" + i;
+                       String keyD = "d" + i;
+                       String valueA = "a" + i;
+                       String valueB = "b" + i;
+                       String valueC = "c" + i;
+                       String valueD = "d" + i;
+
+                       IoTString iKeyA = new IoTString(keyA);
+                       IoTString iKeyB = new IoTString(keyB);
+                       IoTString iKeyC = new IoTString(keyC);
+                       IoTString iKeyD = new IoTString(keyD);
+                       IoTString iValueA = new IoTString(valueA);
+                       IoTString iValueB = new IoTString(valueB);
+                       IoTString iValueC = new IoTString(valueC);
+                       IoTString iValueD = new IoTString(valueD);
+
+
+                       String keyAPrev = "a" + (i - 1);
+                       String keyBPrev = "b" + (i - 1);
+                       String keyCPrev = "c" + (i - 1);
+                       String keyDPrev = "d" + (i - 1);
+                       String valueAPrev = "a" + (i - 1);
+                       String valueBPrev = "b" + (i - 1);
+                       String valueCPrev = "c" + (i - 1);
+                       String valueDPrev = "d" + (i - 1);
+
+                       IoTString iKeyAPrev = new IoTString(keyAPrev);
+                       IoTString iKeyBPrev = new IoTString(keyBPrev);
+                       IoTString iKeyCPrev = new IoTString(keyCPrev);
+                       IoTString iKeyDPrev = new IoTString(keyDPrev);
+                       IoTString iValueAPrev = new IoTString(valueAPrev);
+                       IoTString iValueBPrev = new IoTString(valueBPrev);
+                       IoTString iValueCPrev = new IoTString(valueCPrev);
+                       IoTString iValueDPrev = new IoTString(valueDPrev);
+
+                       try {
+                               t1.startTransaction();
+                               if (i != 0) {
+                                       IoTString tmp = t1.getSpeculative(iKeyAPrev);
+                                       if ((tmp == null) || !tmp.equals(iValueAPrev)) {
+                                               System.out.println("Key a Error: " + i);
+                                               foundError = true;
+                                       }
+                               }
+                               t1.addKV(iKeyA, iValueA);
+                               t1.commitTransaction();
+                       } catch (Exception e) {
+                               System.out.println("Connection Failure!");
+                       }
+
+                       try {
+                               t1.startTransaction();
+                               if (i != 0) {
+                                       IoTString tmp = t1.getSpeculative(iKeyBPrev);
+                                       if ((tmp == null) || !tmp.equals(iValueBPrev)) {
+                                               System.out.println("Key b Error: " + i);
+                                               foundError = true;
+                                       }
+                               }
+                               t1.addKV(iKeyB, iValueB);
+                               t1.commitTransaction();
+                       } catch (Exception e) {
+                               System.out.println("Connection Failure!");
+                       }
+
+                       try {
+                               t2.startTransaction();
+                               if (i != 0) {
+                                       IoTString tmp = t2.getSpeculative(iKeyCPrev);
+                                       if ((tmp == null) || !tmp.equals(iValueCPrev)) {
+                                               System.out.println("Key c Error: " + i);
+                                               foundError = true;
+                                       }
+                               }
+                               t2.addKV(iKeyC, iValueC);
+                               t2.commitTransaction();
+                       } catch (Exception e) {
+                               System.out.println("Connection Failure!");
+                       }
+
+                       try {
+                               t2.startTransaction();
+                               if (i != 0) {
+                                       IoTString tmp = t2.getSpeculative(iKeyDPrev);
+                                       if ((tmp == null) || !tmp.equals(iValueDPrev)) {
+                                               System.out.println("Key d Error: " + i);
+                                               foundError = true;
+                                       }
+                               }
+                               t2.addKV(iKeyD, iValueD);
+                               t2.commitTransaction();
+                       } catch (Exception e) {
+                               System.out.println("Connection Failure!");
+                       }
+               }
+
+               while (true) {
+                       try {
+                               t1.update();
+                               break;
+                       } catch (Exception e) {
+
+                       }
+               }
+
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {
+
+                       }
+               }
+
+               while (true) {
+                       try {
+                               t1.update();
+                               break;
+                       } catch (Exception e) {
+
+                       }
+               }
+
+               while (true) {
+                       try {
+                               t2.update();
+                               break;
+                       } catch (Exception e) {
+
+                       }
+               }
+
+
+               System.out.println("Checking Key-Values...");
+               for (int i = 0; i < NUMBER_OF_TESTS; i++) {
+
+                       String keyA = "a" + i;
+                       String keyB = "b" + i;
+                       String keyC = "c" + i;
+                       String keyD = "d" + i;
+                       String valueA = "a" + i;
+                       String valueB = "b" + i;
+                       String valueC = "c" + i;
+                       String valueD = "d" + i;
+
+                       IoTString iKeyA = new IoTString(keyA);
+                       IoTString iKeyB = new IoTString(keyB);
+                       IoTString iKeyC = new IoTString(keyC);
+                       IoTString iKeyD = new IoTString(keyD);
+                       IoTString iValueA = new IoTString(valueA);
+                       IoTString iValueB = new IoTString(valueB);
+                       IoTString iValueC = new IoTString(valueC);
+                       IoTString iValueD = new IoTString(valueD);
+
+
+                       IoTString testValA1 = t1.getCommitted(iKeyA);
+                       IoTString testValB1 = t1.getCommitted(iKeyB);
+                       IoTString testValC1 = t1.getCommitted(iKeyC);
+                       IoTString testValD1 = t1.getCommitted(iKeyD);
+
+                       IoTString testValA2 = t2.getCommitted(iKeyA);
+                       IoTString testValB2 = t2.getCommitted(iKeyB);
+                       IoTString testValC2 = t2.getCommitted(iKeyC);
+                       IoTString testValD2 = t2.getCommitted(iKeyD);
+
+                       if ((testValA1 == null) || (testValA1.equals(iValueA) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyA);
+                               foundError = true;
+                       }
+
+                       if ((testValB1 == null) || (testValB1.equals(iValueB) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyB);
+                               foundError = true;
+                       }
+
+                       if ((testValC1 == null) || (testValC1.equals(iValueC) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyC);
+                               foundError = true;
+                       }
+
+                       if ((testValD1 == null) || (testValD1.equals(iValueD) == false)) {
+                               System.out.println("Key-Value t1 incorrect: " + keyD);
+                               foundError = true;
+                       }
+
+
+                       if ((testValA2 == null) || (testValA2.equals(iValueA) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyA + "    " + testValA2);
+                               foundError = true;
+                       }
+
+                       if ((testValB2 == null) || (testValB2.equals(iValueB) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyB + "    " + testValB2);
+                               foundError = true;
+                       }
+
+                       if ((testValC2 == null) || (testValC2.equals(iValueC) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyC + "    " + testValC2);
+                               foundError = true;
+                       }
+
+                       if ((testValD2 == null) || (testValD2.equals(iValueD) == false)) {
+                               System.out.println("Key-Value t2 incorrect: " + keyD + "    " + testValD2);
+                               foundError = true;
+                       }
+               }
+
+               if (foundError) {
+                       System.out.println("Found Errors...");
+               } else {
+                       System.out.println("No Errors Found...");
+               }
+       }
+
        static void test7() throws ServerException {
 
                long startTime = 0;