Tuesday, December 30, 2008

Ubuntu gnome session management

Ubuntu 8.04 gnome session manager is very unreliable and unintuitive. You can hardly accomplish anything using the UI. It is amusing that while one can think of it as a helper program to help you restore your programs between system restarts it can also be used to kill programs currently running on your computer, unexpectedly. The author clearly had no idea of how UI should be designed in general, nor a plan for what he was trying to get accomplished with this program specifically. It is the single worst piece of software included with Ubuntu. Oh well one of these days I'll write a better one and get it included with Ubuntu.

However you can partially turn off this useless software by clicking "Automatically remember..." in the Session Options Tab and instead edit the file ~/.gnome2/sessions by hand.

E.g. I added this program to get started automatically with my X session:
16,RestartCommand=/usr/bin/gvim /home/dmitri/Documents/Status.txt /home/dmitri/Misc/GTD.txt

Unfortunately, this displays a strange error message in VIM. The error message only has an error icon and the path to the file. However after I click on it, all the files are opened just fine, except the second one is opened twice. Oh well, it's still 2008 I guess: it's 2009 that will be the year of the Linux desktop.

Wednesday, December 10, 2008

Compensating for lack of unsigned types in Java

For some reason Java has no unsigned primitive types, which makes it really limiting when writing network code or doing bit manipulation.

One workaround is to cast to a longer-type and mask out significant bits.

E.g.:

byte b = getAByte(); // Get a byte from somewhere
int wrong = (int) b;
int right = (int) b & 0xff;

Int wrong will work most of the time, except when you have most-significant bit of the byte set. Because in Java most-significant bit holds the sign, the following happens:

byte b = getAByte(); // let's say this holds 0xff
int wrong = (int) b; // becomes -127 or -0x7f
int right = (int) b & 0xff; // becomes 255 or 0xff

In fact the Java compiler checks this so the following assignments would show compile errors:

byte wrong = 0xff;
byte wrong = 0x80;
byte right = 0x7f;

Monday, December 01, 2008

Getting complete Java exception stack trace

JDK Throwable.printStackTrace() function attempts to compact the stack trace of an exception by eliminating common parents of all stack elements. However it is often helpful to see the entire stack trace.

E.g. if using JDK you may write this function to get the stack trace of an exception as a String:

public static String formatStackTrace(Throwable e) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
return stringWriter.toString();
}


To obtain the complete stack trace you may use this function:

private static String formatStackTrace(Throwable e) {
StringBuffer str = new StringBuffer();
str.append(e.getClass().getName()).append(": ");
str.append(e.getMessage());
StackTraceElement[] stack = e.getStackTrace();
for (int i = 0; i < stack.length; i++) {
StackTraceElement element = stack[i];
str.append("\n\tat ").append(element.getClassName()).
append(".").append(element.getMethodName()).
append("(").append(element.getFileName()).append(":").
append(element.getLineNumber()).append(")");
}

Throwable cause = e.getCause();
if (cause != null) {
str.append("\nCaused by: ").append(formatStackTrace(cause));
}
return str.toString();
}

Monday, November 24, 2008

Script to reuse Eclipse project when switching code directory underneath

We're using subversion transactions here at Snaplogic: when working on a bug fix or new feature we create a branch off main tree, then after the change is complete we merge it into the main tree. Transaction management can be easily automated using shell scripts: tx-begin, tx-commit, etc.

However if you are using Eclipse there is a problem that each time you create a transaction you have to recreate your project. Even though you're working on the code, and have set up your project paths, and environment, and launch configurations, you have to recreate all that when you switch from one transaction to another, because each transaction resides in a different directory.

You want to have transactions in separate directories to be able to go back and forth between them, if you are working on several at a time, and for historical purposes. It may seem that you can overcome this limitation of Eclipse by using symlinks, and you can, to a degree, however Eclipse converts the symlink to the absolute file system path, and stores that in its project file.

So this is the missing piece of the puzzle of reusing the same Eclipse project when switching project directories underneath.

This python script will edit the .location file stored in the .metadata directory of Eclipse's resources plugin.

#!/usr/bin/python
# Pass destination path as the parameter
import sys

LOCATION = "/home/dmitri/workspace/.metadata/.plugins/org.eclipse.core.resources/.projects/code/.location"
PREFIX = "URI//file:"
replace_path = PREFIX + sys.argv[1]
file = open(LOCATION, "rb")
contents = file.read()
start = contents.index(PREFIX)
length = ord(contents[start-1:start])
sys.stdout.write(contents[0:start-2] + chr(0) + chr(len(replace_path)) + replace_path + contents[start + length:])


You run it as follows:

fix-eclipse /home/dmitri/workspace/all-code/dmitri_snaphome-2/snaplogic/python > /tmp/.location
cp /tmp/.location /home/dmitri/workspace/.metadata/.plugins/org.eclipse.core.resources/.projects/code/.location

Tuesday, September 30, 2008

Fixing java disk swapping problem on linux

Running JDK 1.6 on my ubuntu hardy laptop I noticed hard disk drive light flashing every second. Disk activity was happening when running any java program, e.g. Eclipse, or Tomcat. I pinned this down to the JVM's performance files in the /tmp/hsperfdata directory. To turn off disk swapping, and prolong your battery and disk live, run JVM with the following option -XX:-UsePerfData

E.g. for Eclipse you may edit eclipse.ini and add this line at the end:
-XX:-UsePerfData

These were the steps I took to diagnose the issue:

# Become root
sudo su -

# Stop loggers
/etc/init.d/sysklogd stop
/etc/init.d/klogd stop

# Enable block I/O debugging
echo 1 > /proc/sys/vm/block_dump

# Monitor kernel ring buffer
while true; do dmesg -c; sleep 1; done;

...
Examine the output
...
[ 562.539286] java(10323): dirtied inode 8224835 (10310) on sda1
[ 562.539293] java(10323): dirtied inode 8224835 (10310) on sda1
[ 562.545651] eclipse(13917): dirtied inode 8224819 (13898) on sda1
[ 562.545658] eclipse(13917): dirtied inode 8224819 (13898) on sda1

# Find out filename from inode
find / -inum 8224819 2> /dev/null
/tmp/hsperfdata_dmitri/13898

# We're done
# Turn off block I/O debugging
echo 0 > /proc/sys/vm/block_dump

# Start loggers
/etc/init.d/sysklogd start
/etc/init.d/klogd start