/** * Autograder for the Key-Value Store. * * @author Mosharaf Chowdhury (http://www.mosharaf.com) * @author Prashanth Mohan (http://www.cs.berkeley.edu/~prmohan) * * Copyright (c) 2012, University of California at Berkeley * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of University of California, Berkeley nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package edu.berkeley.cs162; import edu.berkeley.cs162.KVClient; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; public class AutoGrader { /** * Information for individual operations */ private static class TestOperation { // Thread to execute this operation in Thread execThread = null; // Time to wait before calling the operation long delayBeforeOp = 0; // Name of the operation String opName = null; // Key and value String key = null; String value = null; // Time to wait in KVCache during the opertion long putDelay = 0; long getDelay = 0; long delDelay = 0; TestOperation(long delayBeforeOp, String opName, String key, String value, long delay) { this.delayBeforeOp = delayBeforeOp; this.opName = opName.toUpperCase(); this.key = key; this.value = value; if (opName.equals("PUT")) { this.putDelay = delay; } else if (opName.equals("GET")) { this.getDelay = delay; } else if (opName.equals("DEL")) { this.delDelay = delay; } } void executeInThread() { Runnable r = new Runnable() { public void run() { // Create a client KVClient kc = new KVClient("localhost", 8080); System.out.println(opName); // Perform the operation try { if (opName.equals("PUT")) { kc.put(key, value); } else if (opName.equals("GET")) { kc.get(key); } else if (opName.equals("DEL")) { kc.del(key); } } catch (KVException kve) { System.err.println(kve.getMsg()); } } }; execThread = new Thread(r); execThread.start(); } void waitToFinish() { try { execThread.join(); } catch (Exception e) { } } } private static long STORE_DELAY = 1000; private static KVStore dataStore = null; private static KVCache dataCache = null; private static int currentOp = 0; private static TestOperation[] TEST_OPS = null; private static TPCMasterServerThread masterThread = null; private static ServerThread[] serverThreads = null; private static int curTestID = -1; // Currently running test private static ArrayList<Long> killAtFirstPhase = new ArrayList<Long>(); private static HashMap<Long, Thread> slaveID2ThreadMap = new HashMap<Long, Thread>(); public static void main(String args[]) { runFirstPhaseFailureTest(); } private static void runTest(int numSets, int maxElemsPerSet, long storeDelay, int numSlaves, TestOperation[] testOps) { // Initialize currentOp = 0; TEST_OPS = testOps; // Set STORE_DELAY STORE_DELAY = storeDelay; long[] slaveIds = new long[numSlaves]; Random slaveIdGenerator = new Random(); for (int i=0; i < numSlaves; i++) { slaveIds[i] = slaveIdGenerator.nextLong(); } // Start TPC Master TPCMasterServerThread masterThread = startMasterServer(numSets, maxElemsPerSet, numSlaves); ServerThread[] serverThreads = new ServerThread[numSlaves]; for (int i=0; i < slaveIds.length; i++) { // Start kvServer serverThreads[i] = startSlaveServer(numSets, maxElemsPerSet, slaveIds[i], "localhost"); // Store mapping from slaveIDs to corresponding threads slaveID2ThreadMap.put(slaveIds[i], serverThreads[i]); delay(500); } // Iterate over TestOperation[] for (TestOperation testOp: testOps) { // Delay the operation delay(testOp.delayBeforeOp); // Each TestOperation runs in its own thread testOp.executeInThread(); // Move to the next TestOperation currentOp++; } // Wait for threads to finish for (TestOperation testOp: testOps) { testOp.waitToFinish(); } for (int i=0; i < slaveIds.length; i++) { // Stop SocketServer serverThreads[i].stopServer(); } masterThread.stopServer(); // Cleanup currentOp = 0; TEST_OPS = null; // Give time to cleanup delay(5000); } private static void runFirstPhaseFailureTest() { int numSets = 2; int maxElemsPerSet = 2; String three = "3"; String seven = "7"; ArrayList<TestOperation> testOps = new ArrayList<TestOperation>(); // PUT (3, 7) testOps.add(new TestOperation(0, "PUT", three, seven, 0)); // Wait 5 seconds; GET 3; Make it last for 10 seconds testOps.add(new TestOperation(5000, "GET", three, null, 10000)); long storeDelay = STORE_DELAY; // Initialize currentOp = 0; TEST_OPS = (TestOperation[]) testOps.toArray(); curTestID = 1; // Set STORE_DELAY STORE_DELAY = storeDelay; int numSlaves = 2; long[] slaveIds = new long[numSlaves]; Random slaveIdGenerator = new Random(); for (int i=0; i < numSlaves; i++) { slaveIds[i] = slaveIdGenerator.nextInt(); } // Start TPC Master masterThread = startMasterServer(numSets, maxElemsPerSet, numSlaves); serverThreads = new ServerThread[numSlaves]; killAtFirstPhase = new ArrayList<Long>(); for (int i=0; i < slaveIds.length; i++) { // Start kvServer serverThreads[i] = startSlaveServer(numSets, maxElemsPerSet, slaveIds[i], "localhost"); if (killAtFirstPhase.size() == 0) { killAtFirstPhase.add(new Long(slaveIds[i])); } // Store mapping from slaveIDs to corresponding threads slaveID2ThreadMap.put(slaveIds[i], serverThreads[i]); delay(500); } // Iterate over TestOperation[] for (TestOperation testOp: testOps) { // Delay the operation delay(testOp.delayBeforeOp); // Each TestOperation runs in its own thread testOp.executeInThread(); // Move to the next TestOperation currentOp++; } // Wait for threads to finish for (TestOperation testOp: testOps) { testOp.waitToFinish(); } for (int i=0; i < slaveIds.length; i++) { // Stop SocketServer serverThreads[i].stopServer(); } masterThread.stopServer(); // Cleanup currentOp = 0; TEST_OPS = null; killAtFirstPhase = null; masterThread = null; serverThreads = null; // Give time to cleanup delay(5000); } /** * Keep track of KVServer life cycle for individual tests */ private static class ServerThread extends Thread { int numSets; int maxElemsPerSet; SocketServer server = null; long slaveId = 0; String masterHostName; public ServerThread(int numSets, int maxElemsPerSet, long slaveId, String masterHostName) { this.numSets = numSets; this.maxElemsPerSet = maxElemsPerSet; this.slaveId = slaveId; this.masterHostName = masterHostName; } public void stopServer() { server.stop(); } public void run() { KVServer kvServer = new KVServer(numSets, maxElemsPerSet); TPCMasterHandler handler = new TPCMasterHandler(kvServer, slaveId, 1); // Create TPCLog String logPath = slaveId + "@" + server.getHostname(); TPCLog tpcLog = new TPCLog(logPath, kvServer); // Load from disk and rebuild logs try { tpcLog.rebuildKeyServer(); } catch (KVException e2) { // TODO: Handle this } // Set log for TPCMasterHandler handler.setTPCLog(tpcLog); server = new SocketServer("localhost"); server.addHandler(handler); try { server.connect(); } catch (IOException e) { e.printStackTrace(); return; } try { handler.registerWithMaster(masterHostName, server); } catch (UnknownHostException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (KVException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } System.out.println("Starting ServerThread at port " + server.getPort() + "..."); try { server.run(); } catch (IOException e) { e.printStackTrace(); } System.out.println("Stopping ServerThread..."); } } /** * Keep track of TPCMaster life cycle for individual tests */ private static class TPCMasterServerThread extends Thread { int numSets; int maxElemsPerSet; SocketServer server = null; int numSlaves = 0; TPCMasterServerThread(int numSets, int maxElemsPerSet, int numSlaves) { this.numSets = numSets; this.maxElemsPerSet = maxElemsPerSet; this.numSlaves = numSlaves; } public void stopServer() { server.stop(); } public void run() { TPCMaster tpcMaster = new TPCMaster(numSlaves); NetworkHandler handler = new KVClientHandler(tpcMaster); server = new SocketServer("localhost", 8080); server.addHandler(handler); try { server.connect(); } catch (IOException e) { e.printStackTrace(); return; } System.out.println("Starting Registration Thread..."); tpcMaster.run(); System.out.println("Starting ServerThread..."); try { server.run(); } catch (IOException e) { e.printStackTrace(); } } } private static TPCMasterServerThread startMasterServer(int numSets, int maxElemsPerSet, int numSlaves) { TPCMasterServerThread thr1 = new TPCMasterServerThread(numSets, maxElemsPerSet, numSlaves); thr1.start(); return thr1; } private static ServerThread startSlaveServer(int numSets, int maxElemsPerSet, long slaveId, String masterHostName) { ServerThread thr1 = new ServerThread(numSets, maxElemsPerSet, slaveId, masterHostName); thr1.start(); return thr1; } private static void testCase1() { } public static void registerKVServer(KVStore dataStore, KVCache dataCache) { AutoGrader.dataStore = dataStore; AutoGrader.dataCache = dataCache; } public static void agCachePutStarted(String key, String value) { } public static void agCachePutFinished(String key, String value) { } public static void agCacheGetStarted(String key) { } public static void agCacheGetFinished(String key) { } public static void agCacheDelStarted(String key) { } public static void agCacheDelFinished(String key) { } public static void agStorePutStarted(String key, String value) { } public static void agStorePutFinished(String key, String value) { } public static void agStoreGetStarted(String key) { } public static void agStoreGetFinished(String key) { } public static void agStoreDelStarted(String key) { } public static void agStoreDelFinished(String key) { } public static void agKVServerPutStarted(String key, String value) { } public static void agKVServerPutFinished(String key, String value) { } public static void agKVServerGetStarted(String key) { } public static void agKVServerGetFinished(String key) { } public static void agKVServerDelStarted(String key) { } public static void agKVServerDelFinished(String key) { } public static void agCachePutDelay() { } public static void agCacheGetDelay() { } public static void agCacheDelDelay() { } /** * KVStore will sleep for STORE_DELAY milliseconds */ public static void agStoreDelay() { delay(STORE_DELAY); } /** * Helper method to put the current thread to sleep for sleepTime duration * @param sleepTime time to sleep in milliseconds */ private static void delay(long sleepTime) { try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } } public static void agRegistrationStarted(long slaveID) { // TODO Auto-generated method stub } public static void agRegistrationFinished(long slaveID) { // TODO Auto-generated method stub } public static void agReceivedTPCRequest(long slaveID) { // TODO Auto-generated method stub } public static void agFinishedTPCRequest(long slaveID) { // TODO Auto-generated method stub } public static void agTPCMasterStarted() { // TODO Auto-generated method stub } public static void agTPCMasterFinished() { // TODO Auto-generated method stub } public static void aghandleGetFinished() { // TODO Auto-generated method stub } public static void aghandleGetStarted() { // TODO Auto-generated method stub } public static void agPerformTPCOperationFinished(boolean isPutReq) { // TODO Auto-generated method stub } public static void agPerformTPCOperationStarted(boolean isPutReq) { // TODO Auto-generated method stub } public static void agSecondPhaseStarted(long slaveID, KVMessage origMsg, boolean origAborted) { if (curTestID == 1 && !killAtFirstPhase.contains(new Long(slaveID))) { Thread srvThread = slaveID2ThreadMap.get(new Long(slaveID)); for (int i=0; i < serverThreads.length; i++) { if (serverThreads[i] == srvThread) { serverThreads[i].run(); } } } } public static void agSecondPhaseFinished(long slaveID, KVMessage origMsg, boolean origAborted) { // TODO Auto-generated method stub } public static void agGetStarted(long slaveID) { // TODO Auto-generated method stub } public static void agGetFinished(long slaveID) { // TODO Auto-generated method stub } @SuppressWarnings("deprecation") public static void agTPCPutStarted(long slaveID, KVMessage msg, String key) { if (curTestID == 1 && killAtFirstPhase.contains(new Long(slaveID))) { Thread srvThread = slaveID2ThreadMap.get(new Long(slaveID)); srvThread.stop(); } } public static void agTPCPutFinished(long slaveID, KVMessage msg, String key) { // TODO Auto-generated method stub } @SuppressWarnings("deprecation") public static void agTPCDelStarted(long slaveID, KVMessage msg, String key) { if (curTestID == 1 && killAtFirstPhase.contains(new Long(slaveID))) { Thread srvThread = slaveID2ThreadMap.get(new Long(slaveID)); srvThread.stop(); } } public static void agTPCDelFinished(long slaveID, KVMessage msg, String key) { // TODO Auto-generated method stub } }