Sort algorithm changes in Java 7

I just got the info from one of out customers that an error in the export function of a Grails application happend. The stacktrace looked like:

Error Details

Error 500: Executing action [export] of controller [ExportController] caused exception: Runtime error executing action
Servlet: grails
URI: /app/grails/export/export.dispatch
Exception Message: Comparison method violates its general contract!
Caused by: Comparison method violates its general contract!
Class: ExportPrintController
At Line: [105]
Code Snippet:
Stack Trace

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at com.troii.app.web.ExportController$_closure2.doCall(ExportController.groovy:105)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

I did some web search and came up with this interesting discussion on stackoverflow. Which links to the compatibility information page of JDK7 and a specific change they made in Java 7: changing the default sort algorithm from MergeSort to TimSort in the java.util.Arrays.sort method.

So a quick workaround for this issue was to add -Djava.util.Arrays.useLegacyMergeSort=true to the tomcat JVM environment – which forces the app to use the old algorithm.

To really fix the issue I had to make a change to the code because it really violated the Comparable contract. Our code looked like:

int compare(ExportTerm e1, ExportTerm e2) {
  if (e1.sortLabel == null) {
    return -1
  }
  if (e2.sortLabel == null) {
    return 1
  }
  return collator.compare(e1.sortLabel, e2.sortLabel)
}

which is wrong, because if you compare two elements where the sortLabel is null on both, the return value would be -1 or 1, depending on the order you compare them – which violates the contract.

Correct it has to look like:

int compare(ExportTerm e1, ExportTerm e2) {
  if (e1.sortLabel == e2.sortLabel) {
    return 0
  }
  if (e1.sortLabel == null) {
    return -1
  }
  if (e2.sortLabel == null) {
    return 1
  }
  return collator.compare(e1.sortLabel, e2.sortLabel)
}

Technologieplauscherl am 22.11.2012 bei netural

Ich war heute endlich wieder mal auf einem Technologieplauscherl. Das hat heute in den Räumlichkeiten von netural stattgefunden – vielen Dank dafür, die Verpflegung war erstklassig! (Gösser Radler und Brötchen von Jindrak)

Beim heutigen Plauscherl handelte es sich um eine “Book Edition!” – Hauptthema waren also Bücher.

Als Ausreisser aus der “Book Edition” hat Bernhard Wurm TypeScript demonstriert – eine interessante Sprache von Microsoft die nach (tatsächlich schönem, lesbaren) JavaScript compiliert wird. Aus dieser Präsentation ist eine ganz interessante Diskussion über Sprachen mit ähnlichen Ansätzen entstanden, wie zB CofeeScript und Dart.

Es war wieder mal ein super Abend: Bier, Snacks und Geeks mit denen man über interessante Themen diskutieren und ranten kann ;-)

Self made Fusion Drive


After reading @jollyjinx posts on tumblr about his experiments with Fusion Drive on older Macs I wondered if this might be possible with my configuration too. Some more googeling brought up this post of Tomasz Korwel who created a bootable Fusion Drive on his MacBook Pro Late 2010 – which me made me very sure that it would work on my MacBook Pro 15″ Mid 2010. An Austrian iOS developer colleague trying it too on his iMac and blogging about it finally convinced me that I have to try it myself.

The most interesting part of Fusion Drive for me was, that is just a Software feature – it does not depend on any specific hardware. When Apple announced that their new iMacs would have the option for a Fusion Drive, I though it would be a special harddisk containing an SSD and a spinning disk in one case. But in fact you can create a Fusion Drive out of any disks in you Mac by using features of the built in CoreData storage system.

Why would you want a Fusion Drive?
For not having to think about where to put which file.

What does that mean?
I am using my MacBook Pro with a 160 GB Intel X-25 SSD and a Toshiba 500 GB harddisk since I bought it in May 2010. When I bought the MacBook I moved the SSD over from the Dell notebook, I was using before, and put the Toshiba Hardisk into an Optibay while removing the DVD drive. I put almost everything on my SSD: operating system, application, documents, source code. I used the harddisk only for “big data” like movies, music, pictures, virtual machines, downloads, disk images. This setup works great until one of the disks gets full and the other one has space, you start to move things around, you need the changes paths or make links – this is ugly.

How to get a Fusion Drive?
First I made a backup of my two disk with Carbon Copy Cloner to two partitions on an external drive, this way I did not have to reinstall my system.

I booted from a USB thumb drive containing the Mountain Lion installer and went into the Terminal app. There I executed the command

diskutil list

to list all my drives:

The list showed me that my SSD was disk0 and the Toshiba harddrive was disk1 so I ran the following command:

diskutil cs create FusionDrive disk0s2 disk1s2

which created a Logical Volume Group out of the two disk:

On this Logical Volume Group I could created a filesystem by running the command

diskutil cs createVolume E8E5214B-BD8D-4023-839E-99E42FA63485 jhfs+ FusionHD 650GB

Finished. After leaving the Terminal the new FusionHD showed up with 650 GB capacity in the Mountain Lion installer. I did not install the system but restarted and booted from the external disk containing the clone I made before. I restored the backup of my SSD to the newly created FusionHD and was immediately able to boot from the Fusion Drive.

The last step was to copy back my media files from the backup of my harddisk wich went smooth to. Everything is running fine so far and I got enough space on my combined two disks again.

This is how the output of

diskutil cs list

now looks like:

What are the drawbacks of this?
You will have to take more care about backups, because now, if one of two disks fails, you will have a problem. I am used to this because I worked on a striped disk array for a long time and I already have a good backup strategy in place.