Package ca.uwaterloo.fydp.xcde

Source Code of ca.uwaterloo.fydp.xcde.XCDEStressTest2$DocObj

package ca.uwaterloo.fydp.xcde;

import ca.uwaterloo.fydp.ossp.*;
import ca.uwaterloo.fydp.ossp.std.*;
import ca.uwaterloo.fydp.ossp.impl.OSSPImpl;
import java.util.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import ca.uwaterloo.fydp.ossp.impl.OSSPSimpleSynchronizer;

public class XCDEStressTest2 {
 
  private static final int maxDepth = 10;
 
  private static final int disconnectThreshold = 10;
 
  private static class DirObj implements XCDEDirClientCallbacks {
    public DirObj(List _cntnr, XCDEDirClient _cl) {
      _cl.setCallbacks(this);
      cntnr = _cntnr;
      cntnr.add(_cl);
    }
    List cntnr; // the list the client
   
    public void receiveState(XCDEDirClient _cl, List _ent) {

    }
   
    public void notifyOfDisconnect(XCDEDirClient _cl) {
      // This routinely happens when deleted.
      cntnr.remove(_cl);
    }
   
    public void notifyOfChange(XCDEDirClient _cl, OSSPStimulus stim) {

    }
  }
 
  private static class RootDirObj extends DirObj implements XCDERootDirClientCallbacks {
    public RootDirObj(List _cntnr, XCDEDirClient _cl) {
      super(_cntnr, _cl);
    }
   
    public void receiveUsers(XCDEDirClient _cl, List _users) {

    }
   
    public void notifyOfDisconnect(XCDEDirClient _cl) {
      System.err.println("The root was disconnected.");
      System.exit(-1);
    }

  }
 
  private static class DocObj implements XCDEDocClientCallbacks {
    public DocObj(List _cntnr, XCDEDocClient _cl) {
      _cl.setCallback(this);
      cntnr = _cntnr;
      cntnr.add(_cl);
    }
    List cntnr;
   
    public void receiveState(XCDEDocClient _cl, XCDEDocument _doc) {

    }
   
    public void notifyOfDisconnect(XCDEDocClient _cl) {
      cntnr.remove(_cl);
    }
   
    public void notifyOfChange(XCDEDocClient _cl, OSSPStimulus stim) {

    }
  }
 
  private static java.util.Random rnd = new java.util.Random();
 
  private static int randomInt(int max) {
    return (int)((max + 1) * rnd.nextDouble());
  }
 
  private static OSSPStimulus randomEdit(XCDEDocument file) {
    final double insertProb = 0.5;
    double val = rnd.nextDouble();
    int pos = randomInt(file.content.length());
    int sel = randomInt(file.content.length() - pos);
    if (val < insertProb) {
      // Insert
      return new XCDEDocChangeInsertion("anon", pos, randomString());
    } else { // i.e. delete text
      // Delete
      return new XCDEDocChangeDeletion("anon", pos, sel);
    }
  }
 
