package com.chap.memo.memoNodes.servlet;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.chap.memo.memoNodes.MemoNode;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
@SuppressWarnings("serial")
public class MemoTestServlet extends HttpServlet {
boolean debug = false;
static Queue queue = QueueFactory.getDefaultQueue();
long total=0;
private void log(HttpServletResponse resp, boolean ok, String shortMsg) {
log(resp, ok, shortMsg, null);
}
private void log(HttpServletResponse resp, boolean ok, String shortMsg,
String msg) {
try {
resp.getWriter().println(
(ok ? "---" : "!E!") + " - " + shortMsg
+ (!debug || msg == null ? "" : msg));
resp.flushBuffer();
} catch (IOException e) {
}
if (ok){
System.out.println(shortMsg + (msg == null ? "" : msg));
} else {
System.err.println(shortMsg + (msg == null ? "" : msg));
}
}
private boolean test(String compare, String result) {
return compare.equals(result);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
doGet(req, resp);
}
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
debug = false;
resp.setContentType("text/plain");
System.out.println("Starting!");
String cleanDBParm = req.getParameter("cleanDB");
if (cleanDBParm != null) {
MemoNode.emptyDB();
log(resp, true, "\nDatabase cleared!");
if (cleanDBParm.equals("only"))
return;
}
String debugStr = req.getParameter("debug");
if (debugStr != null && !debugStr.equals("null")) {
debug = true;
}
if (debug)
System.out.println("Outputting debug info:" + debugStr);
int nofNodes = 10000;
String sNofNodes = req.getParameter("nofNodes");
if (sNofNodes != null) {
try {
nofNodes = Integer.parseInt(sNofNodes);
} catch (Exception e) {
System.out.println("couldn't parse nofNodes=" + sNofNodes);
}
}
int nofArcs = 10000;
String snofArcs = req.getParameter("nofArcs");
if (snofArcs != null) {
try {
nofArcs = Integer.parseInt(snofArcs);
} catch (Exception e) {
System.out.println("couldn't parse nofArcs=" + snofArcs);
}
}
String nofParallel = req.getParameter("parallel");
if (nofParallel == null) {
nofParallel = "1";
}
if (Integer.parseInt(nofParallel)>1){
log(resp, true, "Going parallel:"+nofParallel,"");
TaskOptions to = withUrl("/test")
.param("parallel","1")
.param("nofNodes", Integer.toString(nofNodes))
.param("nofArcs", Integer.toString(nofArcs))
.countdownMillis(1);
int np = Integer.parseInt(nofParallel);
while (np-- > 0){
queue.add(to);
}
}
log(resp, true, "\nStarting single node tests:");
MemoNode rootNode = MemoNode.getRootNode();
log(resp,true,"Root node found:"+rootNode.getId().toString());
// Add single node
String title = "First node";
MemoNode first = new MemoNode(title);
log(resp, test(first.getStringValue(), title), "Write/Read cycle",
":" + first.getStringValue());
first = new MemoNode(first.getId());
log(resp, test(first.getStringValue(), title), "Read from readBus",
": " + first.getId() + "/" + first.getStringValue());
MemoNode.flushDB();
log(resp, test(first.getStringValue(), title), "Read after flush",
": " + first.getId() + "/" + first.getStringValue());
first = new MemoNode(first.getId());
log(resp, test(first.getStringValue(), title),
"Read from readBus after flush", ": " + first.getId() + "/"
+ first.getStringValue());
log(resp, true, "\nUpdating node value:");
title = "Updated node value";
first.update(title);
log(resp, test(first.getStringValue(), title), "Write/Read cycle",
": " + first.getId() + "/" + first.getStringValue());
first = new MemoNode(first.getId());
log(resp, test(first.getStringValue(), title), "Read from readBus",
": " + first.getId() + "/" + first.getStringValue());
log(resp, true, "\nAgain updating node value:");
title = "New updated node value";
first.update(title);
log(resp, test(first.getStringValue(), title), "Write/Read cycle",
": " + first.getId() + "/" + first.getStringValue());
first = new MemoNode(first.getId());
log(resp, test(first.getStringValue(), title), "Read from readBus",
": " + first.getId() + "/" + first.getStringValue());
MemoNode.flushDB();
log(resp, test(first.getStringValue(), title), "Read after flush",
": " + first.getId() + "/" + first.getStringValue());
first = new MemoNode(first.getId());
log(resp, test(first.getStringValue(), title),
"Read from readBus after flush", ": " + first.getId() + "/"
+ first.getStringValue());
log(resp, true, "\nStoring a null value into node:");
first.update((byte[]) null);
log(resp, test(first.getStringValue(), ""),
"Reading string leads to empty string",
": " + first.getId() + "/" + first.getStringValue());
log(resp, first.getValue().length == 0,
"Reading value leads to zero length byte array", ": "
+ first.getId() + "/" + first.getValue());
log(resp, true, "\nMulti nodal tests: (Adding one child)");
title = "First node";
first.update(title);
String secondTitle = "Second node";
MemoNode second = new MemoNode(secondTitle);
first.addChild(second);
log(resp, (first.getChildren().size() == 1),
"Parent has one child", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"Child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp,
test(first.getChildren().get(0).getStringValue(),
secondTitle), "Child found", ": " + first.getId()
+ "|" + first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
MemoNode.flushDB();
System.out.println("Running flush!");
second = new MemoNode(first.getId()).getChildren().get(0);
System.out.println("Got second child");
log(resp, test(second.getStringValue(), secondTitle),
"Child found after flush", ": " + second.getId() + "/"
+ second.getStringValue());
secondTitle = "Second node (new Value)";
second.update(secondTitle);
log(resp,
test(first.getChildren().get(0).getStringValue(),
secondTitle), "Updated child found",
": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "\nMulti nodal tests: (Adding a second child)");
String thirdTitle = "Third Node";
MemoNode third = new MemoNode(thirdTitle);
first.addChild(third);
log(resp, (first.getChildren().size() == 2),
"Parent has two children", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "First child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "Second child found", ": " + first.getId() + "|"
+ first.getChildren().get(1).getId() + "/"
+ first.getChildren().get(1).getStringValue());
log(resp, test(third.getParents().get(0).getStringValue(), title),
"Parent found", ": "
+ third.getParents().get(0).getStringValue());
log(resp, true,
"\nRemove child and re-adding it (within same Arcop shard):");
first.delChild(third);
log(resp, (first.getChildren().size() == 1),
"Parent has one child", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 0),
"Second child has no parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "Child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
first.addChild(third);
log(resp, (first.getChildren().size() == 2),
"Parent has two children", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "First child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "Second child found", ": " + first.getId() + "|"
+ first.getChildren().get(1).getId() + "/"
+ first.getChildren().get(1).getStringValue());
MemoNode.flushDB();
log(resp, true,
"\nRemove child and re-adding it (in multiple Arcop shards):");
first.delChild(second);
log(resp, (first.getChildren().size() == 1),
"Parent has one child", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 0),
"First child has no parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "Child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
first.addChild(second);
log(resp, (first.getChildren().size() == 2),
"Parent has two children", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "First child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "Second child found", ": " + first.getId() + "|"
+ first.getChildren().get(1).getId() + "/"
+ first.getChildren().get(1).getStringValue());
log(resp, true, "\nMerge shards test, compacting DB:");
MemoNode.compactDB();
log(resp, (first.getChildren().size() == 2),
"Parent has two children", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "First child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "Second child found", ": " + first.getId() + "|"
+ first.getChildren().get(1).getId() + "/"
+ first.getChildren().get(1).getStringValue());
log(resp, true, "\nDrop History test.");
MemoNode.flushDB();
MemoNode.dropHistory();
MemoNode.flushDB();
log(resp, (first.getChildren().size() == 2),
"Parent has two children", ":" + first.getId() + ":"
+ first.getChildren().size());
log(resp, (first.getParents().size() == 0),
"Parent has no parents", ":" + first.getId() + ":"
+ first.getParents().size());
log(resp, (second.getParents().size() == 1),
"First child has one parent", ":" + second.getId() + ":"
+ second.getParents().size());
log(resp, (third.getParents().size() == 1),
"Second child has one parent", ":" + third.getId() + ":"
+ third.getParents().size());
log(resp, true, "First child found", ": " + first.getId() + "|"
+ first.getChildren().get(0).getId() + "/"
+ first.getChildren().get(0).getStringValue());
log(resp, true, "Second child found", ": " + first.getId() + "|"
+ first.getChildren().get(1).getId() + "/"
+ first.getChildren().get(1).getStringValue());
log(resp, true, "\nTesting Properties:");
first.setPropertyValue("test", "hello");
log(resp, test(first.getPropertyValue("test"), "hello"),
"Property write/read cycle",
":" + first.getPropertyValue("test"));
first.setPropertyValue("test", "hello2");
log(resp, test(first.getPropertyValue("test"), "hello2"),
"Property new value write/read cycle",
":" + first.getPropertyValue("test"));
log(resp, first.getChildrenByStringValue("test", -1).size() == 1,
"Node has only one property", ":"
+ first.getChildrenByStringValue("test", -1).size());
MemoNode newPropNode = new MemoNode("Test");
newPropNode.setPropertyValue("test", "hello");
log(resp, test(newPropNode.getPropertyValue("test"), "hello"),
"Property write/read cycle",
":" + newPropNode.getPropertyValue("test"));
newPropNode.setPropertyValue("test", "hello2");
log(resp, test(newPropNode.getPropertyValue("test"), "hello2"),
"Property new value write/read cycle",
":" + newPropNode.getPropertyValue("test"));
log(resp,
newPropNode.getChildrenByStringValue("test", -1).size() == 1,
"Node has only one property", ":"
+ newPropNode.getChildrenByStringValue("test", -1)
.size());
newPropNode = new MemoNode("Test2");
newPropNode.setPropertyValue("test", "hello");
log(resp, test(newPropNode.getPropertyValue("test"), "hello"),
"Property write/read cycle",
":" + newPropNode.getPropertyValue("test"));
newPropNode.setPropertyValue("test2", "hello");
log(resp, test(newPropNode.getPropertyValue("test2"), "hello"),
"Property write/read cycle",
":" + newPropNode.getPropertyValue("test"));
newPropNode.setPropertyValue("test", "hello2");
log(resp, test(newPropNode.getPropertyValue("test"), "hello2"),
"Property new value write/read cycle",
":" + newPropNode.getPropertyValue("test"));
log(resp, newPropNode.getChildren().size() == 2,
"Node has two properties", ":"
+ newPropNode.getChildren().size());
log(resp, true, "\nTrying to recursively delete nodes:");
first.delete();
log(resp, first.getChildren().size() == 0, "First has no children",
":" + first.getChildren().size());
log(resp, second.getChildren().size() == 0,
"Second has no children", ":" + first.getChildren().size());
log(resp, third.getChildren().size() == 0, "Third has no children",
":" + first.getChildren().size());
log(resp, third.getParents().size() == 0, "Third has no parents",
":" + first.getParents().size());
MemoNode node;
MemoNode.compactDB();
long start = System.currentTimeMillis();
log(resp, true, "\nPerformance test: Depth (" + nofNodes + ")");
node = new MemoNode("start");
for (int i = 0; i < nofNodes; i++) {
MemoNode newNode = new MemoNode(new Integer(i).toString());
node.addParent(newNode.getId());
node = newNode;
}
long time = System.currentTimeMillis();
log(resp, true,
"Storing done in: " + (time - start)
+ " ms");
MemoNode startNode = node;
int count = 0;
while (node != null) {
List<MemoNode> children = node.getChildren();
if (children.isEmpty()) {
System.out.println(node.getId() + ":"
+ node.getStringValue() + " has no children!");
break;
}
count++;
if (children.get(0) == null) {
System.out.println(node.getId() + ":"
+ node.getStringValue()
+ " has NUll node as a child!");
}
node = children.get(0);
}
log(resp, (count == nofNodes), count + " children counted in:"
+ (System.currentTimeMillis() - time) + " ms");
MemoNode.flushDB();//To get a clean read setup!
time = System.currentTimeMillis();
startNode.delete();
log(resp, true, " Nodes deleted again in:"
+ (System.currentTimeMillis() - time) + " ms");
time = System.currentTimeMillis();
MemoNode.flushDB();
log(resp, true,
" Db flushed:" + (System.currentTimeMillis() - time)
+ " ms");
time = System.currentTimeMillis();
MemoNode.compactDB();
log(resp, true,
" Db compacted:" + (System.currentTimeMillis() - time)
+ " ms");
long arcStart = System.currentTimeMillis();
log(resp, true, "\nPerformance test: Breadth (" + nofArcs + ")");
MemoNode AstartNode = new MemoNode("start");
for (int i = 0; i < nofArcs; i++) {
MemoNode newNode = new MemoNode(new Integer(i).toString());
AstartNode.addChild(newNode);
}
MemoNode.flushDB();//To get a clean read setup!
long atime = System.currentTimeMillis();
log(resp, true, "Storing done in: " + (atime - arcStart) + " ms");
int acount = 0;
Iterator<MemoNode> iter = AstartNode.getChildren().iterator();
while (iter.hasNext()) {
node = iter.next();
// String value = node.getStringValue();
acount++;
}
log(resp, (acount == nofArcs), acount + " children counted in:"
+ (System.currentTimeMillis() - atime) + " ms");
atime = System.currentTimeMillis();
AstartNode.delete();
log(resp, true,
" Nodes deleted again in:"
+ (System.currentTimeMillis() - atime) + " ms");
time = System.currentTimeMillis();
MemoNode.flushDB();
log(resp, true,
" Db flushed:" + (System.currentTimeMillis() - time)
+ " ms");
start = System.currentTimeMillis();
log(resp, true, "\nPattern search test:");
/*
* _ start \ / / \ PreAmble -- 1 -- 3 -- any >--1 2 Pattern -- 5 --
* * (*= argument (using 8 and 7 below) | / \ / \ (two 5's should be
* matched in the diagram to the left) |/ 3 4 3 | \ / \ | 5 5 5 6 |
* | | / \ 8 7 8 5 7 | 8
*/
startNode = new MemoNode("start");
log(resp, true, "Startnode:" + startNode.getId(), "");
MemoNode one = new MemoNode("One");
startNode.addChild(one);
MemoNode two = new MemoNode("Two");
startNode.addChild(two);
MemoNode three1 = new MemoNode("Three");
one.addChild(three1);
three1.addChild(one); // Loop
MemoNode three2 = new MemoNode("Three");
two.addChild(three2.getId());
three2.addParent(one);// multipath
MemoNode four = new MemoNode("Four");
two.addChild(four);
MemoNode six = new MemoNode("Six");
three1.addChild(six);
MemoNode five1 = new MemoNode("Five");
six.addChild(five1);
MemoNode eight1 = new MemoNode("Eight");
five1.addChild(eight1);
MemoNode seven1 = new MemoNode("Seven");
six.addChild(seven1);
MemoNode five2 = new MemoNode("Five");
three2.addChild(five2);
MemoNode eight2 = new MemoNode("Eight");
five2.addChild(eight2);
MemoNode five3 = new MemoNode("Five");
three2.addChild(five3);
four.addChild(five3);
MemoNode seven2 = new MemoNode("Seven");
five3.addChild(seven2);
MemoNode five4 = new MemoNode("Five");
four.addChild(five4);
MemoNode eight3 = new MemoNode("Eight");
five4.addChild(eight3);
MemoNode algorithm = new MemoNode("algo");
MemoNode pattern = new MemoNode("Pattern");
algorithm.addChild(pattern);
MemoNode patFive = new MemoNode("equal;Five");
pattern.addChild(patFive);
MemoNode patEight = new MemoNode("equal;arg(Number)");
patFive.addChild(patEight);
MemoNode preAmble = new MemoNode("PreAmble");
algorithm.addChild(preAmble);
MemoNode PreStart = new MemoNode("equal;start");
preAmble.addChild(PreStart);
MemoNode PreOne = new MemoNode("equal;One");
PreStart.addChild(PreOne);
MemoNode PreTwo = new MemoNode("equal;Three");
PreOne.addChild(PreTwo);
MemoNode preAny = new MemoNode("any");
PreTwo.addChild(preAny);
preAny.addChild(preAny); // Spannend:)
time = System.currentTimeMillis();
log(resp,
true,
"Pattern stored in " + (time - start)
+ " ms ->" + preAmble.getId() + " : "
+ pattern.getId());
start = time;
HashMap<String, String> arguments = new HashMap<String, String>(2);
arguments.put("Number", "Eight");
List<MemoNode> result = startNode.search(algorithm, -1,
arguments);
if (debug) {
for (MemoNode res : result) {
log(resp, true, "Found 1: " + res.getStringValue() + "/"
+ res.getId());
}
}
time = System.currentTimeMillis();
log(resp, result.size() == 2, "Search 1 done in "
+ (time - start) + " ms");
start = time;
arguments.put("Number", "Seven");
result = startNode.search(algorithm, 2, arguments); // topx = 2
if (debug) {
for (MemoNode res : result) {
log(resp, true, "Found 2: " + res.getStringValue() + "/"
+ res.getId());
}
}
time = System.currentTimeMillis();
log(resp, result.size() == 1, "Search 2 done in "
+ (time - start) + " ms");
one.delete();
result = startNode.search(algorithm, 2, arguments); // topx = 2
if (debug) {
for (MemoNode res : result) {
log(resp, true, "Found 3: " + res.getStringValue() + "/"
+ res.getId());
}
}
time = System.currentTimeMillis();
log(resp, result.size() == 0, "Search 3 done in "
+ (time - start) + " ms");
log(resp, startNode.getChildren().size() == 1,
"StartNode has only one child left", ":"
+ startNode.getChildren().size());
for (MemoNode child : startNode.getChildren()) {
log(resp,
true,
"child: " + child.getId() + "/"
+ child.getStringValue());
}
total = 0;
String searchText = "child 1";
int num = 10;
int props = 0;
int depth = 2;
if (req.getParameter("num") != null) {
num = Integer.valueOf(req.getParameter("num"));
}
if (req.getParameter("props") != null) {
props = Integer.valueOf(req.getParameter("props"));
}
if (req.getParameter("depth") != null) {
depth = Integer.valueOf(req.getParameter("depth"));
}
System.out.println("depth=" + depth);
log(resp,true,"\nTest broad tree: "+num+"@"+depth+" with:"+props+" textproperties per node.");
// create nested nodes
start = System.currentTimeMillis();
long end = 0;
MemoNode root = MemoNode.getRootNode();
total++;
resp.getWriter().println("root id=" + root.getId().toString());
addChildren(root, num, depth, props);
end = System.currentTimeMillis();
log(resp,true,"Created " + total + " nodes" +
" (" + (end - start) + "ms)");
// force storing the nodes
start = System.currentTimeMillis();
MemoNode.flushDB();
end = System.currentTimeMillis();
log(resp,true,"flushed database " +
" (" + (end - start) + "ms)");
// create a search structure
MemoNode preambleStart = new MemoNode("start");
MemoNode preamble = new MemoNode("any");
preambleStart.addChild(preamble);
preamble.addChild(preamble);
pattern = new MemoNode("pattern");
MemoNode pattern1 = new MemoNode("equal;" + searchText);
pattern.addChild(pattern1);
HashMap<String, String> args = new HashMap<String, String>();
// search for all nodes with name "child 1"
List<MemoNode> children = null;
for (int i = 0; i < 3; i++) {
start = System.currentTimeMillis();
children = root.search(preambleStart, pattern, 0, args);
end = System.currentTimeMillis();
log(resp,children.size()>0,"found " + children.size() + " nodes, round:"+i+
" (" + (end - start) + "ms)");
}
log(resp, true, "\nAll tests done!");
} catch (Exception e) {
e.printStackTrace();
}
}
// recursively add children to given parent node
private void addChildren (MemoNode parent, int num, int depth, int props) {
for (int i = 0; i < num; i++) {
MemoNode child = new MemoNode("child " + i);
for (int j = 0; j < props; j++) {
child.setPropertyValue(String.valueOf(j), "bla bla bla " + j);
}
parent.addChild(child);
total++;
if (depth > 0) {
addChildren(child, num, depth - 1, props);
}
}
}
}