tag:blogger.com,1999:blog-44711096631929426742024-03-05T20:09:08.038-06:00Many Cups of CoffeeDiscussion of software development pragmatics in the space of java enterprise development, the confluence of errors that inevitably plague such projects, and the many cups of coffee required to make it through the day.Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-4471109663192942674.post-44912522739835170312016-07-04T13:46:00.001-05:002016-07-04T13:47:59.329-05:00Guavate: tiny library bridging Guava and Java8<p>
Java8 is great and adds some useful abstractions to the JDK that have found popularity in the Java community via the wonderful <a href="https://github.com/google/guava">Guava commons library</a> from Google. Group discussion indicates that there will be a Guava version <a href="https://groups.google.com/d/msg/guava-discuss/ZRmDJnAq9T0/-HExv44eCAAJ">soon</a> that requires Java 8 and closes the gap between Guava and Java8. However, until such a time, the rest of us using Guava+Java8 need a tiny shim library for things like Collector implementation's that produce Guava Immutable collections.
</p>
<p>
As always <a href="https://groups.google.com/d/msg/guava-discuss/oWv4ee0BCHc/2HIyXjf7JSwJ">Stephen Colebourne threw together</a> exactly such a tiny utility class: <a href="https://github.com/OpenGamma/Strata/blob/master/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java">Guavate</a>. Unfortunately, it's buried inside of Strata, and for all of my projects I don't want to depend on Strata just for this tiny shim. Also, I have a few Java8 shim methods myself that could use a home. Therefore, <a href="https://github.com/steveash/guavate">I forked Colebourne's Guavate</a> and have released it to Maven Central for anyone else that wants to add this tiny shim library to their Java8 projects:
</p>
<script type="syntaxhighlighter" class="brush: xml"><![CDATA[
<dependency>
<groupId>com.github.steveash.guavate</groupId>
<artifactId>guavate</artifactId>
<version>1.0.0</version>
</dependency>
]]></script>
<p>
There are Collector implementations for each of the Immutable collections:
</p>
<script type="syntaxhighlighter" class="brush: java"><![CDATA[
List<String> inputs = Lists.newArrayList("a", "b", "c");
ImmutableSet<String> outputs = inputs.stream()
.map(String::toUpperCase)
.filter(it -> !it.startsWith("b"))
.collect(Guavate.toImmutableSet());
// outputs is an immutable set of "a" and "c"
]]></script>
<p>
There are also some convenient methods for collecting to maps from Map.Entry (and Common-Lang3's Pair as it implements Entry):
</p>
<script type="syntaxhighlighter" class="brush: java"><![CDATA[
Map<String, Integer> inputs = ImmutableMap.of(
"bob", 1,
"jon", 2,
"mary", 3
);
Map<String,Integer> outputs = inputs.entrySet().stream()
.map(e -> Pair.of(e.getKey().toUpperCase(), e.getValue()))
.collect(Guavate.entriesToMap());
// outputs is a map of BOB:1, JON:2, MARY:3
]]></script>
<p>
Converting an arbitrary iterable into a stream (which should've been in the JDK to begin with):
</p>
<script type="syntaxhighlighter" class="brush: java"><![CDATA[
Iterable<String> values = // ...
Stream<String> streamVals = Guavate.stream(values);
]]></script>
<p>
and converting an Optional into a stream of zero or one element:
</p>
<script type="syntaxhighlighter" class="brush: java"><![CDATA[
Optional<String> maybe = // ...
Stream<String> stream = Guavate.stream(maybe);
]]></script>
<br/>
Checkout the GitHub project page to follow for updates or submit pull requests with your own Java8 additions: <br/>
<a href="https://github.com/steveash/guavate">https://github.com/steveash/guavate</a>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-10805011168710832202015-12-19T10:43:00.000-06:002015-12-19T10:43:50.129-06:00Some neat Spring4 and Spring Boot featuresHere's a few slides on some of the Spring4 and Spring Boot features that I used on a recent project that are interesting. This is not really an introduction to Spring Boot -- but just highlighting a few features. This talk was an internal talk for our team - thus it is informal and brief. But in case anyone else has any interest:
<p/>
<iframe src="https://docs.google.com/presentation/d/1Dlamdl868CXAh301rH-AI0ugaWCUqv_ld6Eu9TvPX_A/embed?start=false&loop=false&delayms=3000" frameborder="0" width="480" height="389" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-73042195730178566272015-09-01T02:34:00.000-05:002015-09-01T23:23:49.580-05:00Whirlwind tour of data scienceI'm giving a talk to the local <a href="http://www.meetup.com/memphis-technology-user-groups/events/223473111/">Data Science / Machine Learning meetup</a>. The topic is a shallow tour of data science topics including tasks and methods. This is a new group and many of the attendees do not have a data science background but are interested. Therefore, I thought a talk that went through the highlights would be useful. Not only is the tour a whirlwind, but creating the slides was a bit of a rush job in the wee hours of the night, so please excuse typos, factual errors, slander, blatent malicious lies, etc.
<br/>
<br/>
Presentation is: <a href="http://slides.com/steveash/datascience/">http://slides.com/steveash/datascience/</a>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-34817669088971700392015-08-06T18:40:00.000-05:002015-08-06T18:40:48.045-05:00Streaming standard deviation and replacing values<p>I'm working on a problem right now where I need to calculate the mean and standard deviation of a value in a streaming fashion. That is I receive a stream of events that generate data points and I need to calculate standard deviation without retaining all of the data points in memory. This has been covered ad nauseam in the literature -- I will just briefly summarize.</p>
<p>Ignoring the whole sample vs population correction, variance can be naively computed as the <i>mean </i>of the squares minus the <i>square</i> of the mean:
$$\sigma^2 = \frac{\sum\nolimits_{i=0}^n x_{i}^2}{n} - \left( \frac{\sum\nolimits_{i=0}^n x_i}{n} \right)^2$$
<p>But this approach is plagued with <a href="http://www.johndcook.com/blog/standard_deviation/">well-documented stability and overflow problems</a>. There are two other methods that I've run across: <a href="http://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/">Welford's</a> which is by far the most published and <a href="http://blogs.sas.com/content/iml/2012/01/18/compute-a-running-mean-and-variance.html">Ross's</a> which appears to be an independent derivation.
<p>Welford's method keeps track of the count, the mean, and a sum of the squared differences from the mean as it goes like this:</p>
<pre class="brush: java">
public static double welford(DoubleStream values) {
OfDouble iter = values.iterator();
if (!iter.hasNext()) return 0;
double m = iter.nextDouble();
double s = 0;
int count = 1;
while (iter.hasNext()) {
double x = iter.nextDouble();
count += 1;
double prevM = m;
double delta = x - prevM;
m = prevM + (delta / count);
s += (delta * (x - m));
}
return Math.sqrt(s / (count - 1));
}
</pre>
<p>This works, but what happens if you need to replace a value in the data population with another? Here's a scenario: you want to track the number of times people click on your ads. You store some counter per person and increment it every time someone clicks something. If you group those people into segments like "people from USA", "people from Canada" you might want to keep track of what is the average number of ad clicks per day for someone from Canada? and what is the standard deviation for this average? The data population that you are averaging and calculating the stddev for is the number of clicks per day -- but you dont want to run big expensive queries over all of your people records.</p>
<p>A solution would be: when you get an ad click for Steve, you notice that his previous counter value for today was 3 and you're about to make it four. So you previously accounted for a 3 in the group's mean/stddev calculation. Now you just need to remove the 3 and add the 4.</p>
<p>I didn't find a solution to this at first glance...though I did as I was writing this blog post >:| (more on that later). Here's one approach to replacing a value:</p>
<pre class="brush: java">
public void replace(double oldValue, double newValue) {
if (count == 0) {
add(newValue); // just add it new
return;
}
// precisely update the mean
double prevM = m;
double sum = m * count;
sum -= oldValue;
sum += newValue;
m = sum / count;
s -= ((oldValue - prevM) * (oldValue - m));
s += ((newValue - prevM) * (newValue - m));
}
</pre>
<p>Since we have the mean and count we can <i>precisely</i> update the mean. Now we just back out the previous contribution to the sum of delta variance and add in the new. The means at the point of removal will be slightly different so it makes sense that this method would introduce a slight error. To measure the amount of error, I ran some simulations. I tried many variations on population size, modification count, drifting the mean over the modifications to simulate underlying data drift. Generally the error was very low -- keeping 7+ digits in agreement, which in most cases was an error < 10^-\7</p>
<p>Here is the output of a simulation with a data population size 1000 that went through 1 million random replacements. The mean was originally 50 and drifted up to 100,000 - so significant change in the underlying population. The final value calculated by the above "replacement" was 102.7715945 and the exact actual value was 102.7715947, which agrees to 9 digits. Here is output every 100,000 modifications. You can see that the error increases but very slowly.</p>
<pre>
Real 101.77630883973457 appx 101.77630883877222 err 9.455489999879566E-12
Real 108.95998062305821 appx 108.95998062134508 err 1.5722586742180294E-11
Real 111.47312659988472 appx 111.47312659954882 err 3.0133000046629816E-12
Real 104.24140320017268 appx 104.2414031714818 err 2.7523494838677614E-10
Real 108.11933587379178 appx 108.11933580405407 err 6.450068193382661E-10
Real 109.42545081143268 appx 109.42545070096071 err 1.0095637905406985E-9
Real 108.65152218111096 appx 108.65152203715265 err 1.3249544449723884E-9
Real 103.34165956961682 appx 103.3416593951618 err 1.6881384078315523E-9
Real 102.77159471215656 appx 102.77159451350815 err 1.9329116036550036E-9
</pre>
<p>As I was publishing this I found <a href="http://lingpipe-blog.com/2009/07/07/welford-s-algorithm-delete-online-mean-variance-deviation/">another approach</a> for deleting values from Welford's standard deviation. This doesn't update the mean precisely, and I'm guessing that that introduces just a little more error. Running the exact same data through his approach shows just slightly more error:
<pre>
Real 101.77630883973457 appx 101.77630883769623 err 2.0027587650921094E-11
Real 108.95998062305821 appx 108.95998062710102 err 3.710356226429184E-11
Real 111.47312659988472 appx 111.4731267005022 err 9.026165066977801E-10
Real 104.24140320017268 appx 104.2414035377799 err 3.2387056223459957E-9
Real 108.11933587379178 appx 108.11933681146603 err 8.672586049942834E-9
Real 109.42545081143268 appx 109.42545279287886 err 1.8107726862840628E-8
Real 108.65152218111096 appx 108.65152556310522 err 3.112698463527759E-8
Real 103.34165956961682 appx 103.34166620916582 err 6.424852307519515E-8
Real 102.77159471215656 appx 102.77160676463879 err 1.1727444988401424E-7
</pre>
<p>I put my <a href="https://gist.github.com/steveash/f9fabd193f19400f063c">code in a gist</a> in case anyone wants to snag it.</p>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-23909043689645603542015-06-07T19:36:00.000-05:002015-06-07T19:36:13.836-05:00Using ELK (elasticsearch + logstash + kibana) to aggregate cassandra and spark logsOn one of my current projects we are using Cassandra and Spark Streaming to do some somewhat-close-to-real time analytics. The good folks at <a href="http://www.datastax.com/" target="_blank">Datastax</a> have built a commercial packaging (Datastax Enterprise, aka DSE) of Cassandra and Spark that allow you to get this stack up and running with relatively few headaches. One thing the Datastax offering does not include is a way to aggregate logs across all of these components. There are quite a few processes running across the cluster, each producing log files. Additionally, spark creates log directories for each application and driver program, each with their own logs. Between the high count of log files and the fact that work happens on all the nodes different each time depending on how the data gets partitioned- it can become a huge time sink to hunt around and grep for the log messages that you care about.<br />
<br />
Enter the ELK stack. ELK is made up of three products:
<br />
<br />
<ul>
<li><b><a href="https://www.elastic.co/products/elasticsearch" target="_blank">Elasticsearch</a></b> - a distributed indexing and search platform. It provides a REST interface on top of a fancy distributed, highly available full text and semi-structured text searching system. It uses Lucene internally for the inverted index and searching.</li>
<li><b><a href="https://www.elastic.co/products/logstash" target="_blank">Logstash</a></b> - log aggregator and processor. This can take log feeds from lots of different sources, filter and mutate them, and output them somewhere else (elasticsearch in this case). Logstash is the piece that needs to know about whatever structure you have in your log messages so that it can pull the structure out and send that semi-structured data to elasticsearch. </li>
<li><b><a href="https://www.elastic.co/products/kibana" target="_blank">Kibana</a></b> - web based interactive visualization and query tool. You can explore the raw data and turn it into fancy aggregate charts and build dashboards.</li>
</ul>
<div>
All three of these are open-source, Apache 2 licensed projects built by <a href="https://www.elastic.co/" target="_blank">Elastic</a>, a company founded by the folks that wrote Elasticsearch and Lucene. They have all of the training, professional services, and production support subscriptions, and a stable of products with confusing names that you aren't quite sure if you need or not...</div>
<div>
<br /></div>
<div>
So how does this look at a high level? Spark and Cassandra run co-located on the same boxes. This is by design so that your Spark jobs can use RDDs that use a partitioning scheme that is aware of Cassandra's ring topology. This can minimize over-the-wire data shuffles, improving performance. This diagram shows at a high level where each of these processes sit in this distributed environment:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKgYIdbb-wYCAS5W62wjtfwcx-dzJjiO5ZKf2ANVoBorEHozd3hyxpBhT-1SxOjRQYJReanrOd3grDiul9dOCFjtVELkTJG-N6_KF5jSNlcYtne3cOpMwLQUBGudnmwhuzpMaeEn-RcDQ/s1600/spark_cass_elk.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKgYIdbb-wYCAS5W62wjtfwcx-dzJjiO5ZKf2ANVoBorEHozd3hyxpBhT-1SxOjRQYJReanrOd3grDiul9dOCFjtVELkTJG-N6_KF5jSNlcYtne3cOpMwLQUBGudnmwhuzpMaeEn-RcDQ/s400/spark_cass_elk.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
This only depicts two "analytics" nodes and one ELK node, but obviously you will have more of each. Each analytics node will be producing lots of logs. Spark writes logs to:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul>
<li>/var/log/spark/worker</li>
<li>/var/lib/spark/worker/worker-0/app-{somelongtimestamp}/{taskslot#}</li>
<li>/var/lib/spark/worker/worker-0/driver-{somelongtimestamp}</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: left;">
To collect all of these logs and forward, there is an agent process on each node called Logstash-Forwarder that is monitoring user specified folders for new log files and is shipping them over via TCP to the actual logstash server process running on the ELK node. Logstash receives these incoming feeds, parses them and sends them to elasticsearch. Kibana responds to my interactive queries and delegates all of the search work to elasticsearch. Kibana doesn't store any results internally or have its own indexes or anything.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Others have already done a good job <a href="https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-4-on-centos-7" target="_blank">explaining how to setup ELK</a> and <a href="https://www.timroes.de/2015/02/07/kibana-4-tutorial-part-1-introduction/" target="_blank">how to use Kibana</a>, and therefore I won't repeat all of that here. I will only highlight some of the differences, and share my Logstash configuration files that I had to create to handle the out-of-the-box log file formats for Cassandra and Spark (as packaged in DSE 4.7 at least).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I installed elasticsearch from the repo, which already created the systemd entries to run it as a service. Following the ELK setup link above, I created systemd entries for logstash and kibana. I also created a <a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-logstash-forwarder-service" target="_blank">systemd unit file for the logstash-forwarder</a> running on each analytics node. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The logstash-forwarder needs to be configured with all of the locations that spark and cassandra will put logfiles. It supports glob syntax, including recursive folder searches like "whatever/**/*.log", but I ended up not using that because it was duplicating some of the entries due to a wonky subfolder being created under the spark driver program log folder called cassandra_logging_unconfigured. My forwarder configuration picks up all of the output logs for the workers, the applications, and the driver and creates a different <b>type</b> for each: <b>spark-worker</b> for generic /var/log spark output, <b>spark-app</b> for app-* log folder, <b>spark-driver</b> for the driver programs (where most of the interesting logging happens). <a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-logstash-forwarder-conf" target="_blank">My logstash-forwarder.conf</a> is in the gist.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
For logstash I setup a few files as a pipeline to handle incoming log feeds:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul>
<li><a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-00_input-conf" target="_blank">00_input.conf</a> - sets up the lumberjack (protocol the forwarder uses) port and configures certs </li>
<li><a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-01_cassandra_filter-conf" target="_blank">01_cassandra_filter.conf</a> - parses the logback formats that DSE delivers for cassandra. Im not sure if vanilla open-source cassandra uses the same by defualt or not. There are two formats between sometimes there is an extra value in here -- possibly from the logback equivalent of NDC.</li>
<li><a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-02_spark_filter-conf" target="_blank">02_spark_filter.conf</a> - parses the logback formats that DSE delivers for spark. I see there are two formats I get here as well. Sometimes with a line number, sometimes without.</li>
<li><a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-07_last_filter-conf" target="_blank">07_last_filter.conf</a> - this is a multiline filter that recognizes java stacktraces and causes them to stay with the original message</li>
<li><a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc#file-10_output-conf" target="_blank">10_output.conf</a> - sends everything to elasticsearch</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: left;">
All of my configuration files are available through the links above <a href="https://gist.github.com/steveash/82f5f3bd10b1a6eb7bcc" target="_blank">in this gist</a>. Between the linked guides above and the configuration here that should get you going if you need to monitor cassandra and spark logs with ELK!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<b>Quick tip:</b> While you're getting things configured and working, you might need to kill the currently indexed data and resend everything (so that it can reparse and re-index). The logstash-forwarder keeps a metadata file called <span style="font-family: Courier New, Courier, monospace;">.logstash-forwarder</span> in the working directory where you started the forwarder. If you want to kill all of the indexed data and resend everything, follow these steps:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ol>
<li>Kill the logstash-forwarder: <br /><span style="font-family: Courier New, Courier, monospace;">sudo systemctl stop logstash-forwarder</span></li>
<li>Delete the logstash-forwarder metadata so it starts from scratch next time: <br /><span style="font-family: Courier New, Courier, monospace;">sudo rm /var/lib/logstash-forwarder/.logstash-forwarder</span></li>
<li>If you need to change any logstash configuration files, do that and then restart logstash: <br /><span style="font-family: Courier New, Courier, monospace;">sudo systemctl restart logstash</span></li>
<li>Delete your existing elastic search indexes (be careful with this!): <br /><span style="font-family: Courier New, Courier, monospace;">curl -XDELETE 'http://<elasticsearch-host>:9200/logstash-*'</elasticsearch-host></span></li>
<li>Start the logstash-forwarder again:<br /><span style="font-family: Courier New, Courier, monospace;">sudo systemctl start logstash-forwarder</span></li>
</ol>
Also note that by default the logstash-forwarder will only pickup files less than 24 hours old. So if you're configuring ELK and playing with filters on stagnant data, make sure at least some files are touched recently so it will pick them up. Check out the log file in /var/log/logstash-forwarder to see if it's skipping particular entries. You can also run the logstash-forwarder with -verbose to see additional debug information.<div>
<br /></div>
<div>
<b>Quick tip:</b> use the wonderfully useful <a href="http://grokdebug.herokuapp.com/">http://grokdebug.herokuapp.com/</a> to test out your grow regex patterns to make sure they match and pull out the fields you want.<br /><br />
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-41385519645062502014-08-24T15:20:00.003-05:002014-08-24T15:20:51.041-05:00Bushwhacker to help team members debug unit test failuresRight now I'm working on a project with a few people who have never worked in Java before. There have been times where they'll experience some problem that they can't easily figure out. They send me the stack trace and instantly I know what the problem is. I wanted a simple way to automate this.<br />
<br />
So I created <b><a href="https://github.com/steveash/bushwhacker">Bushwhacker</a></b> a simple library to help provide more helpful messages at development time. Senior members of the team edit and maintain a simple xml file that describes rules to detect particular exceptions and either replace or enhance the exception message in some way. The rules are fairly sophisticated -- allowing you to, for example, only detect IllegalArgumentException if it was throw from a stack frame from MyClassWhatever. Since the xml rules file is read off of the classpath, you can version the XML file along with your source code (in src/test/resources for example). And you can even maintain multiple rules files for different modules and compose them all together. So if there are common pitfalls in your corporate "commons" module you can keep the bushwhacker rules for it there, and put your team's additional rules in your module.<br />
<br />
It's on Maven Central Repo so its easy to add to your project. Check out usage instructions here: <a href="https://github.com/steveash/bushwhacker">https://github.com/steveash/bushwhacker</a>
<br />
<br />
Here's a few of the rules that we're using right now:<br />
<br />
<br />
<script class="brush: xml" type="syntaxhighlighter"><![CDATA[
<exception>
<matches>
<exceptionclass>org.springframework.beans.factory.NoSuchBeanDefinitionException</exceptionClass>
<calledfrom>org.springframework.transaction.aspectj.AbstractTransactionAspect*</calledFrom>
<messagematches>.*No qualifying bean of type.*PlatformTransactionManager.*</messageMatches>
</matches>
<action>
<addhint>
This usually happens when your unit test extends from the wrong test fixture. Since you
are using something that needs the database, extend from ExternalDbFraudTestFixture. You
might not even realize that your trying to use the database, but some code is going over an
@Transactional which is causing it to try and use the database.
</addHint>
</action>
</exception>
<exception>
<matches>
<exceptionclass>java.lang.IllegalArgumentException</exceptionClass>
<calledfrom>org.jooq.impl.Utils*</calledFrom>
<messagematches>.*Field.*is not contained in Row.*</messageMatches>
</matches>
<action>
<addhint>
Check the jooq query's select list- you probably forgot to add a field to the SELECT. A jooq query is just
like a SQL query you select certain columns and you get a result set of rows. If you ask that resultset for
a column that isn't included in the SELECT list then you will see this exception.
</addHint>
</action>
</exception>
]]></script>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-78314014699225606972014-06-24T14:58:00.000-05:002014-06-24T14:58:07.949-05:00Single record UPSERT in MSSQL 2008+I guess I just don't use SQL's MERGE statement enough to remember its syntax off the top of my head. When I look at the <a href="http://msdn.microsoft.com/en-us/library/bb510625.aspx">Microsoft documentation</a> for it, I can't find just a simple example to do a single record UPSERT. When I google, I don't get any brief blog posts that show it. So here's a brief one to add to the pile:
<br />
<br />
Table:<br />
<br />
<b>DATA_VERSION</b><br />
<b>datakey varchar(16) not null primary key,</b><br />
<b>seqno bigint not null,</b><br />
<b>last_updated datetime not null</b><br />
<b><br /></b>
The table just keeps track of sequence numbers for things identified by 'datakey'. The first time we want to increment a value for a key we need to insert a new record with starting with seqno = 1 then every time after that we just want to increment the existing row.<br />
<br />
MSSQL:
<br />
<script type="syntaxhighlighter" class="brush: sql"><![CDATA[
-- the particular key you want to update is 'somekey'
MERGE DATA_VERSION t
USING (SELECT 'somekey' as datakey) as s
on (t.datakey = s.datakey)
WHEN MATCHED THEN
UPDATE SET t.version = t.version + 1, t.last_updated = getdate()
WHEN NOT MATCHED THEN
INSERT (datakey, version, last_updated) VALUES ('somekey', 1, getdate())
;
]]></script>
Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-54618269713914212932014-03-30T16:08:00.000-05:002014-03-30T16:08:08.006-05:00Spring Test Context Caching + AspectJ @Transactional + Ehcache painAre you using AspectJ @Transactionals and Spring? Do you have multiple SessionFactory's maybe one for an embedded database for unit testing and one for the real database for integration testing? Are you getting one of these exceptions?
<br />
<blockquote>
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.service.UnknownServiceException: Unknown service requested </blockquote>
or
<br />
<blockquote>
java.lang.NullPointerException
at net.sf.ehcache.Cache.isKeyInCache(Cache.java:3068)
at org.hibernate.cache.ehcache.internal.regions.EhcacheDataRegion.contains(EhcacheDataRegion.java:223)</blockquote>
Then you are running in to a problem where multiple, cached application contexts are stepping on each other. This blog post will describe some strategies to deal with the problems that we have encountered.
<br /><br />
<h3>Background</h3>
<br />
Spring's Text Context framework by default tries to minimize the number of times the spring container has to start by caching the containers. If you are running multiple tests that all use the same configuration, then you will only have to create the container once for all the tests instead of creating it before each test. If you have 1000's of tests and the container takes 10-15 seconds to startup, this makes a real difference in build/test time.<br />
<br />
This only works if everyone (you and all of the libraries that you use) avoid static fields (global state), and unfortunately there are places where this is difficult/impossible to avoid -- even spring violates this! A few places that have caused us problems:
<br />
<ul>
<li>Spring AspectJ @Transactional support</li>
<li>EhCache cache managers</li>
</ul>
Aspects are singletons by design. Spring uses this to place a reference to the <span style="font-family: Courier New, Courier, monospace;">BeanFactory</span> as well as the <span style="font-family: Courier New, Courier, monospace;">PlatformTransactionManager</span>. If you have multiple containers each with their "own" AnnotationTransactionAspect, they are in fact sharing the AnnotationTransactionAspect and whichever container starts up last is the "winner" causing all kinds of unexpected hard to debug problems.
<br />
<br />
Ehcache is also a pain here. The ehcache library maints a static list of all of the cache managers that it has created in the VM. So if you want to use multiple containers, they will all share a reference to the same cache.
Spring Test gives you a mechanism to indicate that this test has "dirtied" the container and that it needs to be created. This translates to destroying the container after the test class is finished. This is fine, but if your container has objects that are shared by the other containers, then destroying that shared object breaks the other containers.
<br /><br />
<h3>Solutions</h3>
<br />
The easiest solution is to basically disable the application context caching entirely. This can be done simply by placing <span style="font-family: Courier New, Courier, monospace;">@DirtiesContext</span> on every test or (better) you probably should use super classes ("abstract test fixtures") to organize your tests anyways, in which case just add <span style="font-family: Courier New, Courier, monospace;">@DirtiesContext</span> on the base class. Unfortunately you also lose all of the benefit of caching and your build times will increase.
<br />
<br />
There is no general mechanism for the spring container to "clean itself up", because this sharing of state across container is certainly an anti-pattern. The fact that they themselves do it (<span style="font-family: Courier New, Courier, monospace;">AnnotationTransactionAspect</span>, <span style="font-family: Courier New, Courier, monospace;">EhCacheManagerFactoryBean.setShared(true)</span>, etc.) is an indication that perhaps they should add some support. If you want to keep caching, then step 1 is making sure that you don't use any "static field" singletons in your code. Also make sure that any external resources that you write to are separated so that multiple containers can co-exist in the same JVM.<br />
<br />
To address the AspectJ problem, the best solution that I have found is to create a TestExecutionListener that "resets" the AnnotationTransactionAspect to point to the correct bean factory and PTM before test execution. The code for such a listener is <a href="https://gist.github.com/steveash/9878621">in this gist</a>.<br />
<br />
To then use the listener you put <span style="font-family: Courier New, Courier, monospace;">@TestListeners</span> on your base class test fixture so that all tests run with the new listener. Note that when you use the <span style="font-family: Courier New, Courier, monospace;">@TestListeners</span> annotation you then have to specify all of the execution listeners, including the existing Spring ones. There is an example <a href="https://gist.github.com/steveash/9878621#file-sampletestfixture-java">in the gist</a>.<br />
<br />
The workaround for Ehcache is to not allow CacheManager instances to be shared between containers. To do this, you have to ensure that the cache managers all have unique names. This is actually pretty easy to configure.
<br/>
<script src="https://gist.github.com/steveash/9879696.js"></script>
<br/>
<br />
<h3>Related Issues</h3>
<br />
Here are some links to spring jira issues covering this problem:<br />
<a href="https://jira.spring.io/browse/SPR-6121">https://jira.spring.io/browse/SPR-6121</a><br />
<a href="https://jira.spring.io/browse/SPR-6353">https://jira.spring.io/browse/SPR-6353 </a><br />
<br />Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-23700850402961120952013-09-05T00:43:00.000-05:002013-09-05T00:43:38.893-05:00Java final fields on x86 a no-op?I have always enjoyed digging in to the details of multi-threaded programming, and always enjoy that despite reading for years about CPU memory consistency models, wait-free and lock-free algorithms, the java memory model, java concurrency in practice, etc. etc. -- I still create multi-threaded programming bugs. It's always a wonderfully humbling experience that reminds me how complicated of a problem this is.
<br/><br/>
If you've read the JMM, then you might remember that one of the areas they strengthened was the guarantee of visibility of <i>final</i> fields after the constructor completes. For example,
<br/>
<pre>
public class ClassA {
public final String b;
public ClassA(String b) {
this.b = b;
}
}
...
ClassA x = new ClassA("hello");
</pre>
<br/>
The JMM states that every thread (even threads other than the one that constructed the instance, x, of ClassA) will <i>always</i> observe x.b as "hello" and would never see a value of null (the default value for a reference field).
<br/><br/>
This is really great! That means that we can create immutable objects just by marking the fields as final and any constructed instance is automatically able to shared amongst threads with no other work to guarantee memory visibility. Woot! The flip-side of this is that if ClassA.b were <b>not</b> marked as final then you would have no such guarantee. And other threads could observe a x.b == null result (if no other "safe publication" mechanisms were employed to get visibility)
<br/><br/>
Well when they created the new JMM, everyone's favorite JCP member, Doug Lea, created a <a href="http://g.oswego.edu/dl/jmm/cookbook.html">cookbook</a> to help JVM developers implement the new memory model rules. If you read this, then you will see that the "rules" state that JIT compilers should emit a <i>StoreStore</i> memory barrier, right before the constructor returns. This <i>StoreStore</i> barrier is a kind of "memory fence". When emitted in the assembly instructions, it means that no memory writes (stores) <i>after</i> the fence can be re-ordered before memory writes that appear <i>before</i> the fence. Note that it doesn't say anything about reads -- they can "hop" the fence in either direction.
<br/><br/>
So what does this mean? well if you think about what the compiler does when you call a constructor:
<pre>
String x = new ClassA("hello");
get's broken down in to pseudo-code steps of:
1. pointer_to_A = allocate memory for ClassA
(mark word, class object pointer, one reference field for String b)
2. pointer_to_A.whatever class meta data = ...
3. pointer_to_A.b = address of "hello" string
4. emit a StoreStore memory barrier per the JMM
5. x = pointer_to_A
</pre>
The StoreStore barrier at step 4 ensures that any writes (such as class meta-data and to field b are <i>not</i> re-ordered with the write to x on step 5. This is what makes sure that if x is visible to any other threads -- that that other thread can't see x without seeing x.b as well. Without the StoreStore memory barrier, then steps 3 and 5 <i>could</i> be re-ordered and the write to main memory for x could show up before the write to x.b and another cpu core could observe pointer_to_A.b to be 0 (null), which would violate the JMM.
<br/><br/>
Great news! However, if you look at that cookbook you'll see some interesting things: (1) a lot of people are writing JVMs on lots of processor architectures! (2) <b>*all*</b> of the memory barriers on x86 are <b>no-ops</b> except the StoreLoad barrier! This means that on x86 this <i>StoreStore</i> memory barrier above is a no-op and thus no assembly is emitted for it. It does nothing! This is because the x86's memory model is a <i>strong</i> "total store ordering" (TSO). X86 makes sure that all memory writes are observed as if they were all made in the same order. Thus, the write of 5 would never appear before 3 to any other thread anyways due to TSO, and there is no need to emit a memory fence. Other cpu architectures have weaker memory models which do not make such guarantees, and thus the StoreStore memory fence is necessary. Note that weaker memory models, while perhaps harder or less-intuitive to program against, are generally much faster as the cpu can re-order things to make more efficient use of cache writes and reduce cache coherency work.
<br/><br/>
<b>Obviously you should continue to write <i>correct</i> code that follows the JMM.</b> BUT it also means (unfortunately or fortunately) that forgetting this will not lead to bugs if you're running on x86...like I do at work.
<br/><br/>
To really drill this home and ensure that there are no other side effects that maybe aren't being described in the cookbook, I ran the x86 assembly outputter as described <a href="http://mechanical-sympathy.blogspot.com/2013/06/printing-generated-assembly-code-from.html">here</a> and captured the output of calling the constructor for ClassA (with the final on the reference type field) and the constructor for a ClassB, which was identical to ClassA except without the final keyword on the class member. The x86 assembly output is <b>identical</b>. So from a JIT perspective, on x86 (not itanium, not arm, etc), the final keyword has no impact.
<br/><br/>
If you're curious what the assembly code looks like here it is below. Note the lack of any <b>lock</b>ed instructions. When Oracle's 7u25 JRE emits an x86 StoreLoad memory fence it is done through emitting <b>lock addl $0x0,(%rsp)</b> which just adds zero to the stack pointer -- a no-op, <i>but</i> since its locked -- that has the effect of a full fence (which meets the criteria of a StoreLoad fence). There are a few different ways in x86 to cause the effect of a full fence, and they are discussed in the OpenJDK mailing list. They observed that at least on nehelem intel the lock add of 0 was most space compact/efficient.
<pre>
0x00007f152c020c60: mov %eax,-0x14000(%rsp)
0x00007f152c020c67: push %rbp
0x00007f152c020c68: sub $0x20,%rsp ;*synchronization entry
; - com.argodata.match.profiling.FinalConstructorMain::callA@-1 (line 60)
0x00007f152c020c6c: mov %rdx,(%rsp)
0x00007f152c020c70: mov %esi,%ebp
0x00007f152c020c72: mov 0x60(%r15),%rax
0x00007f152c020c76: mov %rax,%r10
0x00007f152c020c79: add $0x18,%r10
0x00007f152c020c7d: cmp 0x70(%r15),%r10
0x00007f152c020c81: jae 0x00007f152c020cd6
0x00007f152c020c83: mov %r10,0x60(%r15)
0x00007f152c020c87: prefetchnta 0xc0(%r10)
0x00007f152c020c8f: mov $0x8356f3d0,%r11d ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}
0x00007f152c020c95: mov 0xb0(%r11),%r10
0x00007f152c020c9c: mov %r10,(%rax)
0x00007f152c020c9f: movl $0x8356f3d0,0x8(%rax) ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}
0x00007f152c020ca6: mov %r12d,0x14(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)
0x00007f152c020caa: mov %ebp,0xc(%rax) ;*putfield a
; - com.argodata.match.profiling.FinalConstructorMain$ClassA::<init>@6 (line 17)
; - com.argodata.match.profiling.FinalConstructorMain::callA@6 (line 60)
0x00007f152c020cad: mov (%rsp),%r10
0x00007f152c020cb1: mov %r10d,0x10(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)
0x00007f152c020cb5: mov %rax,%r10
0x00007f152c020cb8: shr $0x9,%r10
0x00007f152c020cbc: mov $0x7f152b765000,%r11
0x00007f152c020cc6: mov %r12b,(%r11,%r10,1) ;*synchronization entry
; - com.argodata.match.profiling.FinalConstructorMain::callA@-1 (line 60)
0x00007f152c020cca: add $0x20,%rsp
0x00007f152c020cce: pop %rbp
0x00007f152c020ccf: test %eax,0x9fb932b(%rip) # 0x00007f1535fda000
; {poll_return}
0x00007f152c020cd5: retq
0x00007f152c020cd6: mov $0x8356f3d0,%rsi ; {oop('com/argodata/match/profiling/FinalConstructorMain$ClassA')}
0x00007f152c020ce0: xchg %ax,%ax
0x00007f152c020ce3: callq 0x00007f152bfc51e0 ; OopMap{[0]=Oop off=136}
;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)
; {runtime_call}
0x00007f152c020ce8: jmp 0x00007f152c020caa ;*new
; - com.argodata.match.profiling.FinalConstructorMain::callA@0 (line 60)
0x00007f152c020cea: mov %rax,%rsi
0x00007f152c020ced: add $0x20,%rsp
0x00007f152c020cf1: pop %rbp
0x00007f152c020cf2: jmpq 0x00007f152bfc8920 ; {runtime_call}
</pre>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-2358683366324890452013-07-08T12:28:00.000-05:002013-07-08T12:28:44.091-05:00Database intro for developersMost of my academic background focused on low level database research. I wrote a dynamic programming based join-order optimizer for the open-source SQLite database as project in school. I have submitted a paper for publication in an academic conference that deals with optimizing low-level page structures and optimizer heuristics to improve throughput for certain kinds of workloads on solid-state drives. All in all, I've been a "nuts and bolts" database geek for a while -- more on the systems-level side than on the data mining and data warehousing side. I can talk about exotic fractal trees and various B*-tree variants for efficient indexing and lock-free versions ad nauseum ;)
<br/>
<br/>
In any case, the level of willful ignorance about the basics of how databases work among typical enterprise developers has always surprised me. The are the workhorses of most enterprise apps, and getting them to perform well requires some knowledge of how they work. At least a basic understanding of how indexing works is useful in building up your mental intuition about what will perform and what won't in production. Everyone should also at least know the basic processing pipeline: parsing, optimization, execution.
<br/>
<br/>
This talk was meant to be a simple introduction to some of the basics of how databases process your queries for you. I'd like to do more follow on talks to add more depth in the future. It is geared towards developers -- not DBAs. So there is nothing in here about best practices for backups or transaction log shipping.
<br/>
<br/>
<iframe src="https://docs.google.com/presentation/d/1NzUrtH9qrhW8Gr0x3C_eLbyoz2U_M2GGDUYOGTw8-dc/embed?start=false&loop=false&delayms=3000" frameborder="0" width="480" height="389" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
<br/>
<br/>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-87816294769270363012013-07-08T12:17:00.000-05:002013-07-08T12:17:03.449-05:00Introduction to multi-threaded java programmingI gave a talk for our group about multi-threaded java programming for some of our junior members. I lifted a bulk of the slides from the interwebz, but added a fair amount of new content and commentary. It's not really that good of an introduction, but its something.
<br/>
<iframe src="https://docs.google.com/presentation/d/1xh353FURocH6JsIsex6Xe4IJaESShz95Hv4cg0VCW5w/embed?start=false&loop=false&delayms=3000" frameborder="0" width="480" height="389" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
<br/>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-17924004954622268192013-04-20T10:17:00.001-05:002013-04-20T10:17:13.924-05:00Java implementation of Optimal String Alignment<span style="font-family: inherit;">For a while, I've used the Apache Commons lang StringUtils implementation of <a href="http://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance</a>. It implements a few well known tricks to use less memory by only hanging on to two arrays instead of allocating a huge n x m table for the memoisation table. It also only checks a "stripe" of width 2 * k +1 where k is the maximum number of edits. </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">In most practical usages of levenshtein you just care if a string is within some small number (1, 2, 3) of edits from another string. This avoid much of the n * m computation that makes levenstein "expensive". We found that with a k <= 3, levenshtein with these tricks was faster than </span><a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">Jaro-Winkler distance</a>, which is an approximate edit distance calculation that was created to be a faster approximate (well there were many reasons).<br />
<br />
Unfortunately, the Apache Commons Lang implementation only calculates Levenshtein and not the possible more useful <a href="http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance">Damerau-Levenshtein distance</a>. Levenshtein defines the edit operations insert, delete, and substitute. The Damerau variant adds *transposition* to the list, which is pretty useful for most of the places I use edit distance. Unfortunately DL distance is not a true metric in that it doesn't respect the triangle inequality, but there are plenty of applications that are unaffected by this. As you can see from that wikipedia page, there is often confusion between Optimal String Alignment and DL distance. In practice OSA is a simpler algorithm and requires less book-keeping so the runtime is probably marginally faster. <br />
<br />
I could not find any implementations of OSA or DL that used the memory tricks and "stripe" tricks that I saw in Apache Commons Lang. So I implemented my own OSA using those tricks. At some point I'll also implement DL with the tricks and see what the performance differences are:<br />
<br />
Here's OSA in Java. It's public domain; feel free to use as you like. The unit tests are below. Only dependency is on Guava- but its just the preconditions class and an annotation for documentation so easy to remove that dependency if you like:<br />
<br />
<br /><script src="https://gist.github.com/steveash/5426191.js"></script>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-54713282814560147352013-04-19T15:32:00.001-05:002013-04-20T09:09:22.272-05:00Some Java Puzzlers in a powerpointEvery week our team gets together on friday afternoons and have a presentation. The presenter rotates each week, and the topic can be programming language related, cool new libraries, theoretical -- or whatever related to our work.<br />
<br />
I love doing Java Puzzlers since they do a great job of enriching your understanding of the language in a fun way.
I've already done all of the Java Puzzlers that I could find from slides from Josh Bloche himeself. So this time I created my own, lifting the examples from the book.<br />
<br />
In case this benefits anyone else-- here is mine:
<a href="https://docs.google.com/file/d/0B0MfVUaXs0kNaURxU1pLRW40NDQ/edit?usp=sharing">Java Puzzlers</a>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-28627534719539238542012-12-14T17:27:00.000-06:002012-12-14T17:29:31.513-06:00Why and how we use SpringWe brought on some new team members recently and I couldn't find a good intro to Spring that went through the motivation of why one might use Spring. Thus, I created this presentation. Don't know if anyone else will find it valuable:<br />
<br />
I wanted something that went through the trade-off discussion of various options for dependency management (serivce locator, dependency injection) and then showed some practical uses of Spring and mentioned some pitfalls that I've encountered. This was meant to be a practical onboarding to the technology of Spring in Java.
<br />
<iframe src="https://docs.google.com/presentation/embed?id=1_B68o-1_FYE422bGYzqHqhEJnP532IbxPmWjNgHvKY4&start=false&loop=false&delayms=3000" frameborder="0" width="480" height="389" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-6950673475632614812012-06-25T11:33:00.000-05:002012-06-25T11:33:20.577-05:00The Manufacturing of Software<p>
Among non-technologists, I think there is a common belief -- a wishful thought-- that building software is like any manufacturing process. You just need to design the process, and then get the widgets on the assembly line to execute the process-- and viola! If a widget quits, you just buy a new widget at <strike>the widget store</strike> Monster.com.
</p>
<p>
Thankfully, most of the truly remarkable software projects and software teams over the last decade have debunked this myth and shown the lie. The agile manifesto itself states to value <i>people</i> over <i>processes</i> and this is really a statement against this manufacturing projection.
</p>
<p>
I ran across this wonderful quote while reading Eric Evan's Domain Driven Design:
</p>
<blockquote>
Manufacturing is a popular metaphor for software development. One inference from this metaphor: highly skilled engineers design; less skilled laborers assemble the products. This metaphor has messed up a lot of projects for one simple reason -- software development is <i>all</i> design.
</blockquote>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-77628682625512158952012-04-08T23:41:00.000-05:002012-04-08T23:41:51.261-05:00Bye bye Eclipse -- my disorganized, irresponsible little brotherI have been an Eclipse fan-boy for the last 7 years. I have participated on a number of open source Eclipse plugin projects. I have evangelized it to others. I also have a personal connection to it as my father was one of the project principles when it was still an IBM project. I have apologized for Eclipse a lot:
<ul>
<li>The auto-completion is slow and clunky and just doesn't "feel" right.</li>
<li>The static imports and favorites always seem to get in my way.</li>
<li>The Maven support (while dramatically improved) is still sometimes clunky.</li>
<li>The mismatch of hierarchical projects to non-hierarchical is awkward (maven multi-module projects)</li>
<li>The plugins, while extensive, are often not polished. I wanted to literally break my laptop in half after trying to write some Groovy code -- null pointers flowing up to popups, etc.</li>
<li>The EGit support, while improving, is just developing slowly and still has lots of bugs.</li>
<li>There is a lack of consistency across plugins -- they are obviously developed in isolation and lack a cohesive overall vision.</li>
<li>I still at least once a week have to hear about or help a team member who is stuck in some kind of Eclipse hell where builds are firing continuously or something else is going wrong.</li>
</ul>
<p>I've always loved the dream of Eclipse as it is a simulacrum of why I love open source software. I like the bizarre over the cathedral. But at the end of the day, I need to get work done -- not fight with making Eclipses plugins all play nicely.</p>
<p>An anecdote of my point: last project we were trying to do some Tapestry5 development using Eclipse's WTP + Tomcat. Tapestry has some fancy classloaders so that it can hot load java class file changes without restarting/redeploying. We also wanted to use Tomcat7. Well WTP has the ability to host the tomcat instance from the workspace, which works well with Tapestry's class loader stuff. Unfortunately between the last version of WTP and Tomcat7 it was broken. The only person that works on the Tomcat connector for WTP is a guy named Larry Issacs who has a full time job at SAP. So it might get fixed when he has time...some day. I ended up patching the jar and distributing it to our team myself as a hack.</p>
<p>At the end of the day, I just need to get work done. And so far, <b>IntelliJ has been an improvement</b>. I still love Eclipse, but it needs more resources or more vision or more something to compete well. Its not the big things -- its the little things. The overall cohesiveness in IntelliJ is what I find refreshing.</p>
<p><b>But hey it could be worse -- it could be Visual Studio</b> *giggle*. I love talking with these Visual Studio "fan boys" who have never used any other IDE or at least ReSharper. I was talking with a "chief architect evangelist" from Microsoft (a comical title) and asked if the utterly absurd feature anemia in Visual Studio was indicative of:
<ul>
<li>a lack of imagination or motivation by the development staff to investigate more productive ways to write software <b>or</b></li>
<li>a cultural/systemic problem at Microsoft where the developers using the tools could not communicate with the product management who drives the feature sets.</li>
</ul>
He asked me for specific examples of features. I said "go look at the ReSharper feature list-- specifically Refactorings". He said <i>literally</i>: <b>"Why would you want to refactor anything?"</b>.</p>
<p>In the most patronizing tone I could muster I suggested that he go read the chapter on refactoring in the Microsoft Press book titled "Code Complete".</p>
<p>*sigh* </p>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-5733634454885653162012-04-02T20:08:00.001-05:002012-04-02T20:10:40.031-05:00Hibernate4 SessionFactoryBuilder gotcha<p>Just upgraded one of our projects to Spring 3.1.1 and Hibernate 4.1.1 today and ran into a small problem that ate up some time.</p>
<h3>Symptom:</h3>
<p>
It appeared as if all of my hibernate <property>'s in hibernate.cfg.xml were suddenly not being picked up -- they were just silently being ignored.</p>
<p>So for example, for our unit tests, we run Derby with hibernate.hbm2ddl = create so that the schema is generated dynamically each time. In Hibernate 3.6 we used two files: hibernate.cfg.xml (packaged in the jar, not for customers) and hibernate.local.cfg.xml (placed in the customer's etc directory on the class path for support/production time overrides, etc.).</p>
<p>Well in migrating to Hibernate4 I took advantage of Spring's new hibernate4.LocalSessionFactoryBuilder class to help build my metadata and I got rid of my hibernate.cfg.xml entirely.</p>
<p>I used it like so:</p>
<pre class="brush: java">
@Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataConfig.dataSource())
.scanPackages(DatabasePackage)
.addPackage(DatabasePackage)
.addProperties(dataConfig.hibernateProperties())
.addResource("hibernate.local.cfg.xml")
.buildSessionFactory();
}
</pre>
And I had a hibernate.local.cfg.xml in my src/test/resources that looked like:
<pre class="brush: java">
<hibernate-configuration>
<session-factory>
<property name="hibernate.hbm2ddl.auto">create</property>
</session-factory>
</hibernate-configuration>
</pre>
<p>But it wasn't being picked up! I tried adding mappings in to it and those were picked up. Finally after digging through the Hibernate source I realized the problem. Adding hibernate.cfg.xml's through <b>addResource</b> <i>only</i> processes class mappings -- it ignores properties and listeners etc. However, you can add hibernate.cfg.xml's through the the .configure method and those are still processed as they were before Hibernate4.</p>
<pre class="brush: java">
@Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataConfig.dataSource())
.scanPackages(DatabasePackage)
.addPackage(DatabasePackage)
.addProperties(dataConfig.hibernateProperties())
.configure("hibernate.local.cfg.xml")
.buildSessionFactory();
}
</pre>
<p>I couldn't find this well documented anywhere, nor was it specifically mentioned on the <a href="https://community.jboss.org/wiki/HibernateCoreMigrationGuide40">migration guide</a> as a consideration. They do mention not paying attention to event listeners anymore, but don't mention properties.</p>
<p>No big deal -- just lost some time :(</p>
<br/>
<br/>
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-36232149242389477362012-01-12T01:41:00.000-06:002012-01-12T01:42:06.602-06:00Multi-tier application + database deadlock or why databases aren't queues (part1)Databases aren't queues.<br />
<br />
And despite the ubiquitous presence of queuing technology out there (ActiveMQ, MSMQ, MSSQL Service Broker, Oracle Advanced Queuing) there are plenty of times when we ask our relational brethren to pretend to be queues. This is the story of one such folly, and along the way, we'll delve into some interesting sub-plots of deadlocks, lock escalation, execution plans, and covering indexes, oh my! Hopefully we'll laugh, we'll cry, and get the bad guy in the end (turned out I was the bad guy).
<br />
<br />
This is <b>part one</b> of a multi-part series describing the whole saga. In this part, I lay out the problem, the initial symptom, and the tools and commands I used to figure out what was going wrong.
<br />
<h3>
And so it starts...</h3>
I'm going to set the stage for our discussion, to introduce you to the problem, and establish the characters involved in our tragedy. Let's say that this system organizes music CDs into labeled buckets. A CD can only be in one bucket at a time, and the bucket tracks at an aggregate level how many CDs are contained within it (e.g. bucket "size"). You can visualize having a stack of CDs and two buckets: "good CDs" and "bad CDs". Every once in a while you decide that you don't like your bucket choices, and you want to redistribute the CDs into new buckets--perhaps by decade: "1980s music", "1990s music", "all other (inferior) music". Later you might change your mind again and come up with a new way to organize your CDs, etc. We will call each "set" of buckets a "generation". So at generation zero you had 2 buckets "good CDs" and "bad CDs", at generation one you had "1980s CDs", etc, and so on and so on. The generation always increases over time as you redistribute your CDs from a previous generation's buckets to the next generation's buckets.<br />
<br />
Lastly, while I might have my music collection organized in some bucket scheme, perhaps my friend Jerry has his own collection and his own bucket scheme. So entire sets of buckets over generations can be grouped into music <i>collections</i>. Collections are completely independent: Jerry and I don't share CDs nor do we share buckets. We just happen to be able to use the same system to manage our music collections.<br />
<br />
So we have:
<br />
<ul>
<li>CDs -- the things which are contained within buckets, that we redistribute for every new generation</li>
<li>Buckets -- the organizational units, grouped by generation, which contain CDs. Each bucket has a sticky note on it with the number of CDs currently in the bucket.</li>
<li>Generation -- the set of buckets at a particular point in time.</li>
<li>Collection -- independent set of CDs and buckets</li>
</ul>
Even while we're redistributing the CDs from one generation's buckets to the next, a CD is only in one bucket at a time. Visualize physically moving the CD from "good CDs" (generation 0) to "1980s music" (generation 1).<br />
<br />
<i>NOTE: Our actual system has nothing to do with CDs and buckets-- I just found it easier to map the system into this easy to visualize metaphor.
</i><br />
<br />
In this system we have millions of CDs, thousands of buckets, and lots of CPUs moving CDs from bins in one generation to the next (parallel, but not distributed). The size of each bucket <i>must</i> be consistent at any point in time.
<br />
<br />
So assume the database model looks something like:
<br />
<ul>
<li><b>Buckets</b> Table</li>
<ul>
<li>bucketId <i>(e.g. 1,2,3,4)</i> - <b>PRIMARY KEY CLUSTERED</b></li>
<li>name <i>(e.g. 80s music, 90s music)</i></li>
<li>generation <i>(e.g. 0, 1, 2)</i></li>
<li>size <i>(e.g. 4323, 122)</i></li>
<li>collectionId <i>(e.g. "Steves Music Collection")</i> - <b>NON-CLUSTERED INDEX</b></li>
</ul>
<li><b>Cds</b> Table</li>
<ul>
<li>cdId <i>(e.g. 1,2,3,4)</i> - <b>PRIMARY KEY CLUSTERED</b></li>
<li>name <i>(e.g. "Modest Mouse - Moon and Antarctica", "Interpol - Antics")</i></li>
<li>bucketId <i>(e.g. 1,2, etc. foreign key to the Bucket table)</i> - <b>NON-CLUSTERED INDEX</b></li>
</ul>
</ul>
Note that both tables are clustered by their primary keys-- this means that the actual record data itself is stored in the leaf nodes of the primary index. I.e. the table itself is an index. In addition, Buckets can be looked up by "music collection" without scanning (see the secondary, non-clustered index on collectionId), and Cds can be looked up by bucketId without scanning (see the secondary, non-clustered index on Cds.bucketId).
<br />
<h3>
The algorithm</h3>
So I wrote the redistribution process with a few design goals: (1) it needed to work online. I could concurrently add new CDs into the current generations bins while redistributing. (2) I could always locate a CD-- i.e. I could never falsely report that some CD was missing just because I happen to search during a redistribution phase. (3) if we interrupt the redistribution process, we can resume it later. (4) it needed to be parallel. I wanted to accomplish (1) and (2) with bounded blocking time so whatever blocking work I needed to do, I wanted it to be as short as possible to increase concurrency.<br />
<br />
I used a simple concurrency abstraction that hosted a pool of workers who shared a supplier of work. The supplier of work would keep giving "chunks" of items to move from one bucket to another. We only redistribute a single <i>music collection</i> at a time. The supplier was shared by all of the workers, but it was synchronized for safe multi-threaded access.
<br />
<br />
<br />
The algorithm for each worker is like:<br />
<pre>(I) Get next chunk of work
(II) For each CD decide the new generation bucket in which it belongs
(accumulating the size deltas for old buckets and new buckets)
(III) Begin database transaction
(IV) Flush accumulated size deltas for buckets
(V) Flush foreign key updates for CDs to put them in new buckets
(VI) Commit database transaction</pre>
<pre></pre>
<br />
Each worker would be given a chunk of CDs for the current music collection that was being redistributed (I). The worker would do some work to decide which bucket in the <i>new</i> generation should get the CD (II). The worker would accumulate the deltas for counts: decrementing from the original bucket and incrementing the count for the new bucket. Then the worker would flush (IV) these deltas in a correlated update like <code>UPDATE Buckets SET size = size + 123 WHERE bucketId = 1</code>. After the size updates were flushed, it would then flush (V) all of the individual updates to the foreign key fields to refer to the new generations buckets like <code>UPDATE Cds SET bucketId = 123 WHERE bucketId = 101</code>. These two operations happen in the same database transaction.<br />
<br />
The supplier that <i>gives</i> work to the workers is a typical "queue" like SELECT query -- we want to iterate over all of the items in the music collection in the old generation. This happens in a <i>separate</i> connection, separate database transaction from the workers (discussed later). The next chunk will be read using the worker thread (with thread safe synchronization). This separate "reader" connection doesn't have its own thread or anything.
<br />
<br />
<h3>
First sign of trouble - complete stand still</h3>
So we were doing some large volume testing on not-so-fast hardware, when suddenly...the system just came to a halt. We seemed to be in the middle of moving CDs to new buckets, and they just stopped making progress.
<br />
<h5>
Finding out what the Java application was doing</h5>
So first step was to see what the Java application was doing:
<br />
<br />
<pre>c:\>jps
1234 BucketRedistributionMain
3456 jps
c:\>jstack 1234 > threaddump.out
</pre>
<b><br /></b><br />
<b>Jps</b> finds the java process id, and then run <b>jstack</b> to output a stacktrace for each of the threads in the java program. Jps and Jstack are included in the JDK.
<br />
<br />
The resulting stack trace showed that all workers were waiting in <b>socketRead</b> to complete the database update to flush the bucket size updates (step IV above).
<br />
<br />
Here is the partial stack trace for one of the workers (some uninteresting frames omitted for brevity):
<br />
<br />
<pre>"container-lowpool-3" daemon prio=2 tid=0x0000000007b0e000 nid=0x4fb0 runnable [0x000000000950e000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
...
at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(Unknown)
at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(Unknown)
...
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(Unknown)
...
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
...
at com.mycompany.BucketRedistributor$Worker.updateBucketSizeDeltas()
...
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
...
at java.lang.Thread.run(Unknown Source)
</pre>
<br />
As you can see our worker was updating the bucket sizes which resulted in a Hibernate "flush" (actually pushes the database query across the wire to the database engine), and then we await the response packet from MSSQL once the statement is complete. Note that we are using the jtds MSSQL driver (as evidenced by the net.sourceforge.jtds in the stack trace.
<br />
<br />
So the next question is <i>why</i> is the database just hanging out doing nothing?
<br />
<h5>
Finding out what the database was doing...</h5>
MSSQL provides a lot of simple ways to get insight into what the database is doing. First let's see the state of all of the connections. Open SQL Server Management Studio (SSMS), click New Query, and type <code>exec sp_who2</code>
<br />
<br />
This will return output that looks like:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI_jupJBFuPl5wa3dUGQ9pLRRp8l2Y4J2Do9mrPJykxXmDTjC4Vgvq6VkcsoDcVRfN-sH_x251Mnm7Qo1RdACwJGItPKtT2P09SOi8O3Nj6sQiJ8FztXmL5Znmd_U7vVhnQQY8JmHzR3M/s1600/blog_sp_who2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI_jupJBFuPl5wa3dUGQ9pLRRp8l2Y4J2Do9mrPJykxXmDTjC4Vgvq6VkcsoDcVRfN-sH_x251Mnm7Qo1RdACwJGItPKtT2P09SOi8O3Nj6sQiJ8FztXmL5Znmd_U7vVhnQQY8JmHzR3M/s400/blog_sp_who2_1.png" width="400" /></a></div>
<br />
You can see all of the <b>spids</b> for sessions to the database. There should be five that we're are interested in: one for the "work queue" query and four for the workers to perform updates. The sp_who2 output includes a <b>blkBy</b> column which shows the spid that is <i>blocking</i> the given spid in the case that the given spid is SUSPENDED.
<br />
<br />
We can see that spid 56 is the "work queue" SELECT query (highlighted red). Notice that no one is blocking it... then we see spids 53, 54, 60, and 61 (highlighted in yellow) that are all waiting on 56 (or each other). Disregard 58 - its application source is the management studio as you can see.
<br />
<br />
So how curious! the reader query is blocking all of the update workers and preventing them from pushing their size updates. The reader "work queue" query looks like:
<br />
<br />
<pre>SELECT c.cdId, c.bucketId FROM Buckets b INNER JOIN Cds c ON b.bucketId = c.bucketId WHERE b.collection = 'Steves Collection' and b.generation = 23
</pre>
<h5>
Investing blocking and locking problems...</h5>
I see that spid 56 is blocking everyone else. So what locks is 56 holding? In a new query window, I ran <code>exec sp_lock 56</code> and <code>exec sp_lock 53</code> to see which locks each was holding and who was waiting on what.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgMzzqem0WY4QTm5mL4vjzpR_UkoDddwl24wQ9XDQs_eJIrtNKoSI8cBIq_pM9eez5QHAlOSFARwf8zEYSiDaaC-dXPdpun3k8AagVQWsLRDTNw2DZIUm4MIZJ3ZqQORYVsT3xWKoNXiY/s1600/blog_sp_lock_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgMzzqem0WY4QTm5mL4vjzpR_UkoDddwl24wQ9XDQs_eJIrtNKoSI8cBIq_pM9eez5QHAlOSFARwf8zEYSiDaaC-dXPdpun3k8AagVQWsLRDTNw2DZIUm4MIZJ3ZqQORYVsT3xWKoNXiY/s400/blog_sp_lock_1.png" width="400" /></a></div>
<br />
You can see that 56 was holding a <b>S (shared) lock</b> on a <b>key</b> resource (key = row lock on an index) of object 1349579846, which corresponds to the Buckets table.
<br />
<br />
I wanted to the engine's execution plan for the reader "work queue" query. To get this, I executed a query that I created a while ago to dump as many details about current sessions in the system as possible-- think of it as a "super who2":
<br />
<br />
<pre>select es.session_id, es.host_name, es.status as session_status, sr.blocking_session_id as req_blocked_by,
datediff(ss, es.last_request_start_time, getdate()) as last_req_submit_secs,
st.transaction_id as current_xaction_id,
datediff(ss, dt.transaction_begin_time, getdate()) as xaction_start_secs,
case dt.transaction_type
when 1 then 'read_write'
when 2 then 'read_only'
when 3 then 'system'
when 4 then 'distributed'
else 'unknown'
end as trx_type,
sr.status as current_req_status,
sr.wait_type as current_req_wait,
sr.wait_time as current_req_wait_time, sr.last_wait_type as current_req_last_wait,
sr.wait_resource as current_req_wait_rsc,
es.cpu_time as session_cpu, es.reads as session_reads, es.writes as session_writes,
es.logical_reads as session_logical_reads, es.memory_usage as session_mem_usage,
es.last_request_start_time, es.last_request_end_time, es.transaction_isolation_level,
sc.text as last_cnx_sql, sr.text as current_sql, sr.query_plan as current_plan
from sys.dm_exec_sessions es
left outer join sys.dm_tran_session_transactions st on es.session_id = st.session_id
left outer join sys.dm_tran_active_transactions dt on st.transaction_id = dt.transaction_id
left outer join
(select srr.session_id, srr.start_time, srr.status, srr.blocking_session_id,
srr.wait_type, srr.wait_time, srr.last_wait_type, srr.wait_resource, stt.text, qp.query_plan
from sys.dm_exec_requests srr
cross apply sys.dm_exec_sql_text(srr.sql_handle) as stt
cross apply sys.dm_exec_query_plan(srr.plan_handle) as qp) as sr on es.session_id = sr.session_id
left outer join
(select scc.session_id, sct.text
from sys.dm_exec_connections scc
cross apply sys.dm_exec_sql_text(scc.most_recent_sql_handle) as sct) as sc on sc.session_id = es.session_id
where
es.session_id >= 50
</pre>
<br />
In the above output, the last column is the SQL XML Execution plan. Viewing that for spid 56, I confirmed my suspicion: The plan to serve the "work queue" query was to seek the "music collection" index on the buckets table for 'Steves collection', then seek to the clustered index to confirm 'generation = 23', then seek into the bucketId index on the Cds table. So to serve the WHERE clause in the "work queue" query, the engine had to use both the non-clustered index on Buckets and the clustered index (for the version predicate).
<br />
<br />
When joining and reading rows at <a href="http://msdn.microsoft.com/en-us/library/ms173763.aspx">READ COMMITTED isolation level</a>, the engine will acquire locks as it traverses from index to index in order to ensure consistent reads. Thus, to read the value of the generation in the Buckets table, it must acquire a shared lock. And it has!
<br />
<br />
The problem comes in when the competing sessions that are trying to update the size on that same record of the Bucket table. It needs an <b>X (exclusive)</b> lock on that row (highlighted in red), and eek! it can't get it, because that reader query has a conflicting S lock <i>already granted</i> (highlighted in green).
<br />
<br />
Ok so that all makes sense, but why is the S lock being held? At READ COMMITTED you usually only hold the locks while the record is being read (there are exceptions and we'll get to that in Part 2). They are released as soon as the value is read. So if you read 10 rows in a single statement execution, the engine will: acquire lock on row 1, read row 1, release lock on row 1, acquire lock on row 2, read row 2, release lock on row 2, acquire lock on row 3, etc. So none of the four workers are currently reading-- they are writing -- or at least they're trying to if that pesky reader connection wasn't blocking them.
<br />
<br />
To find this, I was curious <i>why</i> the reader query was in a SUSPENDED state (see original sp_who2 output above). In the above "super who2" output, the <b>current_req_wait</b> value for the "work queue" read query is <code>ASYNC_Network_IO</code>.
<br />
<h5>
ASYNC_Network_IO wait and how databases return results</h5>
ASYNC_Network_IO is an interesting wait. Let's discuss how remote applications execute and consume SELECT queries from databases.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG0pGpNIorgmGiQosDcTRsuQGhtV8uYLIjXZtKkMDv8PCiLtivCSP_iN8YvX1dZ9ak3b8Csuj_MZBcUP3CWncvXv82Tpb8CDujKqP25O8H3CIfQYGBrgO8zL4O8HUz9ty0czTlr4JKjwQ/s1600/db_arch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG0pGpNIorgmGiQosDcTRsuQGhtV8uYLIjXZtKkMDv8PCiLtivCSP_iN8YvX1dZ9ak3b8Csuj_MZBcUP3CWncvXv82Tpb8CDujKqP25O8H3CIfQYGBrgO8zL4O8HUz9ty0czTlr4JKjwQ/s400/db_arch.png" width="400" /></a></div>
That diagram is over-simplified, but within the database there are two chunks of memory to discuss: the <b>buffer cache</b> and the <b>connection network buffer</b>. The buffer cache is a shared chunk of memory, where the actual pages of the tables and indexes are kept to serve queries. So parts of the Buckets and Cds tables will be in memory while this "work queue" query executes. The execution engine executes the plan, it works out of the buffer cache, acquiring locks, and producing output records to send to the client. As it prepares these output records, it puts them in a connection-specific <b>network buffer</b>. When the application reads records from the result set, its actually being served from the network buffer in the database. The application driver typically has its own buffer as well.<br />
<br />
When you just execute a simple SQL SELECT query and don't explicitly declare a database cursor, MSSQL gives you what it calls the "default result set" -- which is still a cursor of sorts -- you can think of it as a cursor over a bunch of records that you can only iterate over once in the forward direction. As your application threads iterate over the result set, the driver requests more chunks of rows from the database on your behalf, which in turn depletes the network buffer.
<br />
<br />
However, with very large result sets, the entire results cannot fit in the connection's network buffer. If the application doesn't read them fast enough, then eventually the network buffer fills up, and the execution engine must stop producing new result records to send to the client application. When this happens the spid must be suspended, and it is suspended with the wait event <b>ASYNC_Network_IO</b>. It's a slightly misleading wait name, because it makes you think there might be a network performance problem, but its more often an application design or performance problem. Note that when the spid is suspended -- just like any other suspension -- the <b>currently held locks will remain held until the spid is resumed</b>.
<br />
<br />
In our case, we know that we have millions of CDs and we can't fit them all in application memory at one time. We, by design, want to take advantage of the fact that we can stream results from the database and work on them in chunks. Unfortunately, if we happen to be holding a conflicting lock (S lock on Bucket record) when the reader query is suspended, then we create a multi-layer application deadlock, as we observed, and the whole system screeches to a halt.<br />
<br />
So what to do for a solution? I will discuss some options and our eventual decision in Parts 2 and 3. Note that I gave one hint at our first attempt when I talked about "covering indexes", and then there is another hint above that we didn't get to in this post about "lock escalation".<br />
<br />
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-75526261024708022342011-12-22T12:17:00.002-06:002011-12-22T12:27:58.631-06:00MSSQL non-clustered indexes INCLUDE feature explainedToday I received a question from someone about the nature of the INCLUDE feature when creating a non-clustered (secondary) index on a table. My response was a bit long, and I haven't posted in a while -- ergo blogpost! Here's the question:<br />
<br />
<blockquote>What is your opinion about using the include statement when building your indexes? I’ve never really used the included functionality and I’m curious if there are upsides or downsides to them. My reading lead me to believe that I should use the include when I have a non clustered index and space appears to be a concern. I can use the ‘include’ as part of the index with the columns that may not be used as frequently. We’re using standard datatypes and nothing with very large column widths. So is there a benefit to using include?</blockquote><br />
<hl /><br />
<br />
A <b>clustered index</b> is stored in a B+-tree data structure and the <i>actual data</i> the whole row of data is in the leaf. So if you think of a b-tree structure (simplified) as something like:<br />
<pre> A
/ \
B C
/ \ / \
M N O P
</pre>And you have records like <br />
<pre>[ Id =1, FirstName = Steve, LastName = Ash ]
[ Id = 2, FirstName = Neil, LastName=Gafter ]
</pre>Then for the <i>clustered</i> index, the id data (id=1 and id=2) will exist at every node (A, B, C, M, N, O, P), but the bytes for “steve” “ash” “neil” “gafter” will only exist in leaf nodes (either M N O or P). The id is used to <i>locate</i> which leaf holds the whole record. (note this is a simplification, see <a href="http://en.wikipedia.org/wiki/B%2B_tree">Wikipedia</a> for more info about b+-trees). The noteworthy fact is being a <i>clustered</i> index means that the whole record is in a leaf (i.e. M N O P).<br />
<br />
Now let’s think of a non-clustered index on lastName that corresponds to the clustered index above.<br />
<pre> D
/ \
E F
/ \
Q R
</pre>In this case the “last name” is used to <i>get to</i> the leaf, and the leaf holds the <i>primary key</i> of the corresponding row in the clustered index. So D E or F will have things like lastName=Ash and lastName=Gafter and the leaves Q and R will have both lastnames and IDs. So an entry in Q or R might look like [lastname=Ash, id=1] (again simplifying). <br />
<br />
So if you issue a query like <pre>SELECT firstName FROM ThisTable WHERE lastName = ‘Ash’</pre>(and the optimizer chooses to use the non-clustered index) then the database engine will do something like:<br />
<ol><li>Seek the <b>non-clustered</b> index for ‘Ash’</li>
<ol><li>Look in D to decide which direction to go E or F (lets say E is the right choice)</li>
<li>Look in E to decide which direction to go Q or R (lets say Q is the right choice)</li>
</ol><li>Find the primary key for ‘Ash’</li>
<ol><li>In Q find id for Ash – which is id=1</li>
</ol><li>Seek the <b>clustered index</b> for id = 1</li>
<ol><li>Look in A to decide which direction to go B or C (lets say B is right)</li>
<li>Look in B to decide which direction to go M or N (lets say N is right)</li>
</ol><li>Find the value of firstName for id=1</li>
<ol><li>In N find firstName for id=1 which is ‘Steve’</li>
</ol><li>return ‘Steve’ as the query result</li>
</ol>Notice that we created a non-clustered indexed on lastName and we can use that index to quickly locate things by last name, but if we need any additional info, then we have to go <i>back</i> to the clustered index to get the other info in the SELECT list.<br />
<br />
The “include” provides a way for you to shove additional information in the leaf nodes of non-clustered indexes (Q and R) to alleviate this "going back" to the clustered index.<br />
<br />
So had I created the non-clustered index above on LastName INCLUDE FirstName then the engine would only need to do:<br />
<br />
<ol><li>Seek the <b>non-clustered</b> index for ‘Ash’</li>
<ol><li>Look in D to decide which direction to go E or F (lets say E is the right choice)</li>
<li>Look in E to decide which direction to go Q or R (lets say Q is the right choice)</li>
</ol><li>Find the firstName for ‘Ash’</li>
<ol><li>In Q due to the include there is id=1 AND firstName=’Steve’ so we have the first name right here!</li>
</ol><li>return Steve</li>
</ol>So you get rid of that entire other seek into the clustered index. This additional seek shows up as a “bookmark lookup” operation in the query plan in MSSQL 2008 & MSSQL 2000 and just another join in MSSQL 2005 query plans. Bookmark lookup is a join -- just with a different name to indicate its semantic role in the query plan.<br />
<br />
When you have an index such that they query can be completely served from the index without needing to go back to the clustered index – such an index is called a <b>covering index</b>. The index <i>covers</i> the needs of the query completely. And it’s a performance boost as you don’t need the other join.<br />
<br />
So this means a few things:<br />
<ol><li>You can obviously only “include” fields in non-clustered indexes. Clustered indexes already have all the fields in the leaf...so it doesn’t mean anything to include more.</li>
<li>You can only have one clustered-index for a table, but you can simulate have multiple clustered indexes by INCLUDing the rest of the columns on your secondary indexes</li>
<li>By duplicating the data in the secondary index, if you UPDATE firstName – you now have to update both the clustered index and the nonclustered index. (<b>Main trade-off consideration</b>)<br />
<ul><li>This is also a <i>huge</i> deadlock opportunity if you’re not using read committed snapshot isolation (RCSI) level. Think of two queries: (1) <pre>UPDATE MyTable SET firstName = ‘Steve2’ where id = 1</pre>and (2) <pre>SELECT shoeSize FROM MyTable WHERE lastName = ‘Ash’</pre>(pretend shoe size is a new field that is in the clustered index but NOT in the non-clustered, i.e. NOT in the INCLUDE). Then the SELECT will seek the non-clustered index, grab shared (S) locks, then (while holding S locks) traverse the clustered index. Whereas (in the opposite order) the UPDATE will seek the clustered index, hold an exclusive (X) lock, then seek the non-clustered index to update firstName. The fact that these two queries are holding incompatible locks in <i>opposite</i> directions, is a deadlock waiting to happen. If I had a dollar for every time I diagnosed this deadlock scenario...</li>
</ul><li>By duplicating the data in the secondary index, each page in the leaf (Q and R) now has <b>fewer</b> rows per page and thus there is a greater memory demand on the buffer cache (and more IO to get the same number of records) (<b>Second trade off consideration</b>)</li><br />
<br />
<br />
<li>Some databases (even MSSQL < 2005) don’t support this feature, but you can approximate it by creating non-clustered indexes with compound keys. I.e. if I created the non-clustered index on <pre>(lastName, firstName)</pre>then the index still covers queries like <pre>SELECT firstName FROM myTable WHERE lastName = ‘Ash’</pre>Note that this is not as good as the INCLUDE solution (for this particular query) as now the bytes of firstName=’Steve’ take up some space in non-leaf nodes D E F.<br />
</ol>So deciding to use an INCLUDE is (like everything) a trade off. If you have a performance critical query that is being executed frequently, then you can usually use INCLUDEs to reduce the number of joins and increase performance. In an environment where CPU is more precious than memory this can be a big win (we can talk about cache locality benefits of includes later). However, if you INCLUDE a column that will be UPDATEd later – then you often are shooting yourself in the foot as the cost can easily outweigh the benefit.<br />
<br />
Last tidbit about INCLUDEs that I’ll mention. The sql index analyzer is REALLY aggressive about recommending you add indexes with lots of INCLUDEs. This is because the index analyzer usually doesn’t know how many UPDATEs you’re doing. Usually you just tell it what SELECT you want to speed up and it naively says “oh well of course if you add these three covering indexes, this SELECT will be faster.” And while that’s true it doesn’t take into account the _total_ workload (UPDATEs DELETEs etc) so just be skeptical when you see this if you use the index analyzer.<br />
<br />
I can’t give you a hard and fast rule to say INCLUDE is GOOD or EVIL as – like everything with database performance tuning – it depends ;)<br />
<br />
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-23422189091500215882011-07-31T20:14:00.001-05:002011-07-31T20:24:17.340-05:00Delegates or interfaces? Functional and OO DualismI have a mixed background: doing C#/.NET for ~4 years then switching to Java (switched jobs). I have been in the Java enterprise ecosystem for the last 4 years. I do mostly Java, but enjoy doing a little C# every now and again. C# is really a nice language. Shame its in such a horrible Microsoft-centric ecosystem.<br />
<br />
In any case, I've been writing a little thing in C# and needed a type with a single method to "doWork". So coming from a Java bias I created a:<br />
<pre>public interface IWorker {
void DoWork();
}
</pre>Later, however, I wanted to offer the users an API option of just using a lambda to "doWork". Unfortunately, there is no type conversion from a delegate to the matching "single method interface" (at least that I could find, if someone knows the answer, please share!). So as a shim, I created:<br />
<pre>public delegate void WorkerDelegate();
public WorkerWrapper : IWorker {
readonly WorkerDelegate workerDelegate;
public WorkerWrapper(WorkerDelegate workerDelegate) {
this.workerDelegate = workerDelegate;
}
public void DoWork() {
workerDelegate();
}
}
</pre>So I wrap the lambda in a little wrapper and don't need to change my entire IWorker-based infrastructure. It works, but I'm not happy with this. I know that in the Java lambda mailing list, they are planning to include a "lambda conversion" so that lambdas can be converted to compatible single abstract method (SAM) types. This would've alleviated my need for the shim above as I could've assigned the lambda directly to an IWorker and all would've been well.<br />
<br />
I believe the "C# way" would've been for me to use delegates all the way through to begin with. Had someone come along with an IWorker interface then that would've been assignable to my WorkerDelegate.<br />
<br />
But is this the right answer? Conceptually, how should I think of these? What <i>is</i> an IWorker in the above case? Is it <i>really</i> just a chunk of code that should be passed around as such? Or is it a member in the space of collaborating types that make up my system...<br />
<br />
This is an example of the conceptual problems reconciling a Functional view of the world with an object oriented view of the world (dualism). I know that many people smarter than me have thought about these problems, and I'm hoping that I can find some good articles discussing them. <br />
<br />
It <i>feels</i> like we're describing the same concept: a "chunk of code" that is defined by an interface (call it a delegate or a SAM, same thing). I don't think that I would have any dissonance if both were assignable to each other, and thus can be treated as different expressions of the same concept. If this were the case, then maybe I would view delegates as just SAM types -- so my "world view" is still object oriented, I just have an additional, concise lambda syntax to create SAMs. Actually, if this were the case, then you could probably invoke the Liskov substitution principle and call functional-OO dualism reconciled... <br />
<br />
But something still seems amiss. There is more to the identity of an IWorker than the fact that it takes no arguments and returns nothing. I suppose the same questions are true of reconciling structural typing to static typing. Hmm.. I have a lot of reading to do.<br />
<br />
I imagine there are a number of philosophical problems between functional and OO. This is just the one I ran across and felt dissonance with C#s implementation. Maybe they truly are different things and should be treated as such. I hope (despite my extremely small readership) to get some links to articles on this topic.<br />
<br />
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-35407568290610300922011-07-09T13:59:00.001-05:002011-07-09T14:37:59.405-05:00I <3 Robert C. Martin<div>Im reading Clean Code by Uncle Bob. I have read sections of this book before when it came out and actually had the pleasure of watching Robert Martin present it at SDWest in 2008. I've decided to read the whole thing.
<br/> <br/>
A while ago, I read a blog post from someone who was arguing that software wasn't a craft but a trade. I believe the authors intention was to say that we software developers should recognize that the value of the software is the business value and thus we shouldn't wax philosophic about "elegance in design" or software aesthetics as that was all wasting time trying to get to the goal. I may be misrepresenting the author's intention. I couldn't find the post to link it.
<br/> <br/>
In any case, I disagreed entirely with this opinion. While I agree that business value is the motivator-- the craft aspects such as aesthetics, conceptual purity, elegance, etc. All contribute to the solution and its extensibility and maintainability. Maybe we're just arguing over the definition of craft, trade, or art, but in any case I feel there is value in </i>recognizing the challenge</i> of good engineering for today and tomorrow. The masters do it almost effortlessly-- almost accidentally. That <i>feels</i> like art to me and thus should be labelled appropriately as craft.
<br/> <br/>
To this point, clean code is more art than science and Mr. Martin has something to say about it that I really enjoyed:
<blockquote>
Every system is built from a domain specific language designed by the programmers to describe their system. Functions are the verbs, classes are the nouns. This is not some throwback to the hideous old notion that the nouns and verbs in a requirements document are the first guess of the classes and functions of a system. Rather, this is a much older truth. The art of programming is, and always has been, the art of language design.
<br/> <br/>
Master programmers think of systems as stories to be told rather than programs to be written. They use facilities of their chosen programming language to construct a much richer and more expressive language that can be used to tell that story. Part of that domain-specific language is the hierarchy of functions that describe all the actions that take place within that system. In an artful act of recursion those actions are written to use the very domain specific language they define to tell their own small part of the story.
</blockquote>
So to argue that software is not art is to <i>naively</i> ignore the reality that language is hard and has a dramatic effect on the bottom line of your code base. How many software systems never change or never need to be understood after they are written? Such systems must not be very interesting or do anything important.
<br/> <br/>
Let's recognize the art of good software engineering! It will motivate us to continue to improve if we recognize these things have a value.</div>Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-73987479222651095162011-06-27T22:54:00.001-05:002011-12-22T12:33:01.607-06:00Maven -_-I have spent the last few days mucking about with POM files. Anyone that has done this understands where I'm going with this. So I'll just leave these two quotes that fit nicely:<br />
<blockquote>But there has to be something fundamentally wrong with any tool that, whenever I use it, seems to have at least a 50% chance of completely fucking up my day.<br />
<br />
-<a href="http://fishbowl.pastiche.org/2007/12/20/maven_broken_by_design/">Charles Miller</a><br />
</blockquote><br />
<blockquote>The people who <b>love</b> Maven <b>love the theory</b>. The people who <b>hate</b> Maven <b>hate the reality</b>.<br />
<br />
-<a href="http://www.alittlemadness.com/2007/08/01/the-problem-with-maven/">Zutubi</a><br />
</blockquote><br />
Frustration.<br />
<br />
<b>EDIT:</b> For anyone running across this. Now that I am well over the "learning curve" hump. I <3 maven. Seriously. Yes there are some rough edges-- I really should be able to delete folders simply without having to do ant-runs, etc. But its benefit drastically outweighs its cost in our environment.Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-56366830944267683152011-04-13T10:18:00.002-05:002011-04-13T18:56:27.733-05:00OO Reading ListOne of my favorite parts of <a href="http://www.amazon.com/Pragmatic-Thinking-Learning-Refactor-Programmers/dp/1934356050/ref=sr_1_1?ie=UTF8&qid=1302699408&sr=8-1">Pragmatic Thinking</a> is the description of the Dreyfuss model of skills acquisition. This describes the phenomena of how people are frequently distributed along some non-trivial "skill" (like programming), and defines metrics about what differentiates each skill level. Overall, as one moves up to higher skill levels, they are increasing their <i>intuition</i> about the problem space. Intuition is something for which we must <i>train</i> our brain through experience and knowledge. To that end, there are a few books that have helped me in increasing my <i>intuition</i>, which I would like to catalog. If you have others that are missing, please leave a comment! My appetite for the amazon marketplace is insatiable ;-)<br />
<br />
<h2>OO and Design Patterns</h2><ul><li><a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">But Uncle Bob Essay on SOLID</a> - This is Robert C Martin's article outlining the principles of Object Oriented Design. If SOLID doesn't ring a bell, then start with this article. Note that the <a href="http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29">now-famous acronym: SOLID</a> is not actually mentioned in this post, but Robert C Martin is still credited as the inventor.</li>
<li><a href="http://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445/ref=sr_1_1?ie=UTF8&qid=1302708855&sr=8-1">Agile Software Development Principles, Patterns, and Practices</a> - lovingly referred to as the PPP book (not to be confused with the protocol). This describes much of the <i>why</i> of OOD, and explains the Agile mindset.</li>
<li><a href="http://www.amazon.com/gp/product/0201379430/sr=1-1/qid=1302709079/ref=olp_product_details?ie=UTF8&me=&qid=1302709079&sr=1-1&seller=">Object Design</a> - another often referenced book describing the <i>why</i> and various design decisions that go into object oriented design. Thinking about objects isn't hard-- category theory and abstraction is something that our brain does quite naturally (hence the appeal of this design methodology). However, the ergonomics of OOD can sometimes lead to an undeserved sense of self-confidence in one's design. It may <i>feel</i> like OOD, because "oh look-- there are objects there! inheritance! oh, my!", but within the context of software engineering there are many factors that make some designs good and some bad.</li>
<li><a href="http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_1?s=books&ie=UTF8&qid=1302705445&sr=1-1">Design Patterns: Elements of Reusable Object Oriented Software</a> - Canonical book by the "gang of four". Has good description of patterns and <i>why</i> they are useful. If you prefer something with prettier pictures, starting with the <a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124/ref=sr_1_2?s=books&ie=UTF8&qid=1302705445&sr=1-2">Head First Design Patterns</a> book is nice too</li>
<li><a href="http://www.amazon.com/Essays-Object-Oriented-Software-Engineering-Oriented/dp/0132888955/ref=sr_1_1?s=books&ie=UTF8&qid=1302705325&sr=1-1">Essays on OO Software Engineering</a> - Maybe not terribly well-known, but well written theoretical overview of OO, the design forces in OOD, and the motivations behind them. I had the pleasure to work with Ed.</li>
<li><a href="http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/ref=sr_1_1?s=books&ie=UTF8&qid=1302705155&sr=1-1">Patterns of Enterprise Application Architecture</a> - Canonical book on patterns by the man himself</li>
<li><a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?s=books&ie=UTF8&qid=1302705613&sr=1-1">Refactoring</a> - Another Fowler book. I haven't read this one cover to cover, but read many chapters. Good examples to get your head around particular refactoring patterns</li>
<li><a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215/ref=sr_1_1?s=books&ie=UTF8&qid=1302705711&sr=1-1">Domain Driven Design</a> - Eric Evan's now-famous book on how to turn business problems into rich object models. Great read.</li>
<li><a href="http://www.amazon.com/Real-World-Patterns-Rethinking-Practices/dp/0557078326/ref=sr_1_1?s=books&ie=UTF8&qid=1302706432&sr=1-1">Real World Java EE Patterns</a> - while this is a "java" book, the principles and design trade-off analysis that Adam Bien does for each pattern is universal. Good read.</li>
</ul><br />
<h2>Code</h2><ul><li><a href="http://www.amazon.com/Beautiful-Code-Leading-Programmers-Practice/dp/0596510047/ref=sr_1_1?s=books&ie=UTF8&qid=1302705967&sr=1-1">Beautiful Code</a> - Essays where programmers reflect on what is beauty in code. As the authors wax philosophic about their "beautiful" examples, you glean insight into their thought process. It's a nice read.</li>
<li><a href="http://www.amazon.com/Implementation-Patterns-Kent-Beck/dp/0321413091/ref=sr_1_1?ie=UTF8&qid=1302706192&sr=1-1-spell">Implementation Patterns</a> - Kent Beck's book about the low-level decisions we make as we actually type the code and create APIs (knowingly or unknowingly). One of my <b>top recommendations</b>. I really love this book.</li>
<li><a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?s=books&ie=UTF8&qid=1302706270&sr=1-1">Clean Code</a> - guide to code readability, writing code at appropriate abstractions, etc. A nice companion to Implementation Patterns. I had the pleasure of meeting Robert C Martin at a conference once. I'm sure I acted appropriately star-struck.</li>
</ul><br />
<h2>Other "meta" and philosophic musings</h2><ul><li><a href="http://www.amazon.com/Notes-Synthesis-Form-Harvard-Paperbacks/dp/0674627512/ref=sr_1_1?ie=UTF8&s=books&qid=1302706811&sr=1-1">Notes on the Synthesis of Form</a> - this is not a computer science book, but deals with the theory of what is design, and describes a methodology for decomposition. It's a quick read, and at least the first half is worth the exploration just to get some ideas in your head about methodologies for design.</li>
<li><a href="http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X/ref=sr_1_1?s=books&ie=UTF8&qid=1302706921&sr=1-1">Pragmatic Programmer</a> - what list would be complete without this one! Good overview of the pragmatic aspects of becoming a good programmer. From problem solving skills to tools, this is required reading. I think if you read this, then skip or at most skim <a href="http://www.amazon.com/Productive-Programmer-Theory-Practice-OReilly/dp/0596519788/ref=sr_1_1?s=books&ie=UTF8&qid=1302707582&sr=1-1">Productive Programmer</a></li>
<li><a href="http://www.amazon.com/Pragmatic-Thinking-Learning-Refactor-Programmers/dp/1934356050/ref=sr_1_3?s=books&ie=UTF8&qid=1302706921&sr=1-3">Pragmatic Thinking: Refactoring your wetware</a> - I mentioned this at the front of the post. I enjoyed most of this book-- in particular the front half. Some of the topics towards the end were less interesting, because they were more familiar. In any case at least the first three chapters are a great read.</li>
<li><a href="http://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0262560992/ref=sr_1_1?s=books&ie=UTF8&qid=1302707349&sr=1-1">The Little Schemer</a> - you can run through this in an afternoon. This is an introduction to recursion, via Scheme/LISP. This book is fun, because its a simple and unique format, but takes you through a journey that helps shape your mind to "think" of solutions recursively.</li>
<li><a href="http://www.amazon.com/Beautiful-Architecture-Leading-Thinkers-Software/dp/059651798X/ref=sr_1_1?s=books&ie=UTF8&qid=1302707446&sr=1-1">Beautiful Architecture</a> - This one wasn't as successful to me as Beautiful Code, but still worth a read. There are a few chapters you can skip, but a few (especially the first chapter) that are great.</li>
<li><a href="http://www.amazon.com/Beautiful-Data-Stories-Elegant-Solutions/dp/0596157118/ref=sr_1_2?s=books&ie=UTF8&qid=1302707446&sr=1-2">Beautiful Data</a> - I'm only about half way through this one, and need to spend more time with it, as I'm sure there are some gems in there I have yet to run across.</li>
</ul><br />
<h2>Reading TO-DOs</h2>These are books that are on my shelf to read next (that are relevant to this list at least)<br />
<ul><li><a href="http://www.amazon.com/Design-Essays-Computer-Scientist/dp/0201362988/ref=sr_1_1?s=books&ie=UTF8&qid=1302706584&sr=1-1">The Design of Design</a> - Fred Brooks (of Mythical Man Month fame) waxes about design philosophies and goes through a few case studies. Im really excited to make time for this.</li>
<li><a href="http://www.amazon.com/Masterminds-Programming-Conversations-Creators-Languages/dp/0596515170/ref=sr_1_1?ie=UTF8&s=books&qid=1302707225&sr=1-1">Masterminds of Programming</a> - interviews with the creators of many of the major languages used over the last 30 years. Looks promising.</li>
<li><a href="http://www.amazon.com/Thoughtworks-Anthology-Technology-Innovation-Programmers/dp/193435614X/ref=sr_1_1?ie=UTF8&s=books&qid=1302707626&sr=1-1">Thoughtworks Anthology</a> - I am going to be selective in which essays I read. I will start with those that are most applicable to my world, and then move out to the more "exotic" (relatively). I know that there are essays in here that will be more useful to my current world than others.</li>
</ul><br />
I feel like I'm missing some...<br />
<br />
SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-52579500049978755392011-03-06T14:15:00.003-06:002011-04-13T10:19:51.103-05:00Spring 2011 Reading ListI gave last Spring's reading list (which was more what I had read in the previous year) in <a href="http://manycupsofcoffee.blogspot.com/2010/01/spring-reading-list.html">this post</a>. This spring, I am going to write what I am currently reading or hope to finish this Spring.<br /><ul><li><a href="http://www.amazon.com/gp/product/193435659X">Seven Languages in Seven Weeks</a> - this book looks interesting, and certainly the challenge of trying to <i>meaningfully</i> cover seven languages and language philosophies in a short book will be interesting if nothing else.</li><li><a href="http://www.amazon.com/gp/product/0981531601">Programming in Scala</a> - I have "played" with Scala, but not done more than toy programs. However, from everything I know about it- I believe I will really enjoy it. I buy into a lot of the functional vs object oriented dualism, and certainly enjoy the terse syntax. I think there are still interesting questions with regards to software development economics (i.e. how do we integrate Scala in a team of mixed skill levels, cost trade offs, etc.)</li><li><a href="http://www.amazon.com/gp/product/0976458705">Thinking Forth</a> - I'm not particularly interested in Forth, but I am interested in language design and problem solving philosophies.</li><li><a href="http://www.amazon.com/gp/product/0321125215">Domain Driven Design</a> - this was recommended by a commenter in the previous post, and I picked it up. I've made it through quite a bit of the book, and have enjoyed it so far. I had always heard this book referenced by Fowler et al, and really I should've read it years ago...</li><li><a href="http://www.amazon.com/gp/product/3540288457">Introduction to Reliable Distributed Programming</a> - its a Springer book, 'nuff said. I've been through a few distributed computing books, and have a fairly broad knowledge of the space. I am hoping to get a more mature, theoretically rigorous view of the problems now.</li><li><a href="http://www.amazon.com/gp/product/0123705916 ">The Art of Multiprocessor Programming</a> - this book is great. I enjoyed the nice mix of intuitive description and theoretical rigor. It's a nice blend of theory and pragmatics. I really recommend reading this for anyone that wants in depth knowledge of parallel computing.</li><li><a href="http://www.amazon.com/gp/product/1604390085">Introductions to Neural Networks for Java</a> - this was an interesting book to <i>skim</i> I don't really want to recommend it, because most of it is explaining his neural network code base instead of the underlying concepts. In any case, its a nice thing to skim over an afternoon.</li><li><a href="http://www.amazon.com/gp/product/0131471392 ">Neural Networks and Learning Machines</a> - Great textbook for all the theoretical background and mathematical proofs regarding Neural Nets and machine learning. I've had to crack open my calc books to freshen up while going through this...its dense.</li><li><a href="http://www.amazon.com/gp/product/0121942759">Fuzzy Models and Genetic Algorithms for Data Mining and Exploration</a> - I can't recommend this book (see my Amazon review if you're curious why), but it does provide a decent vocab overview for the topics it covers.</li></ul><br />Well that's it for the moment! This spring is a bit more theory heavy than the previous list... that probably reflects my work and school change, which has been more research oriented in the last year. I'm not moving away from the <i>real world</i> just trying to get a more comprehensive grasp on both worlds in the areas which I am interested. I've always thought this was one of my strengths-- knowing enough theory to shape my thinking skills and be knowledgeable-- but continuously, deliberately enriching my implementation and practical skills to actually put the theory to good use! The intersection of the two is the more rewarding area for me, I think.<br /><br />SteveAnonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.comtag:blogger.com,1999:blog-4471109663192942674.post-87329176776097735652011-03-05T13:46:00.003-06:002011-03-05T14:05:07.132-06:00Building Derby with Eclipse gotchaThis is partially a reference for myself and for anyone else trying to build Derby 10 from source using Eclipse. My thesis project involves modifying the on-disk page layout for a database (long story for another post). I am currently using Eclipse for my IDE. I just wanted to document a quick pain point in case anyone else is Googling for the answer:<br /><br />I wanted to do a <b>clean build</b> of all of Derby. So I set up an ANT External Tool launch configuration:<ul><li>Launch the build.xml from the root Derby directory</li><li>Working directory is the root Derby directory</li><li>Refresh resources upon completion</li><li>Uncheck the "build before launch</li><li>Choose the <b>clobber, all</b> targets (clobber is a total clean)</li><li>Defaults for everything else</li></ul><br />I started to build and failed with the follow errors (I'm omitting some of the ones in the middle):<br /><blockquote><br /> [javac] C:\DerbyDev\java\build\org\apache\derbyBuild\javadoc\DiskLayoutTaglet.java:24: package com.sun.tools.doclets does not exist<br /> [javac] import com.sun.tools.doclets.Taglet;<br /> [javac] ^<br /> [javac] C:\DerbyDev\java\build\org\apache\derbyBuild\javadoc\DiskLayoutTaglet.java:25: package com.sun.javadoc does not exist<br /> [javac] import com.sun.javadoc.*;<br /> [javac] ^<br /><br />...<br /><br /> [javac] C:\DerbyDev\java\build\org\apache\derbyBuild\javadoc\UpgradeTaglet.java:102: cannot find symbol<br /> [javac] symbol : class Taglet<br /> [javac] location: class org.apache.derbyBuild.javadoc.UpgradeTaglet<br /> [javac] Taglet t = (Taglet) tagletMap.get(tag.getName());<br /> [javac] ^<br /> [javac] 40 errors<br /></blockquote><br />So as you can see from the first two errors -- its missing the dependency for Javadoc things. As it turns out Derby defines its own Taglet for Javadoc processing. All of these classes are defined in the JDKs tools.jar file, which is in the JDK's/lib directory (not included in the JRE).<br /><br />Derby's build script includes tools.jar by: <br /><pathelement path="${java15compile.classpath};${java.home}/../lib/tools.jar"/><br /><br />Well I went to my command prompt and looked at my environment variable and java_home was set to the JDKs location. So this should've worked. I added a new launch configuration to execute the <b>showenv</b> target, and added an echo statement to include java.home.<br /><br />I ran this and low and behold it was pointing to the JRE path, which doesn't have a tools.jar. So the world made sense now. In my eclipse installation, I have both the JDK and JRE installations defined in my preferences. For some reason (subconscious desire to shoot myself in the foot?), the JRE was chosen for this workspace, and thus the launch configuration used that.<br /><br />So to resolve the problem, you can change the external tools launch configuration for the ANT script. Go to the JRE tab and select <b>separate JRE</b> and choose the JDK. Or change the default JRE for the workspace, and leave the launch configuration set to <b>run in the same JRE as the workspace</b>.<br /><br />This isn't a tricky problem, but can be a little misleading...plus I haven't posted in a while ;-)Anonymoushttp://www.blogger.com/profile/06360294285988063025noreply@blogger.com