Newsmap is a really neat way to visualize news headlines available via the Google News RSS feeds.
2007-11-23
2007-11-22
Configuring Mac OS X Terminal
I recently installed Leopard (Mac OSX 10.5) on a new mac. There are a few factory settings I usually change on a new installation, although by far fewer than I do typically with Windows. One of them is the default keyboard configuration for Ctrl+Left Arrow, Ctrl+Right Arrow, Page Up, Page Down, Home, and End in Terminal. The default settings drive me a bit potty since I'm used to using Linux and emacs every day at work.
Changing them is easy, fortunately. Just visit Keyboard under Settings in Terminal->Preferences, and modify the following keys, so that their action matches the value shown. You can edit the keystroke for an item by double clicking on it, selecting "send string to shell", and typing the indicated keys.
| Key | Action | Keystrokes |
|---|---|---|
| control cursor left | \033b | ESC b |
| control cursor right | \033f | ESC f |
| end | \005 | CTRL+e |
| home | \001 | CTRL+a |
| page down | \026 | CTRL+v |
| page up | \033v | ESC v |
Posted by
Brian Duff
at
22:20
13
comments
Links to this post
Labels: apple
2007-11-14
Detecting Concurrent Changes with the Decorator Pattern
Recently, our bug tracking system started receiving reports of a ConcurrentModificationException. The API in question was only ever supposed to be used on one thread, and yet a caller somewhere was making modifications on a background thread.
One thing that makes it tricky to diagnose this kind of problem is that a ConcurrentModificationException thrown during iteration only tells you that a concurrent modification was detected. But no information is present in the stack trace about where the rogue write actually happened. Wouldn't it be nice to have something like this?
java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) ... Caused by: java.lang.Throwable: List modified at ... at org.foo.SomeRogueCaller.writeOnTheWrongThread(SomeRogueCaller.java:30)
It's pretty easy to do this using the decorator pattern. The basic idea is to write a decorator for java.util.List that records a stack trace when modifications are made to the list, and sets the trace of the last modification as the cause of any ConcurrentModificationException thrown while iterating.
I used the Google Collections Library as part of my implementation, primarily because its ForwardingList, ForwardingListIterator and ForwardingIterator base classes make it really easy to decorate the respective collections classes.
So the basic idea is to write a decorator that can audit writes. I created a subclass of ForwardingList that stores a Throwable representing the last modification. The audit method will be used to record modifications, and the setLastModificationAsCause method is used to initialize the cause of a ConcurrentModificationException to the last modification (if any).
final class AuditedWriteList<E> extends ForwardingList<E> {
private Throwable lastModification;
protected AuditedWriteList(List<E> delegate) {
super(delegate);
}
private void audit() {
synchronized (this) {
lastModification = new Throwable( "List modified" );
}
}
private void setLastModificationAsCause( Throwable t ) {
synchronized (this) {
if ( lastModification != null ) t.initCause( lastModification );
}
}
// ...
}
Now, we override all List methods that modify the list, and make them audit. For example, here's the implementation for add(E):
@Override
public boolean add( E object ) {
audit();
return super.add( object );
}
Finally, we implement the iterator() and listIterator() methods to return a decorator Iterator and ListIterator respectively that catches a ConcurrentModificationException and calls the setLastModificationAndCause method:
@Override
public Iterator<E> iterator() {
return new AuditingIterator<E>( super.iterator() );
}
// Inner class
private final class AuditingIterator<T> extends ForwardingIterator<T> {
protected AuditingIterator(Iterator<T> delegate) {
super( delegate );
}
@Override
public T next() {
try {
return super.next();
} catch ( ConcurrentModificationException e ) {
setLastModificationAsCause(e);
throw e;
}
}
}
Now, if we do something like this:
List<String> list = newAuditedWriteList( Lists.newArrayList( "One", "Two", "Three" ) );
for ( Iterator<String> i = list.iterator(); i.hasNext(); ) {
i.next();
list.add( "Four" );
}
We get a helpful stack trace telling us exactly where the modification took place. The beauty of the decorator approach is that the only change we made to our client code was to wrap the creation of our list with the call to newAuditedWriteList. Since this diagnostic is likely to be slow when there are a lot of writes, it could be conditionally turned on in debug environments.
The full source code is available in the dubh-examples google code module.
Posted by
Brian Duff
at
17:36
2
comments
Links to this post
Labels: collections, concurrency, java
