private void queueInvocationCommon(AbstractInvocation invocation, ConversationImpl conversation)
   {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "queueInvocationCommon", new Object[] {invocation, conversation});
      if (dispatcherEnabled)
      {
         // Start F201521

         try                                                                              // D202636
         {                                                                                // D202636
            // First job is to ask the ConversationReceiveListener for the object which may contain
            // a dispatch queue. If they return null here, we assume that we should use the dispatch
            // queue held in the Conversation.
            // Note this method may throw a RuntimeException indicating that there was a problem
            // executing this method. If this occurs, we don't want to dispatch this segment as
            // the conversation will be closed.
            Dispatchable dispatchable = invocation.getThreadContext();

            // If this was null, then use the Conversation as the Dispatchable object
            if (dispatchable == null) dispatchable = conversation;

            // Save this in the invocation
            invocation.setDispatchable(dispatchable);

            // Update the count in the Conversation of how many requests are outstanding on
            // this Conversation. This is needed when we are processing errorOccurred
            // notifications as we want to ensure that errorOccurred callbacks come after
            // all the data has been processed for that Conversation.
            synchronized (conversation.getTotalOutstandingRequestCountLock())
            {
               conversation.incrementTotalOutstandingCount();
            }

            ReceiveListenerDispatchQueue dispatchQueue = null;
            Object dispatchableLock = dispatchable.getDispatchLockObject();

            // Take a lock on the dispatchable to determin its dispatch queue.  This is
            // required to exclude other threads whilst we check if there is an associated
            // dispatch queue and if there is - increment its reference count.  We can drop
            // out of the synchronize block once the reference count is increased as other
            // threads will not disassociate a dispatch queue with a non-zero reference count.
            synchronized(dispatchableLock)
            {
               dispatchQueue = (ReceiveListenerDispatchQueue) dispatchable.getDispatchQueue();
               if (dispatchQueue != null)
                  dispatchable.incrementDispatchQueueRefCount();
            }
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "queueInvocationCommon", "dispatchQueue="+dispatchQueue);
            // End F201521

            if (dispatchQueue == null)
            {
               // The dispatchable was not already associated with a dispatch queue, so try
               // finding a suitable queue in the list of empty queues.  We synchronize on the
               // empty queues list to prevent corruption of the data structure by concurrent
               // access.  We also want to prevent anyone else from adding or removing queues
               // from the list until we have either removed a queue of our own or chosen a
               // queue to dispatch into.
               synchronized(emptyDispatchQueues)
               {
                  if (!emptyDispatchQueues.isEmpty())
                     dispatchQueue = emptyDispatchQueues.remove(emptyDispatchQueues.size()-1);  // D217401
                  else
                  {
                     // There was no empty queues so choose a queue by taking the modulus of
                     // the monotomically incrementing counter associated with the conversation.
                     // We must do this inside a block synchronized on the empty dispatch queue
                     // to prevent a race condition where someone could be adding the queue we
                     // decide upon into the empty queues list.
                     int queueNumber = conversation.getInstanceCounterValue();
                     dispatchQueue = dispatchQueues[queueNumber % maxConcurrentDispatches];
                  }
               }
               if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "dispatchQueue="+dispatchQueue);

               // Now we have decided upon a dispatch queue - associate it with the
               // dispatchable and ensure it has a non-zero reference count.  This is
               // done inside a synchronize block to ensure the change is kept consistent
               // across threads accessing the dispatchable.
               synchronized(dispatchableLock)                                                // F201521
               {
                  dispatchable.setDispatchQueue(dispatchQueue);                              // F201521
                  dispatchable.incrementDispatchQueueRefCount();                             // F201521
               }
            }

            //Reset invocation prior to enqueue to prevent its reference count getting messed up. 
            invocation.resetReferenceCounts();
            
            // Finally enqueue the work to our chosen dispatch queue
            dispatchQueue.enqueue(invocation);
         }
         catch (RuntimeException e)
         {
            // No FFDC code needed
            // Note the connection has already been blown away by this point - so no further action
            // needs to be taken.
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Looks like getThreadContext failed:", e);
         }
         // Start D213108
         // It's important that we carry on here and do not barf back up to the TCP channel
         // as we do not want to knacker any threads that will service user requests
         catch (Throwable t)
         {
            FFDCFilter.processException(t, "com.ibm.ws.sib.jfapchannel.impl.rldispatcher.ReceiveListenerDispatcher",
                                        JFapChannelConstants.RLDISPATCHER_QUEUEINVOCCOMMON_01, this);

            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "RL Dispatcher threw an exception: ", t);
         }
         // End D213108
         // End D202636
      }
      else // dispatcherEnabled == false
      {
         // If we are not using the new dispatching code then just invoke
         // the appropriate method on this thread.
         invocation.invoke();
         invocation.repool();
         invocation.resetReferenceCounts();                                               // D213108
      }
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "queueInvocationCommon");
   }