  private static String randomString() {
    final int longestString = 32;
    //
    // Add 1 to the random number b/c element names of length 0 are
    // illegal and inserts of length 0 are pointless.
    //
    int length = 1 + randomInt(longestString);
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < length; i++) {
      // Choose a random ASCII letter or digit.
      char c;
      for (;;) {
        c = (char)(byte)(rnd.nextDouble()*256);
        if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || (('0' <= c) && (c <= '9'))) {
          break;
        }
      }
      buf.append(c);
    }
    return buf.toString();
  }
 
  private static String randomUsedUserName(XCDERootDirectory doc) {
    return ((XCDERootDirectoryUserState)doc.users.get(randomInt(doc.users.size()-1))).userName;
  }
 
  private static String randomUnusedUserName(XCDERootDirectory doc) {
    outer: for (;;) {
      String s = randomString();
      for (ListIterator i = doc.users.listIterator(); i.hasNext(); ) {
        String name = ((XCDERootDirectoryUserState)i.next()).userName;
        if (s.equals(name)) {
          continue outer;
        }
      }
      return s;
    }
  }
 
  private static XCDEDocumentSelection randomSelection(XCDEDocument file) {
    int pos = randomInt(file.content.length());
    int sel = randomInt(file.content.length() - pos);
    return new XCDEDocumentSelection(pos, sel);
  }
 
  private static XCDERootDirectoryUserState randomViewingUserState(String name, Vector path, OSSPDirectory dir) {
    if (dir.elements.isEmpty()) {
      // We'll abort doing a viewing user and instead do a non-viewing user.
      return null;
    }
    OSSPDirectoryElement el = (OSSPDirectoryElement)dir.elements.get( randomInt(dir.elements.size()-1) );
    path.add(el.name);
    if (el.state instanceof OSSPDirectory) {
      return randomViewingUserState(name, path, (OSSPDirectory)el.state);
    } else {
      // Found a file. Decide if we want to have a cursor in it or not.
      final double selecting = 0.75;
      double val = rnd.nextDouble();
      if (val < selecting) {
        return new XCDERootDirectoryUserState(name, (String[])path.toArray(new String[path.size()]), randomSelection((XCDEDocument)el.state), rnd.nextBoolean(), rnd.nextBoolean());
      } else {
        return new XCDERootDirectoryUserState(name, (String[])path.toArray(new String[path.size()]), null, rnd.nextBoolean(), rnd.nextBoolean());
      }
    }
  }
 
  private static XCDERootDirectoryUserState randomUserState(String name, XCDERootDirectory root) {
    final double viewingProb = 0.5;
    double val = rnd.nextDouble();
    if (val < viewingProb) {
      XCDERootDirectoryUserState tmp = randomViewingUserState(name, new Vector(), root);
      if (tmp != null) {
        return tmp;
      }
      // Else we ended up at an empty directory instead of a file. There might be files somewhere
      // in the repository, but let's just not view anything.
    }
    return new XCDERootDirectoryUserState(name, null, null, rnd.nextBoolean(), rnd.nextBoolean());
  }

  /*
  private static OSSPDirectoryElement randomElement(OSSPDirectory dir) {
    return (OSSPDirectoryElement)dir.elements.get(randomInt(dir.elements.size()-1));
  }
  */
 
  private static String randomUsedElementName(OSSPDirectory dir) {
    return ((OSSPDirectoryListingElement)dir.ls.get(randomInt(dir.elements.size()-1))).name;
  }
 
  private static OSSPDirectoryElement randomNewDirectoryElement(OSSPDirectory dir, int depth) {
    final double createDirProb = 0.5;
    String name = randomUnusedElementName(dir);
    double val = rnd.nextDouble();
    if (val < createDirProb && depth < maxDepth) {
      // Create a dir.
      return new OSSPDirectoryElement(name, randomDirectory(depth));
    } else {
      // Create a file.
      return new OSSPDirectoryElement(name, randomDocument());
    }
  }
 
  private static String randomUnusedElementName(OSSPDirectory dir) {
    outer: for (;;) {
      String s = randomString();
      for (ListIterator i = dir.ls.listIterator(); i.hasNext(); ) {
        String name = ((OSSPDirectoryListingElement)i.next()).name;
        if (s.equals(name)) {
          continue outer;
        }
      }
      return s;
    }
  }
 
  private static OSSPDirectory randomDirectory(int depth) {
    final int maxInitialElements = 5;
    int numElements = randomInt(maxInitialElements);
    OSSPDirectory dir = new OSSPDirectory();
    for (int i = 0; i < numElements; i++) {
      OSSPDirectoryElement el = randomNewDirectoryElement(dir, depth+1);
      dir.ls.add(new OSSPDirectoryListingElement(el.name, el.state.getClass().getName()));
      dir.elements.add(el);
    }
    return dir;
  }
 
  private static XCDEDocument randomDocument() {
    return new XCDEDocument(randomString());
  }
 
  /**
   * Connects the specified number of clients to the specified server
   * and has the clients make random concurrent changes
   * to the server as fast as possible for the indicated amount of time.
   * At the end, it has each client re-download the state and check it
   * versus the local copy. The process is repeated the specified number
   * of times. The results are printed to System.out.
   *
   * @param addr
   * @param port
   * @param numberOfClients
   * @param timeInMillis
   * @param repeats
   */
  public static void stressTest(InetAddress addr, int port, final int numberOfClients, final long timeInMillis, int repeats, boolean noDelayMode) {
    for (int trial = 0; trial < repeats; trial++) {

      final OSSPSynchronizer sync = new OSSPSimpleSynchronizer();
      // List of all objects opened by the clients.
      for (int i = 0; i < numberOfClients; i++) {
        final LinkedList objs = new LinkedList();
        final XCDEDirClient root;
        if (!noDelayMode) {
          root = XCDE.connectToServer(addr, port, sync);
        } else {
          root = XCDE.connectToServerInNoDelayMode(addr, port, sync);
        }
        new RootDirObj(objs, root);
       
        new Thread(new Runnable() {
          public void run() {
            try {
              // Repeatedly lock the sync, randomly choose something from DirObjs, and
              // randomly do something with it.
              long end = System.currentTimeMillis() + timeInMillis;
              while (System.currentTimeMillis() < end){
                root.pace();
                synchronized (sync) {
                  if (objs.size() == 0) {
                    System.exit(0);
                  }
                  Object o = objs.get(randomInt(objs.size()-1));
                  if (o instanceof XCDEDocClient) {
                    XCDEDocClient cl = (XCDEDocClient)o;
                    XCDEDocument doc = cl.getState();
                    boolean canEdit = cl.isOpen() && (doc != null);
                    // Our options are: open, edit, close, disconnect
                    final double editProb = 0.5, openProb = 0.75, closeProb = 0.90;
                    double val = rnd.nextDouble();
                    if (val < editProb && canEdit) {
                      cl.makeChange(randomEdit(doc));
                    } else if (val < openProb ) {
                      if (!cl.isOpen()) {
                        cl.open();
                      }
                    } else if (val < closeProb) {
                     
                      // Disallow a close on an open thing that just doesn't yet have its state.
                      if (!(cl.isOpen() && doc == null)) {
                        cl.close();
                      }
                     
                    } else {
                     
                      // Allow a disconnect only if there is at least a certain
                      // number of connected objects.
                      if (objs.size() > disconnectThreshold) {
                        cl.disconnect();
                        objs.remove(cl);
                      }
                     
                    }
                  } else {
                    XCDEDirClient cl = (XCDEDirClient)o;
                    List ls = cl.getState();
                    boolean canEdit = cl.isOpen() && (ls != null);
                    // Our options are: open, edit, close, disconnect, and connect to child
                    final double editProb = 0.4, childProb = 0.6, openProb = 0.8, closeProb = 0.90;
                    double val = rnd.nextDouble();
                    if (val < editProb && canEdit) {
                      OSSPDirectory dir = ((XCDEAbstractDirClient)cl)._getState();
                      // Our choices are: create a child, delete a child, add a user, change a user, and remove a user
                      // However, the last three only apply if this is a root dir.
                      if (cl instanceof XCDERootDirClient) {
                        XCDERootDirClient rcl = (XCDERootDirClient)cl;
                        List users = rcl.getUsers();
                        XCDERootDirectory root = (XCDERootDirectory)dir;
                        final double userProb = 0.25;
                        val = rnd.nextDouble();
                        if (val < userProb) {
                          final double addUserProb = 0.33, delUserProb = 0.66;
                          val = rnd.nextDouble();
                          if (val < addUserProb || users.isEmpty()) {
                            rcl.makeChange(new XCDERootDirectoryUserStimulusAdd(randomUserState(randomUnusedUserName(root), root)));
                          } else if (val < delUserProb) {
                            rcl.makeChange(new XCDERootDirectoryUserStimulusRemove(randomUsedUserName(root)));
                          } else {
                            final double sameName = 0.75;
                            val = rnd.nextDouble();
                            if (val < sameName) {
                              String name = randomUsedUserName(root);
                              rcl.makeChange(new XCDERootDirectoryUserStimulusChange(name, randomUserState(name, root)));
                            } else {
                              rcl.makeChange(new XCDERootDirectoryUserStimulusChange(randomUsedUserName(root), randomUserState(randomUnusedUserName(root), root)));
                            }
                          }
                          continue;
                        }
                        // Else continue on with a directory change.
                      }
                      // If we got here, we didn't do a user change. Do a directory change.
                      val = rnd.nextDouble();
                      final double createProb = 0.5;
                      if ((val < createProb) || ls.isEmpty()) {
                        cl.makeChange(new OSSPDirectoryStimulusInitiateCreate(randomNewDirectoryElement(dir, 0)));
                      } else {
                        // Delete an element.
                        cl.makeChange(new OSSPDirectoryStimulusDelete(randomUsedElementName(dir)));
                      }
                    } else if (val < childProb && canEdit) {
                      // Must randomly choose from the elements that are not already open.
                     
                      // The list is indeed a LinkedList in reality so this code will work.
                      List ls2 = (List)((LinkedList)ls).clone();
                      outer: for (Iterator i = cl.getOpenChildren(); i.hasNext(); ) {
                        XCDEDirElement el = (XCDEDirElement)i.next();
                        // Found an open child. Remove it from the list of children to potentially open.
                        for (Iterator j = ls2.iterator(); j.hasNext(); ) {
                          OSSPDirectoryListingElement el2 = (OSSPDirectoryListingElement)j.next();
                          if (el.getDirElementName().equals(el2.name)) {
                            // Found it.
                            j.remove();
                            continue outer;
                          }
                        }
                      }
                      // ls2 is now a list of all the children we can open. If it's empty, we'll just skip
                      // this editing iteration.
                      if (!ls2.isEmpty()) {
                        OSSPDirectoryListingElement el = (OSSPDirectoryListingElement)ls2.get(randomInt(ls2.size()-1));
                        // Open this.
                        if (el.className.equals(OSSPDirectory.class.getName())) {
                          new DirObj(objs, cl.connectToDir(el.name));
                        } else {
                          new DocObj(objs, cl.connectToDoc(el.name));
                        }
                      }
                    } else if (val < openProb) {
                      // Disallow redundant opens.
                      if (!cl.isOpen()) {
                        cl.open();
                      }
                    } else if (val < closeProb) {
                      // Disallow a close on an open thing that just doesn't have its
                      // state yet.
                      if (!(cl.isOpen() && ls == null)) {
                        cl.close();
                      }
                     
                    } else {
                     
                      // Allow a disconnect only if there is at least a certain
                      // number of connected objects.
                      if (objs.size() > disconnectThreshold) {
                        cl.disconnect();
                        objs.remove(cl);
                      }
                     
                    }
                  }
                }
              }
              // Done. Must disconnect everything.
              synchronized (sync) {
                while (!objs.isEmpty()) {
                  Object ob = objs.removeFirst();
                  if (ob instanceof XCDEDirClient) {
                    ((XCDEDirClient)ob).disconnect();
                  } else {
                    ((XCDEDocClient)ob).disconnect();
                  }
                }
              }
            } catch (Exception e) {
              System.out.println("Exception during test thread. Error follows.");
              e.printStackTrace();
              System.exit(-1);
            }
          }
        }).start();
      }
    }
  }
 
  /**
   * args[0] = server machine name as string
   * args[1] = server port number as string
   * args[2] = number of clients to connect with
   * args[3] = milliseconds to run each trial for
   * args[4] = max. number of trials to do
   *
   * @param args
   */
  public static void main(String[] args) throws UnknownHostException {
    stressTest(InetAddress.getByName(args[0]), Integer.parseInt(args[1]),
        Integer.parseInt(args[2]), Integer.parseInt(args[3]), Integer.parseInt(args[4]), Boolean.valueOf(args[5]).booleanValue());
  }
}
TOP

Related Classes of ca.uwaterloo.fydp.xcde.XCDEStressTest2$DocObj

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.