Compare commits

...

14 Commits

  1. 10
      ConnHandler.java
  2. 3
      ResManager.java
  3. 52
      basicClient.html
  4. 807
      client.html
  5. 706
      cortex.js
  6. 419
      cortexLocks.js
  7. 16
      shell.html

10
ConnHandler.java

@ -340,7 +340,7 @@ class ConnHandler implements Runnable {
userAgent = header;
}
System.out.println(i + ": '" + header + "'");
//System.out.println(i + ": '" + header + "'");
i++;
header = sin.readLine();
}
@ -353,6 +353,7 @@ class ConnHandler implements Runnable {
byte[] get_resp= null;
String CODE = "200 OK";
int resp_length = 0;
String content_type = "text/html";
if (type == TYPE_GET) {
reqLine = reqLine.substring(4);
res.log("GET " + reqLine);
@ -361,6 +362,11 @@ class ConnHandler implements Runnable {
CODE = "404 Not Found";
}
resp_length = get_resp.length;
String end = reqLine.substring(reqLine.length()-4);
if (end == ".js")
content_type = "text/javascript";
else if (end == "css")
content_type= "text/css";
} else {
// No forward
if (reqLine.equals("")) {
@ -385,7 +391,7 @@ class ConnHandler implements Runnable {
SimpleDateFormat formater = new SimpleDateFormat("E, d M y H:m:s z");
sout.print("HTTP/1.1 " + CODE + "\r\n"+
"Date: " + formater.format(now) + "\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"Content-Type: " + content_type + "; charset=UTF-8\r\n" +
"Server: Cortex @ " + Integer.toString(res.PORT) + "\r\n");
// Print response

3
ResManager.java

@ -146,6 +146,9 @@ class ResManager {
putSite("shell.html", readURL(new URL(baseurl + "shell.html")));
putSite("ajax.js", readURL(new URL(baseurl + "ajax.js")));
putSite("cortex.js", readURL(new URL(baseurl + "cortex.js")));
putSite("basicClient.html", readURL(new URL(baseurl + "basicClient.html")));
} catch (Exception e) {

52
basicClient.html

@ -0,0 +1,52 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Client</title>
<style type="text/css">
.page {
visibility: hidden;
position: absolute;
top: 40px;
left: 10px;
border: 1px solid black;
padding: 5px;
width: 550px;
}
td, th {
border: 1px solid black;
margin: 0px;
}
tr {
padding: 0px;
margin: 0px;
}
table {
padding: 0px;
border: 1px solid black;
}
</style>
<script src="cortex.js" ></script>
</head>
<body>
<div id="statusLabel"></div>
<div id="numberOfNodes">Number of nodes: <script> document.write(numberOfNodes); </script></div>
<div id="connections">Connected to:</div>
<div id="dlc">DLC:</div>
<input id="networkAddr"><input type="button" value="Join Network" onClick="join_network(document.getElementById('networkAddr').value);"><br/>
<br />
<b>Log:</b> <input type="checkbox" value="log" id="logCheck"/>Log?<br/>
<textarea rows="7" cols="60" id="cortexLog" readonly="true"></textarea>
<br/>
<input type="button" value="Reload HTML" onclick="reloadHTML()" />
<br/><br/>
<input type="button" value="Kill Server" onClick="killServer()" />
<script language="javascript">cortex_start()</script>

807
client.html

@ -35,16 +35,10 @@
<script>
var localNodeAddr = '';
var originURL = 'Unknown Source';
var connected = false;
var numberOfNodes = 0;
var connections = new Array();
var tests = new Array();
var testLocks = new Array();
var lockTrys = new Array();
var myLocks = new Array();
var runningTests = new Array();
var rangeLocks = new Array();
@ -54,280 +48,8 @@ var doneStage = 0;
var runTry = null;
var dlc = 0;
var msgQ = new Array();
function error(msg) {
log("ERROR: " + msg);
alert("ERROR: " + msg);
clearInterval(cronID);
}
/* basic ping function for local node
* if successful,
* if we haven't greeted the server, we do,
* otherwise nothing (just a heartbeat)
* if it fails, lets the user know we have lost
* connection to the node server
*/
function ping() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
if (!connected) {
connected = true;
greet();
}
},
function(resp) {
connected = false;
var html = "Connection to local Node failed. Try reloading from <a href=\"" + originURL + "\" target=\"window\">" + originURL + "</a>";
document.getElementById('statusLabel').innerHTML = html;
}
);
ajaxSend(http, "cmd=ping\n\n", retfn);
}
/* Greets the server
* so far just gets the server's IP and origin URL
*/
function greet() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
var arr = resp.split(" ");
localNodeAddr = arr[0];
originURL = arr[1];
document.getElementById('statusLabel').innerHTML = "I am <b>" + localNodeAddr + "</b>";
init();
}
);
ajaxSend(http, "cmd=greet\n\n", retfn);
}
function killServer() {
announceDead(localNodeAddr);
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
// got a resp, server not dead
killServer();
});
ajaxSend(http, "cmd=kill\n\n", retfn);
}
function getLog() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
var log = document.getElementById('log');
//alert("getLog() resp: " + resp);
log.value = resp + log.value;
// Since getLog returns (a call back is called later)
// this is tail recursive friendly
getLog();
});
ajaxSend(http, "cmd=getLog\n\n", retfn);
}
// two digits
function d2(str) {
if (str <10)
return "0"+str;
else
return str;
}
function getTime() {
var date = new Date();
return d2(date.getHours()) + ":" + d2(date.getMinutes()) + ":" + d2(date.getSeconds())
}
var logCheckElem = null;
function log(str) {
if (logCheckElem == null)
logCheckElem = document.getElementById("logCheck");
if (logCheckElem.checked == true) {
str = getTime() + ": " + str+"\n";
var log = document.getElementById('log');
log.value = str + log.value;
}
}
function log2(str) {
str = getTime() + ": " + str+"\n";
var log = document.getElementById('log');
log.value = str + log.value;
}
function getMsgs() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
//log("getMsgs: len > 0");
log("getMsgs: " + resp);
queueMsgs(resp);
// Since getMsgs returns (a call back is called later)
// this is tail recursive friendly
getMsgs();
});
ajaxSend(http, "cmd=getMsgs\n\n", retfn);
}
function connectedTo(addr) {
if (addr == localNodeAddr)
return true;
for(i = 0; i < connections.length; i++) {
if (connections[i] == addr)
return true;
}
return false;
}
function addConnection(addr) {
if(!connectedTo(addr)) {
connections[connections.length] = addr;
numberOfNodes++;
return true;
} else
return false;
}
function genNodeList() {
var str = "";//localNodeAddr+",";
for (var i =0; i < connections.length; i++) {
str += connections[i] + ",";
}
if (connections.length > 0)
str = str.substring(0,str.length-1);
return str;
}
function advertiseNewNode(addr) {
var m = new Object();
m['query'] = "newNode";
m['addr'] = addr;
bcastMsg(m);
}
function announceDead(addr) {
var m = new Object();
m['query'] = "deadNode";
m['addr'] = addr;
bcastMsg(m);
}
function handleNewNode(resp, welcome) {
if (welcome == null)
welcome = false;
var addr = resp.addr;
//log2("handle new node " + addr + " from " + resp.origin);
// handles re adding if reloaded html
//if (!connectedTo(addr))
//{
var ret = genNodeList();
var n = addConnection(addr);
if (welcome == true) {
sendDLC(addr);
sendWelcome(ret, addr);
sendLocks(addr);
sendTests(addr);
}
if (n == true) {
sendReqs(addr);
advertiseNewNode(addr);
}
}
function sendDLC(addr) {
var m = new Object();
m.query = "DLC";
sendMsg(m, addr);
}
function sendReqs(addr) {
for(i in lockTrys) {
var lock = lockTrys[i];
if (lock == null)
continue;
var m = new Object();
m["query"] = "getLock";
m["type"] = i;
m["name"] = lock["name"];
m["time"] = lock.time;
m["addr"] = localNodeAddr;
if (i == "range") {
m["start"] = lock.start;
m["end"] = lock.end;
}
sendMsg(m, addr);
}
}
function sendWelcome(addrList, addr) {
var m = new Object();
m["query"] = "welcome";
m["addrList"] = addrList;
sendMsg(m, addr);
}
function sendLocks(addr) {
for (var i in testLocks) {
log ("testLog[" + i + "]");
var l = testLocks[i];
var m = new Object();
m["query"] = "addLock";
m["type"] = "test";
m["name"] = l["name"];
m["addr"] = l["addr"];
m["locked"] = l["locked"];
m["perjob"] =
m["time"] = l["time"];
if (l.running) {
m["running"] = true;
m["min"] = l["min"];
m["max"] = l["max"];
m["perjob"] = l["perjob"];
}
sendMsg(m, addr);
}
for (var i in rangeLocks) {
var r = rangeLocks[i];
while(r) {
log("rangeLock[" + i +" [" + r.start + "-" + r.end +"]]");
var m = new Object();
m["query"] = "addLock";
m["type"] = "range";
m["name"] = i;
m["addr"] = r["addr"]
m["locked"] = r["locked"];
m["start"] = r["start"];
m["end"] = r["end"];
m["done"] = r["done"];
if (r['results'])
m["results"] = r["results"];
sendMsg(m, addr);
r = r.next;
}
}
}
function sendTests(addr) {
for(var i in tests) {
@ -336,32 +58,6 @@ function sendTests(addr) {
}
}
function handleAddLock(resp) {
if(resp['locked'] == null)
resp['locked'] = false;
// dont add/overwrite if exists?
var lock = retrieveLock(resp);
if (resp['type'] == "test" ) {//&& (lock == null || lock.addr == null)) {
var locks = getLockType(resp['type']);
locks[resp['name']] = resp
if(resp['running'] == true) {
runningTests.push(resp['name']);
}
} else if(resp['type'] == "range" && lock.addr == null) {
log("Add range lock: " + resp['name'] + " (" + resp['start'] + " to " + resp['end'] + ") : ");
var lock = getRangeLock(resp['name'], resp['start'], resp['end']);
lock.addr = resp['addr'];
lock.locked = resp['locked'];
lock.done = resp['done'];
lock.results = resp['results'];
lock.name = resp['name'];
}
}
function packArray(arr) {
if (arr instanceof Object) {
var str = "{";
@ -432,108 +128,6 @@ function packResults(res) {
return str;
}
function packObject(m, defaultValue) {
var str = "";
for (var i in m) {
if (m[i] == '')
{
if (defaultValue == null) {
continue;
} else {
m[i] = defaultValue;
}
}
if (i == "results") {
str += i + "=" + packResults(m[i]) + "\n";
} else {
str += i + "=" + m[i] + "\n";
}
}
return str;
}
function removeNodeRangeLocks(addr) {
for(var i in rangeLocks) {
log("freeing " + i + " locks");
var rlock = rangeLocks[i];
while (rlock != null) {
log("looking at " + i + " (" + rlock.start + " to " + rlock.end + ") : " + rlock.addr);
if (rlock.addr == addr) {
log("unlocking");
rlock.locked = false;
}
rlock = rlock.next;
}
}
}
function disconnect(addr) {
log("--------------DISCONNECT " + addr + "----------");
// remove from connections list
for (var i=0; i < connections.length; i++) {
if (connections[i] == addr) {
connections.splice(i,1);
numberOfNodes--;
break;
}
}
// remove locks
// test locks
for(var i in testLocks) {
var lock = testLocks[i];
if (!lock)
continue;
if (lock.addr == addr) {
lock.locked = false;
}
}
// range locks
removeNodeRangeLocks(addr);
log("disconnect: freeing range locks");
}
function sendMsg(m, addr, time, mtype) {
if(time == null)
time = dlc;
if(mtype == null)
mtype = "single";
var str = "cmd=sendMsg\n";
str += "origin=" + localNodeAddr + "\n";
str += "dlc=" + time + "\n";
str += "mtype=" + mtype + "\n";
str += packObject(m);
str += "\n";
log ("SEND: " + str);
var http = ajaxConnect();
var retfn = returnfn(http, null,
function() {
disconnect(addr);
announceDead(addr);
log("ERROR> message to " + addr + " not delivered: '" + str + "'");
});
ajaxSend(http, str, retfn, addr);
}
function bcastMsg(m) {
if (m.query != "heartBeat")
dlc ++;
//log("BCAST conLen: " + connections.length);
for(var i=0; i < connections.length; i++) {
log("bcast "+ i +" " + m.query + " to " + connections[i] + " dlc:" + dlc);
sendMsg(m, connections[i], dlc, "bcast");
//log("back from sendMsg, i:" + i + " conlen:" + connections.length);
}
}
function encodeStr(str) {
var res="";
@ -573,69 +167,19 @@ function decodeStr(str) {
return res;
}
function addMsg(resp) {
//log("addMsg mdlc: " + resp.dlc + " mqlen: " + msgQ.length + " type:" + resp.mtype + " query: " + resp.query);
for(var i=msgQ.length-1; i>=0; i--) {
//log("resp.dlc:" + resp.dlc + " msgQ[i].dlc:" + msgQ[i].dlc);
if (resp.dlc > msgQ[i].dlc) {
//log("moving " + i + " to " + (i+1));
msgQ[i+1] = msgQ[i];
} else {
//log("first, moving " + i + " to " + (i+1));
//msgQ[i+1] = msgQ[i];
//log("putting msg in " + i + " + 1, RETURN");
msgQ[i+1] = resp;
return;
}
}
//log("END: putting msg in 0");
msgQ[0] = resp;
}
function queueMsgs(mstr) {
log("GOT messages: " + mstr);
var resps = mstr.split("\n\n");
for(var rcount=0; rcount < resps.length; rcount++) {
var resp = resps[rcount];
if (resp == "")
continue;
resp = parseResp(resp);
if (resp.query == "DLC") {
dlc = resp.dlc;
//var m = new Object();
//m.query = "DLC";
//bcastMsg(m);
} else {
addMsg(resp);
}
}
var s = "QUEUE: "
for (var i =0; i< msgQ.length; i++) {
s += msgQ[i].dlc + " ";
}
log(s);
log("mqlen:" + msgQ.length);
while (msgQ.length>0 && ((msgQ[msgQ.length-1].dlc - 1) <= dlc)) {
var r = msgQ.pop();
log("mdlc: " + r.dlc + " dlc: " + dlc + " mqlen: " + msgQ.length + " type:" + r.mtype + " query: " + r.query);
if (r.mtype == "bcast")
dlc = r.dlc
processMsg(r);
}
}
function processMsg(resp) {
if (resp["query"] == "join_network") {
log("Message join_network received");
handleNewNode(resp, true);
} else if (resp["query"] == "welcome") {
handleWelcome(resp);
} else if (resp["query"] == "newNode") {
//addConnection(resp["addr"]);
handleNewNode(resp, false);
} else if (resp["query"] == "deadNode") {
disconnect(resp["addr"]);
// if (resp["query"] == "join_network") {
// log("Message join_network received");
// handleNewNode(resp, true);
// } else if (resp["query"] == "welcome") {
// handleWelcome(resp);
// } else if (resp["query"] == "newNode") {
// //addConnection(resp["addr"]);
// handleNewNode(resp, false);
// } else if (resp["query"] == "deadNode") {
// disconnect(resp["addr"]);
} else if(resp["query"] == "addLock") {
handleAddLock(resp);
} else if (resp["query"] == "getLock") {
@ -650,120 +194,16 @@ function processMsg(resp) {
handleActivateJob(resp);
} else if(resp["query"] == "results") {
handleResults(resp);
} else if(resp["query"] == "new_network") {
join_network(resp["addr"], false);
} else if(resp["query"] == "heartBeat") {
// do nothing;
// } else if(resp["query"] == "new_network") {
// join_network(resp["addr"], false);
// } else if(resp["query"] == "heartBeat") {
// // do nothing;
return;
} else {
log("Error: Unkown message '" + resp["query"] + "' received from " + resp["origin"]);
}
}
function handleWelcome(resp) {
log("Welcome message received");
//var myNodes = genNodeList();
addConnection(resp['origin']);
if (resp['addrList']){
var nodes = resp['addrList'].split(",");
for(var i=0; i < nodes.length; i++){
addConnection(nodes[i]);
}
}
for(var i =0; i< connections.length; i++) {
var addr = connections[i];
if (addr == localNodeAddr)
continue;
advertiseNewNode(addr);
}
}
function extractHost(url) {
// http: or file:
var host = url.substr(5);
while (host.charAt(0) == '/')
host = host.substr(1);
var end = host.indexOf('/');
if (end > 0 )
host = host.substr(0, end);
return host;
}
function setStatus() {
document.getElementById('numberOfNodes').innerHTML = "Number of nodes: " + numberOfNodes;
document.getElementById('connections').innerHTML = "Connected to: " + genNodeList();
document.getElementById('dlc').innerHTML = "DLC: " + dlc;
}
function init() {
if (connected == false)
return;
numberOfNodes = 1;
if (originURL.substr(0, 4) == "file") {
// we are the first
//numberOfNodes = 1; // ourself
log("Loaded from file");
// now we sit and wait
} else { // it was http, so we were loaded from another node
log("Loaded from " + originURL);
originAddress = extractHost(originURL);
join_network(originAddress);
}
}
function parseResp(resp) {
var lines = resp.split("\n");
var arr = [];
for(var i=0; i < lines.length; i++) {
//var kv = lines[i].split("=");
var mid = lines[i].indexOf("=");
var kv = new Array();
kv[0] = lines[i].substring(0, mid);
kv[1] = lines[i].substring(mid+1);
if (kv[1] == "true")
kv[1] = true;
else if(kv[0] == "false")
kv[1] = false;
else if (kv[0] == "dlc" ||
kv[0] == "start" ||
kv[0] == "end" ||
kv[0] == "min" ||
kv[0] == "max")
kv[1] = Number(kv[1]);
else if (kv[0] == "results")
kv[1] = unpackResults(kv[1]);
arr[kv[0]] = kv[1];
}
return arr;
}
function join_network(address, bcast) {
if(bcast == null) {
bcast = true;
}
log("join_network -> " + address);
var m = new Object();
m["query"] = "join_network";
m["addr"] = localNodeAddr;
//m["nodes"] = genNodeList();
sendMsg(m, address);
if (bcast == true) {
m = new Object();
m["query"] = "new_network";
m["addr"] = address;
bcastMsg(m);
}
}
var runCount = 0;
var workMod = 1;
@ -816,7 +256,7 @@ function cron() {
if (runCount % 10 == 0) {
ping();
//getLog();
setStatus();
//setStatus();
checkLocks();
updateTestsStatus();
if ( doneStage == 1 ) {
@ -836,46 +276,16 @@ function cron() {
if (runCount % 20 == 0)
updateResults();
if (runCount % 300 == 0)
heartBeat();
//if (runCount % 300 == 0)
// heartBeat();
// 180 seconds, or 3 minutes
if (runCount == 1800)
/*if (runCount == 1800)
runCount = 0;
runCount++;
runCount++; */
}
function heartBeat() {
var m = new Object();
m.query = "heartBeat";
bcastMsg(m);
}
function reloadHTML() {
var http = ajaxConnect();
var retfn = returnfn(http);
ajaxSend(http, "cmd=reloadHTML\n\n",retfn);
}
function poke() {
var http = ajaxConnect();
document.getElementById("pingNodeResp").innerHTML = "";
var dest = document.getElementById("pingNode").value;
var retfn = returnfn(http,
function(resp) {
document.getElementById("pingNodeResp").innerHTML += resp + "<br>";
var retfn = returnfn(http,
function(resp) {
document.getElementById("pingNodeResp").innerHTML += resp + "<br>";
});
ajaxSend(http, "cmd=greet\n\n", retfn, dest);
});
ajaxSend(http, "cmd=ping\n\n", retfn, dest);
}
function setTestStatus(str, col) {
var e = document.getElementById('testStatus');
@ -895,23 +305,6 @@ function getLockType(type) {
return null;
}
function isLocked(lockType, lockName, start, end) {
if (lockType == "range") {
var rlock = getRangeLock(lockname, start, end);
if (rlock)
return rlock.locked;
else return false;
} else {
var locks = getLockType(lockType);
if (locks[lockName] == null)
return false;
else if(locks[lockName].locked != true)
return false;
else
return true;
}
}
function loadTest(tname) {
if(tname == '') {
@ -933,68 +326,6 @@ function loadTest(tname) {
}
function retrieveLock(struct) {
if (struct.type == "test") {
return testLocks[struct.name];
} else if(struct.type == "range") {
var l = getRangeLock(struct.name, struct.start, struct.end);
if (l == null)
error("retrieveLock for range got null");
return l;
}
}
function getLock(type, name, start, end) {
var locks = getLockType(type);
var lockTry;
if (type == "test") {
if(locks[name] == null) {
locks[name] = new Object();
}
lockTry = locks[name];
} else if (type == "range") {
lockTry = getRangeLock(name, start, end);
if (!lockTry) {
error("Cannot get range lock in getLock(" + name +", "+ start + ", " + end + ")");
return;
}
}
lockTry.time = getTime();
lockTry.dlc = dlc+1;
lockTry.name = name;
lockTry.addr = localNodeAddr;
lockTry.type = type;
lockTry.okay = 1;
lockTry.locked = false;
var d = new Date();
lockTry.localTime = d.getTime();
if (type == "test") {
lockTrys[type] = lockTry;
setTestStatus("Acquiring lock for test '" + name + "' " + lockTry.okay + "/" + numberOfNodes + "...", "yellow");
} else if (type == "range") {
lockTrys[type] = lockTry;
setWorkStatus("Acquiring lock for work '" + name + "' (" + lockTry.start + " to " + lockTry.end + ")" + lockTry.okay + "/" + numberOfNodes + "...", "yellow");
}
var m = new Object();
m["query"] = "getLock";
m["type"] = type;
m["name"] = name;
m["time"] = lockTry.time;
m["addr"] = localNodeAddr;
if (type == "range") {
m["start"] = start;
m["end"] = end;
}
bcastMsg(m);
}
function lessTime(t1, t2) {
var t1a = t1.split(":");
var t2a = t2.split(":");
@ -1033,28 +364,6 @@ function cameFirst(a, b) {
}
function locksEqual(a, b) {
if(a == null || b == null)
return false;
if(a['type'] != b['type'])
return false;
if(a['type'] == 'test') {
if (a.name == b.name)
return true;
else
return false;
} else if (a['type'] == "range") {
log("locksEqual? " + a.name + " (" + a.start + " to " + a.end + ") and " + b.name + " (" + b.start + " to " + b.end + ")");
if (a.name == b.name && a.start == b.start && a.end == b.end) {
log("true");
return true;
} else {
log("false");
return false;
}
}
}
function grantLock(resp, lock) {
removeNodeRangeLocks(resp.origin);
@ -1473,24 +782,6 @@ function handleTestUpdate(resp) {
tests[resp['name']]['reducefn'] = decodeStr(resp["reducefn"]);
}
function releaseLock(type) {
var lock = myLocks[type];
myLocks[type] = null;
lock.locked = false;
var m = new Object();
m["query"] = "releaseLock";
m["type"] = type;
m["name"] = lock.name;
if (type == "range") {
m["start"] = lock.start;
m["end"] = lock.end;
}
bcastMsg(m);
}
function handleLockRelease(resp) {
//var locks = getLockType(resp['type']);
@ -1536,57 +827,6 @@ function lookForWork() {
}
}
function getRangeLock(name, start, end) {
log("getRangeLock for (" + name + " from " + start + " to " + end + ")");
if (!rangeLocks[name]) {
log("no locks for " + name + ", so MAKING");
rangeLocks[name] = genRangeCell(name, start, end);
return rangeLocks[name];
}
log("locks exist for " + name + " so SEARCHING forward");
var rlock = rangeLocks[name];
if(end < rlock.start) {
log("Space before first lock, MAKING HERE");
rangeLocks[name] = genRangeCell(name, start, end);
rangeLocks[name].next = rlock;
return rangeLocks[name];
}
while(rlock.next && rlock.start < rlock.end+1) {
log("looking at (" + rlock.start + " to " + rlock.end + ")");
if (rlock.start == start && rlock.end == end) {
log("FOUND IT");
return rlock;
}
if (rlock.end < start && rlock.next.start > end) {
log("GAP between (" + rlock.start + " to " + rlock.end + ") and (" + rlock.next.start + " to " + rlock.next.end + ") where we should be so MAKING THERE");
var nlock = rlock.next;
rlock.next = genRangeCell(name, start, end);
rlock.next.next = nlock;
return rlock.next;
}
rlock = rlock.next;
}
log("SEARCH ended");
if (rlock.start == start && rlock.end == end) {
log("Found it!");
return rlock;
} else {
if (rlock.end < start) {
log("There is space at the end to make what we want");
rlock.next = genRangeCell(name, start, end);
return rlock.next;
} else {
log("search ended after what we wanted, FAIL");
return null;
}
}
}
function makeRangeLock(tlock, suggestedSize) {
suggestedSize--;
@ -1639,6 +879,7 @@ function makeRangeLock(tlock, suggestedSize) {
}
}
/*
function genRangeCell(name, start, end, next) {
var c = new Object();
c.name = name;
@ -1648,7 +889,7 @@ function genRangeCell(name, start, end, next) {
c.locked = false;
c.done = false;
return c;
}
} */
var map_test = null;
var reduce = null;
@ -1851,9 +1092,7 @@ function updateFinalResults() {
var cronID = setInterval("cron()", 100);
getMsgs();
getLog();
function page(p) {

706
cortex.js

@ -0,0 +1,706 @@
/* cortex.js
* PURPOSE
* AUTHOR
* LICENSE
*
* NOTES
*/
/* HTML elements used
* cortexLog - textarea
* statusLabel - div
* numberOfNodes - div
* connections -div
* dlc - div
*/
/***** Ajax Basics *****/
var port = location.href.substring( location.href.substring(7).indexOf(':')+8,
location.href.substring(7).indexOf('/')+7);
// Returns an ajax object
function ajaxConnect() {
var http = null;
if(window.XMLHttpRequest)
http = new XMLHttpRequest();
else if (window.ActiveXObject)
http = new ActiveXObject("Microsoft.XMLHTTP");
return http;
}
/* returns a function that can be passed to http.send
* that runs code fn on successful response
* Kind of a macro function builder
* http: ajax object
* fn: function taking one argument, the resp from the server,
* this function is run on a successful ajax call
* err: OPTIONAL argument that contains a funtion
* to be run if the connection failed
*/
function returnfn(http, fn, err) {
if (!fn)
fn = function(resp) {};
if (!err)
err = function() {};
return function() {
if (http.readyState == 4) {
if (http.responseText == '')
err();
else
fn(http.responseText);
}
};
}
/* Does ajax magic. Makes ajax call with data and sets up
* retfn to be called on response
* forward is the final destination address of the call if
* it is not this local
*/
function ajaxSend(http, data, retfn, forward) {
if (!forward)
forward = '';
http.onreadystatechange = retfn;
http.open('POST', "http://localhost:"+port+"/"+ forward, true);
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.send(data);
}
/***** Utility Functions *****/
// make sure a number is two digits long, padding 0 on front
function d2(str) {
if (str <10)
return "0"+str;
else
return str;
}
// generate the time as a string
function getTime() {
var date = new Date();
return d2(date.getHours()) + ":" + d2(date.getMinutes()) + ":" + d2(date.getSeconds())
}
function extractHost(url) {
// http: or file:
var host = url.substr(5);
while (host.charAt(0) == '/')
host = host.substr(1);
var end = host.indexOf('/');
if (end > 0 )
host = host.substr(0, end);
return host;
}
var logging = true
function log(str) {
//if (logCheckElem == null)
// logCheckElem = document.getElementById("logCheck");
if (logging) { //logCheckElem.checked == true) {
str = getTime() + ": " + str+"\n";
var log = document.getElementById('cortexLog');
if(log)
log.value = str + log.value;
}
}
function error(msg) {
log("ERROR: " + msg);
alert("ERROR: " + msg);
clearInterval(cronID); // Shuts down cron
}
/***** Basic Server Communication *****/
var localNodeAddr = '';
var originURL = 'Unknown Source';
var connected = false;
var numberOfNodes = 0;
var connections = new Array();
var dlc = 0;
var msgQ = new Array();
/* basic ping function for local node
* if successful,
* if we haven't greeted the server, we do,
* otherwise nothing (just a heartbeat)
* if it fails, lets the user know we have lost
* connection to the node server
*/
function ping() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
//log("pong!");
if (!connected) {
connected = true;
greet();
}
},
function(resp) {
connected = false;
var html = "Connection to local Node failed. Try reloading from <a href=\"" + originURL + "\" target=\"window\">" + originURL + "</a>";
stl = document.getElementById('statusLabel');
if (stl)
stl.innerHTML = html;
}
);
//log("ping!");
ajaxSend(http, "cmd=ping\n\n", retfn);
}
function init() {
log("init");
if (connected == false)
return;
numberOfNodes = 1;
if (originURL.substr(0, 4) == "file") {
// we are the first
//numberOfNodes = 1; // ourself
log("Loaded from file");
// now we sit and wait
} else { // it was http, so we were loaded from another node
log("Loaded from " + originURL);
originAddress = extractHost(originURL);
join_network(originAddress);
}
}
/* Greets the server
* so far just gets the server's IP and origin URL
*/
function greet() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
log("greet returned");
var arr = resp.split(" ");
localNodeAddr = arr[0];
originURL = arr[1];
stl = document.getElementById('statusLabel');
if (stl)
stl.innerHTML = "I am <b>" + localNodeAddr + "</b>";
init();
}
);
log("send greet msg");
ajaxSend(http, "cmd=greet\n\n", retfn);
}
// Kill the server
function killServer() {
announceDead(localNodeAddr);
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
// got a resp, server not dead
killServer();
});
ajaxSend(http, "cmd=kill\n\n", retfn);
}
// Get the latest server logs
function getLog() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
var log = document.getElementById('cortexLog');
if (log)
log.value = resp + log.value;
// Since getLog returns (a call back is called later)
// this is tail recursive friendly
getLog();
});
ajaxSend(http, "cmd=getLog\n\n", retfn);
}
/***** Function Registry *****/
var fnreg = new Array;
function registerFn(fnname, fn, preplace) {
path = fnname.split(".");
root = fnreg;
for(i=0; i < path.length-1; i++) {
if (root[path[i]] == undefined)
root[path[i]] = new Array();
root = root[path[i]];
}
if (preplace)
root[path[i]] = fn;
else {
if (root[path[i]] == undefined)
root[path[i]] = [fn, null];
else {
j=0;
while(root[path[i]][j] != null)
j++;
root[path[i]][j] = fn;
root[path[i]][j+1] = null;
}
}
}
/* Finds the chain of functions,
* calls the nth
* stores its return
* calls the nth+1 with the return of the nth as well
* returns the results of the mth
*/
function execFn(name, args) {
root = fnreg;
names = name.split(".");
for (i=0; i< names.length; i++) {
root = root[names[i]];
if (root == undefined)
return false; // ERROR, NO FN
}
i=0;
ret = true;
while(root[i]) {
ret = root[i](args, ret);
i++;
}
return ret;
}
/***** Messeging between nodes *****/
function addMsgHandler(msgName, handlerFN, handlerReplace) {
registerFn("msgHandler." + msgName, handlerFN, handlerReplace);
}
function processMsg(resp) {
log("processMsg: " + resp['query']);
if (!execFn("msgHandler." + resp["query"], resp))
log("Error: Uknnown message '" + resp['query'] + "'");
}
function packObject(m, defaultValue) {
var str = "";
for (var i in m) {
if (m[i] == '')
{
if (defaultValue == null) {
continue;
} else {
m[i] = defaultValue;
}
}
if (i == "results") {
str += i + "=" + packResults(m[i]) + "\n";
} else {
str += i + "=" + m[i] + "\n";
}
}
return str;
}
function sendMsg(m, addr, time, mtype) {
if(time == null)
time = dlc;
if(mtype == null)
mtype = "single";
var str = "cmd=sendMsg\n";
str += "origin=" + localNodeAddr + "\n";
str += "dlc=" + time + "\n";
str += "mtype=" + mtype + "\n";
str += packObject(m);
str += "\n";
//log ("SEND: " + str);
var http = ajaxConnect();
var retfn = returnfn(http, null,
function() {
disconnect(addr);
announceDead(addr);
log("ERROR> message to " + addr + " not delivered: '" + str + "'");
});
//log("sendMsg: " + str);
ajaxSend(http, str, retfn, addr);
}
function bcastMsg(m) {
if (m.query != "heartBeat")
dlc ++;
//log("BCAST conLen: " + connections.length);
for(var i=0; i < connections.length; i++) {
log("bcast "+ i +" " + m.query + " to " + connections[i] + " dlc:" + dlc);
sendMsg(m, connections[i], dlc, "bcast");
//log("back from sendMsg, i:" + i + " conlen:" + connections.length);
}
}
function addMsg(resp) {
for(var i=msgQ.length-1; i>=0; i--) {
if (resp.dlc > msgQ[i].dlc) {
msgQ[i+1] = msgQ[i];
} else {
msgQ[i+1] = resp;
return;
}
}
msgQ[0] = resp;
}
function parseResp(resp) {
var lines = resp.split("\n");
var arr = [];
for(var i=0; i < lines.length; i++) {
//var kv = lines[i].split("=");
var mid = lines[i].indexOf("=");
var kv = new Array();
kv[0] = lines[i].substring(0, mid);
kv[1] = lines[i].substring(mid+1);
if (kv[1] == "true")
kv[1] = true;
else if(kv[0] == "false")
kv[1] = false;
else if (kv[0] == "dlc" ||
kv[0] == "start" ||
kv[0] == "end" ||
kv[0] == "min" ||
kv[0] == "max")
kv[1] = Number(kv[1]);
else if (kv[0] == "results")
kv[1] = unpackResults(kv[1]);
arr[kv[0]] = kv[1];
}
return arr;
}
function queueMsgs(mstr) {
log("GOT messages: " + mstr);
var resps = mstr.split("\n\n");
for(var rcount=0; rcount < resps.length; rcount++) {
var resp = resps[rcount];
if (resp == "")
continue;
resp = parseResp(resp);
if (resp.query == "DLC") {
dlc = resp.dlc;
//var m = new Object();
//m.query = "DLC";
//bcastMsg(m);
} else {
addMsg(resp);
}
}
var s = "QUEUE: "
for (var i =0; i< msgQ.length; i++) {
s += msgQ[i].dlc + " ";
}
log(s);
log("mqlen:" + msgQ.length);
while (msgQ.length>0 && ((msgQ[msgQ.length-1].dlc - 1) <= dlc)) {
var r = msgQ.pop();
log("mdlc: " + r.dlc + " dlc: " + dlc + " mqlen: " + msgQ.length + " type:" + r.mtype + " query: " + r.query);
if (r.mtype == "bcast")
dlc = r.dlc
processMsg(r);
}
}
function getMsgs() {
var http = ajaxConnect();
var retfn = returnfn(http,
function(resp) {
//log("getMsgs: " + resp);
queueMsgs(resp);
// Since getMsgs returns (a call back is called later)
// this is tail recursive friendly
getMsgs();
},
function() {
log("ERROR: getMsg RETURN FAIL");
});
log("getMsgs");
ajaxSend(http, "cmd=getMsgs\n\n", retfn);
}
/***** P2P Network Communication *****/
function connectedTo(addr) {
if (addr == localNodeAddr)
return true;
for(i = 0; i < connections.length; i++) {
if (connections[i] == addr)
return true;
}
return false;
}
function addConnection(addr) {
if(!connectedTo(addr)) {
connections[connections.length] = addr;
numberOfNodes++;
return true;
} else
return false;
}
function join_network(address, bcast) {
if(bcast == null) {
bcast = true;
}
log("join_network -> " + address);
var m = new Object();
m["query"] = "join_network";
m["addr"] = localNodeAddr;
//m["nodes"] = genNodeList();
sendMsg(m, address);
if (bcast == true) {
m = new Object();
m["query"] = "new_network";
m["addr"] = address;
bcastMsg(m);
}
}
function genNodeList() {
var str = "";//localNodeAddr+",";
for (var i =0; i < connections.length; i++) {
str += connections[i] + ",";
}
if (connections.length > 0)
str = str.substring(0,str.length-1);
return str;
}
function advertiseNewNode(addr) {
var m = new Object();
m['query'] = "newNode";
m['addr'] = addr;
bcastMsg(m);
}
function announceDead(addr) {
var m = new Object();
m['query'] = "deadNode";
m['addr'] = addr;
bcastMsg(m);
}
function sendDLC(addr) {
var m = new Object();
m.query = "DLC";
sendMsg(m, addr);
}
function sendWelcome(addrList, addr) {
var m = new Object();
m["query"] = "welcome";
m["addrList"] = addrList;
sendMsg(m, addr);
}
function heartBeat() {
var m = new Object();
m.query = "heartBeat";
bcastMsg(m);
}
function reloadHTML() {
var http = ajaxConnect();
var retfn = returnfn(http);
ajaxSend(http, "cmd=reloadHTML\n\n",retfn);
}
/*
function poke() {
var http = ajaxConnect();
document.getElementById("pingNodeResp").innerHTML = "";
var dest = document.getElementById("pingNode").value;
var retfn = returnfn(http,
function(resp) {
document.getElementById("pingNodeResp").innerHTML += resp + "<br>";
var retfn = returnfn(http,
function(resp) {
document.getElementById("pingNodeResp").innerHTML += resp + "<br>";
});
ajaxSend(http, "cmd=greet\n\n", retfn, dest);
});
ajaxSend(http, "cmd=ping\n\n", retfn, dest);
}
*/
/***** Msg Handlers *****/
function handleNewNode(resp, welcome) {
if (welcome == null)
welcome = false;
var addr = resp.addr;
//log2("handle new node " + addr + " from " + resp.origin);
// handles re adding if reloaded html
//if (!connectedTo(addr))
//{
var ret = genNodeList();
var n = addConnection(addr);
if (welcome == true) {
sendDLC(addr);
sendWelcome(ret, addr);
//sendLocks(addr);
//sendTests(addr);
}
if (n == true) {
//sendReqs(addr);
advertiseNewNode(addr);
}
}
addMsgHandler( "join_network",
function (resp) {
handleNewNode(resp, true);
});
addMsgHandler( "newNode",
function (resp) {
handleNewNode(resp, false);
});
addMsgHandler( "welcome",
function (resp) {
log("Welcome message received");
//var myNodes = genNodeList();
addConnection(resp['origin']);
if (resp['addrList']){
var nodes = resp['addrList'].split(",");
for(var i=0; i < nodes.length; i++){
addConnection(nodes[i]);
}
}
for(var i =0; i< connections.length; i++) {
var addr = connections[i];
if (addr == localNodeAddr)
continue;
advertiseNewNode(addr);
}
});
addMsgHandler( "deadNode",
function (resp) {
var addr = resp['addr'];
log("DISCONNECT " + addr);
// remove from connumberOfNodesnections list
for (var i=0; i < connections.length; i++) {
if (connections[i] == addr) {
connections.splice(i,1);
numberOfNodes--;
break;
}
}
});
addMsgHandler( "new_network",
function (resp) {
join_network(resp["addr"], false);
});
addMsgHandler( "heartBeat",
function (resp) {
// do nothing
});
/***** CRON System *****/
// list of intervals
var crontabs = new Array();
/* add a function to be called