private void queueInvocationCommon ( AbstractInvocation invocation , ConversationImpl conversation ) { if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . entry ( this , tc , "queueInvocationCommon" , new Object [ ] { invocation , conversation } ) ; if ( dispatcherEnabled ) { try { Dispatchable dispatchable = invocation . getThreadContext ( ) ; if ( dispatchable == null ) dispatchable = conversation ; invocation . setDispatchable ( dispatchable ) ; synchronized ( conversation . getTotalOutstandingRequestCountLock ( ) ) { conversation . incrementTotalOutstandingCount ( ) ; } ReceiveListenerDispatchQueue dispatchQueue = null ; Object dispatchableLock = dispatchable . getDispatchLockObject ( ) ; synchronized ( dispatchableLock ) { dispatchQueue = ( ReceiveListenerDispatchQueue ) dispatchable . getDispatchQueue ( ) ; if ( dispatchQueue != null ) dispatchable . incrementDispatchQueueRefCount ( ) ; } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "queueInvocationCommon" , "dispatchQueue=" + dispatchQueue ) ; if ( dispatchQueue == null ) { synchronized ( emptyDispatchQueues ) { if ( ! emptyDispatchQueues . isEmpty ( ) ) dispatchQueue = emptyDispatchQueues . remove ( emptyDispatchQueues . size ( ) - 1 ) ; else { int queueNumber = conversation . getInstanceCounterValue ( ) ; dispatchQueue = dispatchQueues [ queueNumber % maxConcurrentDispatches ] ; } } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "dispatchQueue=" + dispatchQueue ) ; synchronized ( dispatchableLock ) { dispatchable . setDispatchQueue ( dispatchQueue ) ; dispatchable . incrementDispatchQueueRefCount ( ) ; } } invocation . resetReferenceCounts ( ) ; dispatchQueue . enqueue ( invocation ) ; } catch ( RuntimeException e ) { if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "Looks like getThreadContext failed:" , e ) ; } catch ( Throwable t ) { FFDCFilter . processException ( t , "com.ibm.ws.sib.jfapchannel.impl.rldispatcher.ReceiveListenerDispatcher" , JFapChannelConstants . RLDISPATCHER_QUEUEINVOCCOMMON_01 , this ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "RL Dispatcher threw an exception: " , t ) ; } } else { invocation . invoke ( ) ; invocation . repool ( ) ; invocation . resetReferenceCounts ( ) ; } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . exit ( this , tc , "queueInvocationCommon" ) ; }
Queues any type of invocation entry into an appropriate queue.  The queue is selected first
by determining if a requests associated conversation is already associated with a queue.  If
it is not then a list of empty queues is consulted before finally reverting to using a
the modulus of a monatomically incrementing counter (associated with conversation instance).
<p>
Note: this method contains some reasonably complex synchronization.  One underlying assumption
in this is that it cannot be invoked concurrently to queue an invocation for the same conversation.
This pre-condition is kept by virtue of the fact that the channel framework will not concurrently
read data from a single socket - and this method must be executed prior to making another read
request.
@param invocation
@param conversation