QuickFIX/J
  1. QuickFIX/J
  2. QFJ-552

Message Stores expected to be thread safe but are not

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.4.0, 1.5.0
    • Fix Version/s: None
    • Component/s: Engine
    • Labels:
      None
    • Environment:
      Linux + JDBC + SQL Server 2005

      Description

      SessionState.java starts with the following bit of code:

      /**
       * Used by the session communications code. Not intended to be used by
       * applications.
       *
       * All dynamic data is protected by the session's intrinsic lock. The
       * log and message store implementation must be thread safe.
       */
      public final class SessionState {
          private final Object lock;
          private final Log log;

          // MessageStore implementation must be thread safe
          private final MessageStore messageStore;
      ...
      }

      Yet, looking at the JdbcStore.java and MemoryStore.java implementations, they are in fact not thread safe as designed (may also be true for FileStore.java, but haven't checked).

      The memory store uses a regular java.util.HashMap for all its operations, which is clearly not thread safe. I have never actually seen this cause a problem in practice, however.

      The jdbc store does not synchronize its use of the jdbc connection, which can lead to race conditions inside the close() method of the jtds prepared statement, as shown in the stack trace below (specifically, the jtds close() method has a boolean to determine if its connection is already closed in which case it will not doubly close it despite any subsequent calls. This value is set once the close routine is complete but occurs after the connection object has already been assigned a null value- this allows another thread to potentially access the null connection object before the boolean guard has been set). Note that this bug occurs about once a week in a production environment (usually during startup), although its frequency is probably higher than average due to many quickfixj applications accessing the same database concurrently.

      Example 1:

      java.lang.NullPointerException
      at net.sourceforge.jtds.jdbc.JtdsStatement.close(JtdsStatement.java:868)
      at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.close(JtdsPreparedStatement.java:485)
      at org.logicalcobwebs.proxool.AbstractProxyStatement.close(AbstractProxyStatement.java:115)
      at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:93)
      at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
      at quickfix.JdbcUtil.close(JdbcUtil.java:143)
      at quickfix.JdbcStore.storeSequenceNumbers(JdbcStore.java:288)
      at quickfix.JdbcStore.setNextTargetMsgSeqNum(JdbcStore.java:272)
      at quickfix.JdbcStore.incrNextTargetMsgSeqNum(JdbcStore.java:173)
      at quickfix.SessionState.incrNextTargetMsgSeqNum(SessionState.java:359)
      at quickfix.Session.nextLogon(Session.java:1535)
      at quickfix.Session.next(Session.java:720)
      at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:106)
      at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:70)
      at quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:86)
      at java.lang.Thread.run(Thread.java:619)

      Example 2:

      java.lang.NullPointerException
      at net.sourceforge.jtds.jdbc.JtdsStatement.close(JtdsStatement.java:868)
      at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.close(JtdsPreparedStatement.java:485)
      at org.logicalcobwebs.proxool.AbstractProxyStatement.close(AbstractProxyStatement.java:115)
      at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:93)
      at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
      at quickfix.JdbcUtil.close(JdbcUtil.java:143)
      at quickfix.JdbcStore.set(JdbcStore.java:259)
      at quickfix.SessionState.set(SessionState.java:299)
      at quickfix.Session.sendRaw(Session.java:1736)
      at quickfix.Session.generateLogon(Session.java:1430)
      at quickfix.Session.next(Session.java:1357)
      at quickfix.mina.SessionConnector$SessionTimerTask.run(SessionConnector.java:248)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
      at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
      at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:619)
      1. SynchronizedMessageStore.java
        4 kB
        Carmelo Piccione
      2. SynchronizedMessageStoreFactory.java
        0.9 kB
        Carmelo Piccione

        Issue Links

          Activity

          Hide
          Carmelo Piccione added a comment -

          A simple but thread safe message store implementation. The constructor takes a MessageStore instance as input and delegates all method calls to it through an object lock. This is a work around which allows safe usage of the original QFJ message stores such as JdbcStore, FileStore, and MemoryStore.

          Show
          Carmelo Piccione added a comment - A simple but thread safe message store implementation. The constructor takes a MessageStore instance as input and delegates all method calls to it through an object lock. This is a work around which allows safe usage of the original QFJ message stores such as JdbcStore, FileStore, and MemoryStore.

            People

            • Assignee:
              Unassigned
              Reporter:
              Carmelo Piccione
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:

                Development