Archive for April, 2008

h1

Thread-safe code

April 20, 2008

All software is buggy. I am not especially worried about finding bugs in code, but when you identify the same bug rearing its head in multiple places, that’s a cause for concern. How do you satisfy yourself that you have rooted out all instances of the bug? Do you just fix each one as you find them or can you do something about the problem?

So what’s the bug? In any Java Spring application, storing state in a singleton bean is inherently thread-unsafe and a recipe for disaster. Each such instance needs to be considered on its own merit to determine if the code provides thread-safe access to the state. I considered using some sort of static bug-detection tool such as FindBugs to help me find more instances of this bug. And maybe it is possible. I can’t think of any. I also looked at Google’s Singleton Detector, but that deals with another Singleton pattern – not singleton beans in a Spring application.

So I decided to write some code to identify a short-list of candidates that could be inspected manually.

  1. First I load the application context and get a list of singleton beans.
  2. I then filter out all beans that don’t belong to the package I am interested in.
  3. Going through all variables in each bean, I ignore all statics and references to other Spring beans.
  4. I then assume that properties set through the Spring application context are not meant to be mutable state and ignore those fields as well.
  5. This then gives me my candidate list. Unfortunately, this also includes properties assigned through the Spring application context but using constructor arguments, and fields whose names are different from their setters.

I will keep my mind open to refine this, or to approach this from an entirely different angle. For now, here’s the code:

package com.ragstorooks.testing;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Vector;

import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;

public class SpringSingletonStateDetector {
  private static String packageName = "com.ragstorooks";
  private static String applicationContextName = "applicationContext.xml";

  public void testSingletonState() throws Exception {
    ClassPathXmlApplicationContext applicationContext =
      new ClassPathXmlApplicationContext(applicationContextName);
    Collection<Object> beanInstances = new Vector<Object>();

    System.err.println("Spring singleton classes and their fields:");
    System.err.println();
    String[] beans = applicationContext.getBeanDefinitionNames();
    for (String b : beans) {
      Object bean = applicationContext.getBean(b);
      beanInstances.add(bean);
    }

    for (String b : beans) {
      if (applicationContext.isPrototype(b)) continue;

      boolean namePrinted = false;
      Object bean = applicationContext.getBean(b);
      Class<?> beanz = bean.getClass();
      if (beanz.getPackage() == null ||
          !beanz.getPackage().getName().startsWith(packageName))
        continue;

      for (Class<?> clazz = beanz;
          clazz.getPackage() != null &&
          clazz.getPackage().getName().startsWith(packageName);
          clazz = clazz .getSuperclass().getClass()) {
        Field[] beanFields = beanz.getDeclaredFields();
        if (beanFields.length == 0) continue;

        for (Field beanField : beanFields) {
          beanField.setAccessible(true);
          if (Modifier.isStatic(beanField.getModifiers()) ||
              beanInstances.contains(beanField.get(bean)))
            continue;

          // Hopefully properties set via Spring are ok and can be ignored!
          if (applicationContext.getBeanFactory().getBeanDefinition(b).
              getPropertyValues().contains(beanField.getName()))
            continue;

          if (!namePrinted) {
            System.err.println(String.format("%s%s(%s):",
                System.getProperty("line.separator"), b, clazz.getSimpleName()));
            namePrinted = true;
          }
          System.err.println(String.format("\t%s: %s",
              beanField.getName(), beanField.getType().getSimpleName()));
        }
      }
    }

    applicationContext.destroy();
  }

  public static void main(String[] args) throws Exception {
    new SpringSingletonStateDetector().testSingletonState();
  }
}
h1

No losses in 5 straight games now

April 20, 2008

I managed to hold a much higher-rated opponent to a draw on the white side of a Caro-Kann this past week. As is typical in the Caro-Kann, white enjoyed a space advantage for most of the game, but black was solid and impregnable. Once he was able to make his pawn breaks, we liquidated to a drawn endgame.

After the game, we discussed a couple of variations where black could have played more aggressively and ended up with an extra pawn in a rook-endgame, but being in severe time trouble, he chose to take the safe approach. All in all, quite a boring game indeed.

h1

Back from my hiatus

April 15, 2008

After a long break, I finally played a game last week and won (with black). You can replay it here.

1.e4 c5 2.c4 e6 3.d3 Nc6 4.Nf3 d5 [Nf6] 5.cxd5 exd5 6.exd5 Qxd5 7.Nc3 Qd8 8.Qb3!?
When I played d5, I thought I might get into some trouble opening up my king before finishing development. On the other hand, I couldn’t stomach the idea of playing a very closed position with lots of maneuvering. On the plus side, he is also not castled and he has an isolated d-pawn that I can target. I hadn’t seen white’s 8th move when I played d5 and I am not sure I would have gone for this line if I had seen it. But it presents no real dangers though I have to keep a wary eye out for tactical ideas on f7.

8…Nf6 9.Ng5?
Trying to immediately target the f7 square. At this point however, it is easily defended, and in fact gives me the initiative.

9…Qe7+ 10.Be2 Nd4 11.Qd1 Bg4 12.Nge4?
Giving up a pawn in the process. Be3 was perfectly playable, developing another piece and preparing to castle.

12…Nxe4 13.dxe4 Bxe2 14.Nxe2 Qxe4
At this point, I was feeling extremely good about my position. I was up a pawn, my pieces were active and he couldn’t castle because his bishop on e2 would be underprotected. He could play Be3 or f3, to try and lessen the pressure but that would create new weaknesses that I could target.

15.O-O?!
I had been so sure he couldn’t castle that I had all but ignored that move in my calculations. When he castled anyway, I had to take a closer look at the position and realized that he was counting on winning the piece back by pinning my knight on e2. Instinctively I felt I should be able to grab his piece and hold on but even after 20 minutes of thought, I couldn’t find a concrete refutation over the board. Not wanting to give him any sort of initiative, I declined the piece and played…

15…Nc2??
I definitely need to work on my tactics. I had seen 15…Nxe2+ 16.Kh1 Rd8 17.Bd2 but couldn’t figure out a continuation beyond this. The computer shows 17…Rd6! 18.Re1 Re6 and I can hold on to the extra piece. I was so concerned about my exposed king that I failed to see the rook lift! My move gives him back the initiative.

Analysis diagram after 18...Re6

16.Nc3 Qg6 17.Rb1?
I was really worried about 17.Nd5 as that would have given me some hard problems to solve.

17…Rd8 18.Qe2+ Be7 19.Qb5+?
I think Nb5 was actually stronger, threatening Nc7+ and Nxa7.

19…Rd7 20.Be3 a6 21.Qa4 b5 22.Nxb5?
Now, down a piece, white goes down quickly. 22.Qf4 would have made life far more difficult for me. Any other queen move however, and it would have been trapped.

22…axb5 23.Qxb5 Nxe3 24.fxe3 Qd3 25.Qb8+ Rd8 26.Qf4? O-O 27.Rbd1 Qg6 28.Qc7 Bd6 29.Qb7 Qh5 30.g3 Bxg3 31.hxg3 Rxd1 32.Rxd1 Qxd1+ 33.Kf2 Rd8 34.Qe4 0-1