00001 package net.threebit.utils.sosc;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 import java.sql.*;
00022 import java.util.*;
00023 import java.util.logging.*;
00024
00029 public class Hillock {
00030
00034 private static final Logger logger = Logger.getLogger("net.threebit.utils.sosc");
00035
00039 private static boolean enabled = true;
00040
00045 private static final ThreadLocal threadLocal = new ThreadLocal();
00046
00050 private static final LinkedList workQueue = new LinkedList();
00051
00057 public static void startPath (String name) {
00058 if (! enabled) { return; }
00059 Long started = new Long(System.currentTimeMillis());
00060
00061
00062 endPath();
00063
00064 HashMap map = local();
00065 synchronized (map) {
00066 map.put("started", started);
00067 map.put("name", name);
00068 map.put("nodes", new LinkedList());
00069 }
00070
00071 }
00072
00076 public static void endPath() {
00077 if (! enabled) { return; }
00078
00079 Long ended = new Long(System.currentTimeMillis());
00080 Map work = new HashMap();
00081
00082 HashMap map = local();
00083 synchronized (map) {
00084
00085 if (map.get("name") == null) { return ; }
00086
00087
00088 map.put("ended", ended);
00089
00090
00091 work.put("name", map.get("name"));
00092 work.put("started", map.get("started"));
00093 work.put("ended", map.get("ended"));
00094 work.put("nodes", map.get("nodes"));
00095
00096
00097 map.clear();
00098 }
00099
00100 synchronized (workQueue) {
00101 workQueue.add(work);
00102 workQueue.notifyAll();
00103 }
00104
00105 }
00106
00110 public static void startNode (String name) {
00111 if (! enabled) { return; }
00112
00113 Long started = new Long(System.currentTimeMillis());
00114 Map newNode = new HashMap();
00115 newNode.put("name",name);
00116 newNode.put("started", started);
00117
00118 HashMap map = local();
00119 synchronized (map) {
00120 LinkedList nodes = (LinkedList) map.get("nodes");
00121
00122 if (nodes.size() == 0) {
00123
00124 nodes.add(newNode);
00125 return;
00126 }
00127
00128 Map node = (Map) nodes.getLast();
00129 if (node.get("ended") != null) {
00130
00131
00132 nodes.add(newNode);
00133 }
00134 else {
00135
00136
00137
00138 while (true) {
00139 LinkedList children = (LinkedList) node.get("children");
00140 if (children == null || children.size() == 0) {
00141
00142 if (children == null) { children = new LinkedList(); }
00143 children.add( newNode );
00144 node.put("children",children);
00145 break;
00146 }
00147 else {
00148
00149
00150
00151 Map child = (Map) children.getLast();
00152 if (child.get("ended") != null) {
00153
00154 children.add( newNode );
00155 break;
00156 }
00157 else {
00158
00159
00160 node = child;
00161 }
00162 }
00163 }
00164 }
00165 }
00166 }
00167
00171 public static void endNode() {
00172 if (! enabled) { return; }
00173
00174 Long ended = new Long(System.currentTimeMillis());
00175 HashMap map = local();
00176 synchronized (map) {
00177 LinkedList nodes = (LinkedList) map.get("nodes");
00178 if (nodes == null || nodes.size() == 0) { return; }
00179 Map node = (Map) nodes.getLast();
00180 while (true) {
00181 LinkedList children = (LinkedList) node.get("children");
00182 if (children == null || children.size() == 0) {
00183
00184 if (node.get("ended") != null) { throw new RuntimeException(" Assert failed: tried to 'end' a node twice"); }
00185 node.put("ended",ended);
00186 break;
00187 }
00188 else {
00189
00190 Map child = (Map) children.getLast();
00191 if (child.get("ended") == null) {
00192
00193 node = child;
00194 }
00195 else {
00196
00197 node.put("ended",ended);
00198 break;
00199 }
00200 }
00201 }
00202 }
00203 }
00204
00208 public static void node (String name) {
00209 startNode(name);
00210 endNode();
00211 }
00212
00216 public static HashMap local() {
00217 synchronized (threadLocal) {
00218 HashMap m = (HashMap) threadLocal.get();
00219 if (m == null) {
00220 m = new HashMap();
00221 threadLocal.set( m );
00222 }
00223 return m;
00224 }
00225 }
00226
00304 public static DbTool db() throws Exception {
00305 return new DbTool(jdbcDriverClass(), jdbcURL(), jdbcUserName(), jdbcPassword());
00306 }
00307
00309 public static String jdbcDriverClass () { return System.getProperty("net.threebit.utils.sosc.Hillock.jdbcDriverClass"); }
00310
00312 public static String jdbcURL () { return System.getProperty("net.threebit.utils.sosc.Hillock.jdbcURL"); }
00313
00315 public static String jdbcUserName () { return System.getProperty("net.threebit.utils.sosc.Hillock.jdbcUserName"); }
00316
00318 public static String jdbcPassword () { return System.getProperty("net.threebit.utils.sosc.Hillock.jdbcPassword"); }
00319
00320 static {
00321
00322 Thread worker = new Thread() {
00326 public void run() {
00327 try {
00328 LinkedList workList = new LinkedList();
00329 while (true) {
00330
00331
00332 synchronized (workQueue) {
00333
00334
00335 if (workQueue.size() == 0) { workQueue.wait(); }
00336
00337
00338
00339 workList.addAll( workQueue );
00340 workQueue.clear();
00341 }
00342
00343 DbTool db = null;
00344 try {
00345 db = db();
00346 Connection c = db.getConnection();
00347 c.setAutoCommit(false);
00348 c.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE );
00349 PreparedStatement ps = c.prepareStatement(" insert into hillockPaths (name, started, ended) values (?,?,?) ");
00350 PreparedStatement ns = c.prepareStatement(" insert into hillockPathNodes (name, started, ended, path, parent) values (?,?,?,?,?) ");
00351
00352 for (Iterator i = workList.iterator(); i.hasNext(); ) {
00353 Map path = (Map) i.next();
00354
00355 Long pathEnded = (Long) path.get("ended");
00356 LinkedList nodes = (LinkedList) path.get("nodes");
00357
00358 ps.setString(1,(String) path.get("name"));
00359 ps.setTimestamp(2,new Timestamp(((Long) path.get("started")).longValue()));
00360 ps.setTimestamp(3,new Timestamp(((Long) path.get("ended")).longValue()));
00361 ps.execute();
00362 ps.clearParameters();
00363 int pathId = db.getInt(" select max(id) from hillockPaths ");
00364
00365 LinkedList stack = new LinkedList();
00366 stack.addAll( (List) nodes );
00367
00368 while (stack.size() > 0) {
00369 Map node = (Map) stack.removeFirst();
00370
00371 Integer parent = (Integer) node.get("parent");
00372 Long nodeEnded = (Long) node.get("ended");
00373 if (nodeEnded == null) { nodeEnded = pathEnded; }
00374
00375 ns.setString(1, (String) node.get("name"));
00376 ns.setTimestamp(2,new Timestamp(((Long) node.get("started")).longValue()));
00377 ns.setTimestamp(3,new Timestamp(nodeEnded.longValue()));
00378 ns.setInt(4, pathId);
00379 if (parent == null) { ns.setNull(5, Types.INTEGER); }
00380 else { ns.setInt(5, parent.intValue() ); }
00381 ns.execute();
00382 ns.clearParameters();
00383 Integer nodeId = new Integer(db.getInt(" select max(id) from hillockPathNodes; "));
00384
00385
00386
00387 LinkedList children = (LinkedList) node.get("children");
00388 if (children != null) {
00389 LinkedList stackAdd = new LinkedList();
00390 for (Iterator j = children.iterator(); j.hasNext(); ) {
00391 Map child = (Map) j.next();
00392 child.put("parent", nodeId);
00393 stackAdd.add(child);
00394 }
00395 stack.addAll(0, stackAdd);
00396 }
00397 }
00398 }
00399 }
00400 catch (Exception e) {
00401 logger.throwing("HillockWorker","run",e);
00402 }
00403 finally {
00404 try { if (db != null) { db.commit(); } } catch (Exception e) { logger.throwing("HillockWorker","run",e); }
00405 try { if (db != null) { db.close(); } } catch (Exception e) { logger.throwing("HillockWorker","run",e); }
00406 }
00407 workList.clear();
00408 }
00409 }
00410 catch (Exception e) {
00411 enabled = false;
00412 logger.throwing("HillockWorker","run",e);
00413 }
00414 }
00415 };
00416 worker.start();
00417 }
00418 }