EoD SQL 2.0 – Let the Bug Hunting begin!

Now that I’ve finally got EoD SQL 2.0-alpha out the door, it’s time to start bug hunting.

Part of the upcoming 2.0 version is a lot of new unit-tests. In the past EoD SQL was not test-covered nearly enough, and so several bugs slipped under the carpet (in particular in the 1.1 release).

Already 1 new bug has been found and fixed, and 2 older bugs (introduced in 1.1) have also been fixed. In my use of the 2.0 code-base (during development of other projects), I’ve found the 2.0 code to be an amazing performance improvement over the 1.0 code-base.

For those interested, the 2.0 code is so much faster because of two structural changes:

  • Less thread contention
    • Much of the synchronization locking has been removed
    • Some of the code now requires that you rely on Java’s implicit locks to ensure thread-safety
      • For example, you should set-up your own TypeMappers in a static initializer or another thread-safe structure (ie: ServletContextListener).
  • Much less branching through if and switch statements
    • There are far more classes in the code-base, and as such the API has grown in size
    • Many of the new classes use inheritance to avoid conditional branches

An example of the removal of conditional branches is the binding of a column value to a field or method. In the 1.0/1.1 code-base it was done like this:

for(int i = 1; i <= meta.getColumnCount(); i++) { Member member = columnMap.get(new ColumnName(meta.getColumnName(i))); if(member != null) { if(member instanceof Field) { Field f = (Field)member; TypeMapper mapper = types.get(f.getType()); if(mapper != null) { Object value = mapper.get(results, i); if(results.wasNull()) { value = null; } f.set(target, value); } else { throw new SQLException("No TypeMapper for: " + f.getType().getName()); } } else if(member instanceof Method) { Method m = (Method)member; Class javaType = m.getParameterTypes()[0]; TypeMapper mapper = types.get(javaType); if(mapper != null) { Object value = mapper.get(results, i); if(results.wasNull()) { value = null; } m.invoke(target, value); } else { throw new SQLException("No TypeMapper for: " + javaType.getName()); } } } }[/sourcecode] In the new 2.0 code-base, the code looks like this: [sourcecode language="Java"] for(int i = 0; i < columns.length; i++) { Object value = mappers[i].get(row, i + 1); if(row.wasNull()) { value = null; } columns[i].set(into, value); }[/sourcecode] Yup! That is the same piece of code! In the 2.0 version, we look at the ResultSet the first time around and construct all of the binding information into 2 arrays, one of TypeMappers and the other of a new MutableColumn class which replaces my use of the java.lang.reflect.Member class.

This means that the DataObjectBinding‘s cannot be reused as much as before (one per method, rather than one per DataObject class), but they are much much faster since all the binding work is figured out up front.

I’ll probably be posting more on this pattern in the future, since it has some massive impact on how your code works (and how HotSpot can optimize it).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: