5 Replies Latest reply on Jan 10, 2005 2:45 PM by adrian.brock

    CachedConnectionManager implementation

      So I was playing with reimplementing the (CCM) cached connection manager yesterday.

      Although I managed to solve the problem mentioned here
      http://jira.jboss.com/jira/browse/JBJCA-12
      and some of the other problems I know about.

      The solution I have does little to resolve the underlying problem of this features

      The CCM is responsible for the following features.

      1) Keeping track of Unshareable connections as defined on resource-refs.
      With the current implementation this only works if you set the misnamed
      SpecCompliant to true (but then you lose the connection close checking)

      2) Lazy enlistment of connections into user transactions, e.g.

      Connection c = connectionFactory.createConnection;
      UserTransaction ut = ...
      ut.begin(); // does ut.enlistResource(c);
      ...
      ut.commit();
      ...
      ut.begin(); // does ut.enlistResource(c) again
      


      3) Connection close checking - keeping track of which beans opened which
      connections and closing them with warnings.

      4) SpecCompliant=true processing (which doesn't look very spec compliant to me :-)
      This is similar to the connection close checking except instead of closing the
      connection it disconnects the connection from the managed connection (which is
      returned to the pool). When the ejb is reinvoked, it automatically reconnects
      i.e. gets a ManagedConnection for the connection handle.

      The major problem with this processing is that there is no notification that
      the bean has vanished/bean garbage collects so nothing tidies up the map
      of object -> connection handles in the CCM.

      The original JIRA problem mentioned above is that if somebody does a getConnection()
      or connection.close() during transaction synchronization, the context is incorrect.
      It is the context of the caller since we are outside the CCM interceptor.

        • 1. Re: CachedConnectionManager implementation

          What is really required is a pattern that comes up a lot,
          but we currently have no direct implementation for it.

          It is the combined Transaction/InvocationContext pattern.

          i.e. When we have a transaction state should be synchronized with it.
          When there is no transaction state should tidied up when the invocation finishes.

          There are extra complications relating to recursive calls, e.g. Entity re-entrance.
          The pattern also needs to take into account singletons like Servlets and JMX
          when outside the EJB context.

          • 2. Re: CachedConnectionManager implementation

            I will call this pattern InvocationContextLocal.

            A simple/naive implementation is:

            Add an interceptor before the transaction interceptor that maintains a thread local
            stack of invocation contexts.

            Each part of the system will use its own "slot" in the invocation context to store state.
            It can also define its own order of close context processing.

            In the transaction demarcation interceptor "enlist" this context in the transaction
            for synchronization at commit/rollback.

            On the invocation return stroke close the context (unless it was enlisted
            in a transaction).
            If there is a transaction, the transaction synchronization does the context close
            processing.

            • 3. Re: CachedConnectionManager implementation

              Obvious problems with this approach:

              1) Every invocation needs to establish an invocation context on the off chance
              one is needed.
              2) When outside a transaction, state will be cleaned up later than what is done now
              (which is done in each interceptor).
              The reason for not doing it in an interceptor is that we want to control the order
              of cleanup. e.g. we don't want to release the entity lock until we have finished
              checking all the connections have been closed. But we don't do that until
              the db synchronize has been performed.

              Logically, the invocation context interceptor would be better placed after the
              Lock/Instance/Reentrance interceptors. Especially since the instance interceptor
              is what gives us the object instance.

              But the problem with doing that is that the context on the thread local stack
              is cleaned up too early. Meaning transaction synchronization uses the wrong context.
              We cannot defer the cleanup to transaction synchronization since this invocation
              might not be the demarcation point of the transaction.

              • 4. Re: CachedConnectionManager implementation
                bill.burke

                These seem like separate problems that should be solved in different places.

                2 and 3 seem like they should be implemented at the JCA level.

                For 2, when the connection is accessed, check to see if the current thread is associated with a transaction, if so enlist the connection with the transaction.

                For 3, this should also be handled by JCA. If a connection is obtained while within the context of a tx a Tx synchronization should be used to automatically close/release the connection in afterComplete. You shouldn't have to use EJB to get this automatic connection closing. If the connection has already been associated, then there is no need to register this synchronization.

                Is the TX still associated with the thread in Synchronization.afterComplete? If so, if somebody calls getConnection within afterComplete, the JCA impl should check to see if the current TX is committed, if so, do not enlist the connection with the TX and treat it as if it was dissassociated.

                One other thing on #3. I think it should also allocate an Exception when getConnection() is called. That way, if you as a developer want to find out exactly where a connection was leaked, you can find out by printing the stack trace of all places getConnection() was called and not cleaned up. You cannot do this with the CCM solution currently.

                I don't not understand 1/4. I'll have to read the spec.


                • 5. Re: CachedConnectionManager implementation

                   

                  "bill.burke@jboss.com" wrote:
                  These seem like separate problems that should be solved in different places.

                  2 and 3 seem like they should be implemented at the JCA level.

                  For 2, when the connection is accessed, check to see if the current thread is associated with a transaction, if so enlist the connection with the transaction.


                  Enlist which connections? If they are not recorded against the EJB instance
                  by a context interceptor how do you know the list?
                  Without an Invocation Context demarcation all you could have is a Thread
                  list of connections some of which might belong to a previous EJB or WEB
                  container in the stack.


                  For 3, this should also be handled by JCA. If a connection is obtained while within the context of a tx a Tx synchronization should be used to automatically close/release the connection in afterComplete. You shouldn't have to use EJB to get this automatic connection closing. If the connection has already been associated, then there is no need to register this synchronization.

                  Is the TX still associated with the thread in Synchronization.afterComplete? If so, if somebody calls getConnection within afterComplete, the JCA impl should check to see if the current TX is committed, if so, do not enlist the connection with the TX and treat it as if it was dissassociated.


                  Fine as long as there is a transaction. If there is no transaction they need
                  closing at end of invocation.

                  But in both cases only if the EJB instances does not mark them as
                  unshareable resource-refs. JCA does not know this information without being
                  told by the EJB/WEB container.


                  One other thing on #3. I think it should also allocate an Exception when getConnection() is called. That way, if you as a developer want to find out exactly where a connection was leaked, you can find out by printing the stack trace of all places getConnection() was called and not cleaned up. You cannot do this with the CCM solution currently.


                  Yes you can, since it already does this.