hack, life, hack, life

{life,hack}* Some Real Life and Hacking interleaved this week.  I added file-upload via the browser, and then ran into a problem with a misconfigured machine poisoning my Paxos voting.  It’s not Paxos, but I kept endlessly triggering a new round of voting, for no good reason.  That took a day to settle out on a reasonable approach. AllState came out to look at my car, and haul it off to the shop… for 3 weeks.  Ugh.  Bent the door reinforcement beam, so I need a new door.  The Evo’s been a rock-solid reliable car with 120K miles on it (and yes I drive it like an Evo should be), so I’m not going to skimp on the repair.  But 3 weeks driving my family beater van.  Ugh.  Also shot about half a day to talk with the various people (appraiser-scheduler, appraiser, claims manager, body shop).  (fyi – the beater van is a Toyota previa with 165K miles on it, purchased explicitly to train teenage drivers; its slow & reliable and cheap). I got our new hire to do a nice hack for better HTML generation from inside the Cloud.  We want a way to let H2O developers (that’s mostly me, Jan Vitek & the new guy right now) churn out HTML pages with internal stats on the Cloud.  So we need an easy way to write fairly pretty HTML, and also fill-in-the-blanks with some Plain Olde Java Code, and install with no extra files (a single JAR install) and be rock-solid reliable on ANY network & browser config (means: No JavaScript! for those security-conscience networks), and be debugable in-house (means: no downloading large packages e.g. JSPs, etc; been there, done that, watched several good engineers lose their lives debugging that crud).  So what did we come up with? You write a Java class for each unique browser page:

public abstract class HTMLIndex extends HTMLUtils {

You have one big HTML String for the page:

final static String html =
HTML.dtd
+ ""
+ "  "
+ "     Welcome to H2O"
+ CSS.tables
+ "  "
+ ""
+ "

[Surf the local K/V Store](Store.View)"
+ "

The Local Cloud has %subnet_size members"
+ "

[Upload a file](Upload)"

(ugh: not sure how to get code to not auto-html-ize here.  It’s a plain Java String with plain HTML embedded in it).  Notice a few boilerplate strings already folded in, including some CSS.  Notice I got href links in there, other html and that funny %subnet_size token.  This isn’t the whole HTML string for this page, more later.  But first: You write the fill-in-the-blanks function, filling in the %subnet_size token with H2O.Cloud._subnet_size:

public static H2ONanoHTTP.Response serve( H2ONanoHTTP server, String uri, Properties header ) {
  String source = html;
...
  source = replace(source,"subnet_size",H2O.Cloud._subnet_size);
  return server.wrap(source);
}

Simple, dumb, frightfully easy to use.  I’m sure it’s been thought of a zillion times before.  (and thanks to NanoHTTP for a 1-file web server)  Oh, and for tables your HTML string looks like:

final static String html =
    + "

The Local Cloud has %subnet_size members"
    + "

[Upload a file](Upload)"
    + "

"
    + ""
    + "%tableRow{"
    + "  "
    + "    "
    + "    "
    + "    "
    + "    "
    + "    "
    + "    "
    + "    "
    + "  "
    + "}"
    + "

| Local Nodes | CPUs | FreeMem | TotalMem | MaxMem | FreeDisk | MaxDisk |
| [%node](Node=%host) | %num_cpus | %free_mem | %tot_mem | %max_mem | %free_disk | %max_disk |

n"

And the fill-in code:

    for (H2ONode h2o : H2O.Cloud._members.values()) {
      // only replace the table line, we will insert the values later one by one
      source = multiReplace(source, "tableRow");
      String host = h2o._inet.getHostAddress();
      source = replace(source,"rowClass",(alt++&1)==0 ? "rowOdd" : "rowEven");
      source = replace(source,"host",host);
      source = replace(source,"node",host);
      source = replace(source,"num_cpus" ,            h2o.get_num_cpus () );
      source = replace(source,"free_mem" ,toMegabytes(h2o.get_free_mem ()));
      source = replace(source,"tot_mem"  ,toMegabytes(h2o.get_tot_mem  ()));
      source = replace(source,"max_mem"  ,toMegabytes(h2o.get_max_mem  ()));
      source = replace(source,"free_disk",toMegabytes(h2o.get_free_disk()));
      source = replace(source,"max_disk" ,toMegabytes(h2o.get_max_disk ()));
    }
    source = remove(source,"tableRow");

That ‘replace’ function does the obvious thing.  Very nice.  A for-loop in the Java-code to fill in the HTML table.  Clean, simple to use.  Yes I am stupidly happy about this hack.  Thanks Petr. More Real Life: changing jobs means changing insurance.  I COBRA’d the skipped month between jobs, but it doesn’t kick immediately (instead it kicks in retroactively).  This means all those bills I take for this entire month have to be re-filed with each individual provider so they can be back-billed to COBRA.  Also, all my providers need to know about the COBRA this month, and about the new plan next month.  TOTAL pain in the butt.  My teenager crushes her glasses weekly, typically using her face to cushion  her headlong rolling dive in the grass, or to put that wrestling move over on her siblings, or to test the power of belt-sanders & power tools, stuff like that.  I glad she’s enjoying life vigorously but there’s a limit to how far an epoxy repair job can go, so I finally had to pony up for another $400 pair of glasses… during the COBRA-hell-month.  My youngest is in for another round of orthodontics.  My cholesterol prescription ran out.  My colonoscopy (after insurance) is running $600.  And so on: each is another shot at my wallet when I’m in the 1-month no-paycheck limbo, and the fact that COBRA cashed my premium check is just ironic. My hack(s)?  First was a major cleanup of my async RPC stuff; greenfield coding is great and all that, but after some QA & a little hammering it needed to go from “fun hack” to “production ready” which needs a whole ‘nother level of thinking.  I’ll save the other major hack for next blog. Last bit of ‘life’: I’ve been listening to the music group Bond.  Awesome stuff and easy on the eyes…  😉 Cliff