docs: protected MCWrapper getFreeConnection(ManagedConnectionFactory managedConnectionFactory, Subject subject, ConnectionRequestInfo cri,
                                            int hashCode) throws ResourceAllocationException {
  
          final boolean isTracingEnabled = TraceComponent.isAnyTracingEnabled();
  
          if (isTracingEnabled && tc.isEntryEnabled()) {
              Tr.entry(this, tc, "getFreeConnection", gConfigProps.cfName);
          }
  
          MCWrapper mcWrapper = null;
          MCWrapper mcWrapperTemp1 = null;
          MCWrapper mcWrapperTemp2 = null;
          int mcwlSize = 0;
          int mcwlIndex = 0;
  
          synchronized (freeConnectionLockObject) {
              mcwlSize = mcWrapperList.size();
              if (mcwlSize > 0) {
                  mcwlIndex = mcwlSize - 1;
                  // Remove the first mcWrapper from the list (Optimistic)
                  mcWrapperTemp1 = (MCWrapper) mcWrapperList.remove(mcwlIndex);
                  mcWrapperTemp1.setPoolState(0);
              }
  
          }
  
          /*
           * At this point we may have a mcWrapper and we can release the free pool lock. This is a
           * very optimistic view of the world. We assume that the connection will match most of the time to
           * have released the lock.
           */
          if (mcWrapperTemp1 != null) {
  
              if (hashCode == mcWrapperTemp1.getSubjectCRIHashCode()) {
                  mcWrapper = getMCWrapperFromMatch(subject, cri, managedConnectionFactory, mcWrapperTemp1);
                  if (((com.ibm.ejs.j2c.MCWrapper) mcWrapperTemp1).do_not_reuse_mcw) {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(this, tc, "Connection error occurred for this mcw " + mcWrapperTemp1 + ", mcw will not be reuse");
                      }
                      synchronized (pm.waiterFreePoolLock) {
                          cleanupAndDestroyMCWrapper(mcWrapperTemp1);
                          synchronized (freeConnectionLockObject) {
                              --numberOfConnectionsAssignedToThisFreePool;
                          }
                          pm.totalConnectionCount.decrementAndGet();
                          if ((pm.waiterCount > 0) && (pm.waiterCount > pm.mcWrapperWaiterList.size())) {
                              pm.waiterFreePoolLock.notify();
                          }
                      }
                  }
              }
  
              if (mcWrapper == null) {
                  /*
                   * In the 5.0.1 release, we had heavier locking which allowed a resource adapter
                   * to call connection error occurred during mc.matchManagedConnection. I am not
                   * 100% sure if this worked correctly in all cases, but is going to make sure it
                   * works. Any call to getMCWrapperFromMatch with calls mc.matchManagedConnection must
                   * be in a synchronized pm.waterFreePoolLock if its in a synchronized freeConnectionLockObject.
                   * Adding the pm.waiterFreePoolLock.
                   */
                  synchronized (pm.waiterFreePoolLock) {
                      synchronized (freeConnectionLockObject) {
                          // We need to look through the list, since we didn't find a matching connection at
                          // the end of the list, we need to use get and only remove if we find a matching
                          // connection.
                          mcwlSize = mcWrapperList.size();
                          if (mcwlSize > 0) { // set this to 0 since mcWrappterTemp1 has already been removed.
  
                              mcwlIndex = mcwlSize - 1;
                              for (int i = mcwlIndex; i >= 0; --i) {
  
                                  mcWrapperTemp2 = (MCWrapper) mcWrapperList.get(i);
                                  if (hashCode == mcWrapperTemp2.getSubjectCRIHashCode()) {
                                      mcWrapper = getMCWrapperFromMatch(subject, cri, managedConnectionFactory, mcWrapperTemp2);
                                      if (((com.ibm.ejs.j2c.MCWrapper) mcWrapperTemp2).do_not_reuse_mcw) {
                                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                              Tr.debug(this, tc, "Connection error occurred for this mcw " + mcWrapperTemp2 + ", mcw will not be reuse");
                                          }
                                          mcWrapperList.remove(i);
                                          cleanupAndDestroyMCWrapper(mcWrapperTemp2);
                                          synchronized (freeConnectionLockObject) {
                                              --numberOfConnectionsAssignedToThisFreePool;
                                          }
                                          pm.totalConnectionCount.decrementAndGet();
                                          if ((pm.waiterCount > 0) && (pm.waiterCount > pm.mcWrapperWaiterList.size())) {
                                              pm.waiterFreePoolLock.notify();
                                          }
                                      }
                                  }
                                  if (mcWrapper != null) {
                                      mcWrapperList.remove(i);
                                      mcWrapper.setPoolState(0);
                                      break;
                                  }
  
                              }
  
                          } // end if mcwlSize > 1
  
                      } // end synchronized (freeConnectionLockObject)
  
                      /*
                       * We need to add the first non-matching mcWrapper back into the free pool or waiter queue.
                       */
                      if (!((com.ibm.ejs.j2c.MCWrapper) mcWrapperTemp1).do_not_reuse_mcw) {
                          //synchronized (pm.waiterFreePoolLock) {
                          // waiter code
                          if ((pm.waiterCount > 0) && (pm.waiterCount > pm.mcWrapperWaiterList.size())) {
  
                              // there are requests waiting, so notify one of them
                              pm.mcWrapperWaiterList.add(mcWrapperTemp1);
                              pm.waiterFreePoolLock.notify();
                          } else {
  
                              synchronized (freeConnectionLockObject) {
                                  mcWrapperList.add(mcWrapperTemp1); // Add to end of list
                                  mcWrapperTemp1.setPoolState(1);
                              }
  
                          }
                          //} // end synchronized (waiterFreePoolLock)
                      } // end synchronized (waiterFreePoolLock)
  
                      if ((isTracingEnabled && tc.isDebugEnabled())) {
                          if (mcWrapper != null) {
                              ++fnop_gets;
                          }
                      }
  
                  }
              } else {
  
                  /*
                   * We found a connection the first try :-)
                   */
                  if ((isTracingEnabled && tc.isDebugEnabled())) {
                      ++fop_gets;
                  }
  
              } // end else
  
          }
  
          if ((isTracingEnabled && tc.isDebugEnabled())) {
              if (mcWrapper == null) {
                  ++fnop_get_notfound;
              }
          }
  
          if (isTracingEnabled && tc.isEntryEnabled()) {
              if (isTracingEnabled && tc.isDebugEnabled()) {
                  if (mcWrapper != null) {
                      Tr.debug(this, tc, "Returning mcWrapper " + mcWrapper);
                  } else {
                      Tr.debug(this, tc, "MCWrapper was not found in Free Pool");
                  }
              }
              Tr.exit(this, tc, "getFreeConnection");
          }
  
          return mcWrapper;
  
      }