Coverage Report - com.sun.grizzly.connectioncache.impl.transport.InboundConnectionCacheBlockingImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
InboundConnectionCacheBlockingImpl
71 %
77/108
63 %
49/78
0
InboundConnectionCacheBlockingImpl$ConnectionState
100 %
6/6
N/A
0
 
 1  
 /*
 2  
  * 
 3  
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 4  
  * 
 5  
  * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 6  
  * 
 7  
  * The contents of this file are subject to the terms of either the GNU
 8  
  * General Public License Version 2 only ("GPL") or the Common Development
 9  
  * and Distribution License("CDDL") (collectively, the "License").  You
 10  
  * may not use this file except in compliance with the License. You can obtain
 11  
  * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 12  
  * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 13  
  * language governing permissions and limitations under the License.
 14  
  * 
 15  
  * When distributing the software, include this License Header Notice in each
 16  
  * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 17  
  * Sun designates this particular file as subject to the "Classpath" exception
 18  
  * as provided by Sun in the GPL Version 2 section of the License file that
 19  
  * accompanied this code.  If applicable, add the following below the License
 20  
  * Header, with the fields enclosed by brackets [] replaced by your own
 21  
  * identifying information: "Portions Copyrighted [year]
 22  
  * [name of copyright owner]"
 23  
  * 
 24  
  * Contributor(s):
 25  
  * 
 26  
  * If you wish your version of this file to be governed by only the CDDL or
 27  
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
 28  
  * elects to include this software in this distribution under the [CDDL or GPL
 29  
  * Version 2] license."  If you don't indicate a single choice of license, a
 30  
  * recipient has the option to distribute your version of this file under
 31  
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
 32  
  * its licensees as provided above.  However, if you add GPL Version 2 code
 33  
  * and therefore, elected the GPL Version 2 license, then the option applies
 34  
  * only if the new code is made subject to such option by the copyright
 35  
  * holder.
 36  
  *
 37  
  */
 38  
 
 39  
 package com.sun.grizzly.connectioncache.impl.transport;
 40  
 
 41  
 import com.sun.grizzly.connectioncache.spi.concurrent.ConcurrentQueue;
 42  
 import com.sun.grizzly.connectioncache.spi.transport.InboundConnectionCache;
 43  
 
 44  
 import java.io.Closeable;
 45  
 import java.io.IOException ;
 46  
 
 47  
 import java.util.logging.Logger ;
 48  
 
 49  
 import java.util.Map ;
 50  
 import java.util.HashMap ;
 51  
 
 52  
 /** Manage connections that are initiated from another VM.
 53  
  *
 54  
  * @param C  a connection
 55  
  * @author Ken Cavanaugh
 56  
  */
 57  84
 public final class InboundConnectionCacheBlockingImpl<C extends Closeable>
 58  
         extends ConnectionCacheBlockingBase<C>
 59  
         implements InboundConnectionCache<C> {
 60  
     
 61  
     private final Map<C,ConnectionState<C>> connectionMap ;
 62  
     
 63  
     protected String thisClassName() {
 64  0
         return "InboundConnectionCacheBlockingImpl" ;
 65  
     }
 66  
     
 67  
     private static final class ConnectionState<C extends Closeable> {
 68  
         final C connection ;                // Connection of the
 69  
         // ConnectionState
 70  
         int busyCount ;                        // Number of calls to
 71  
         // get without release
 72  
         int expectedResponseCount ;        // Number of expected
 73  
         // responses not yet
 74  
         // received
 75  
         
 76  
         ConcurrentQueue.Handle<C> reclaimableHandle ;  // non-null iff connection
 77  
         // is not in use and has no
 78  
         // outstanding requests
 79  
         
 80  38
         ConnectionState( final C conn ) {
 81  38
             this.connection = conn ;
 82  
             
 83  38
             busyCount = 0 ;
 84  38
             expectedResponseCount = 0 ;
 85  38
             reclaimableHandle = null ;
 86  38
         }
 87  
     }
 88  
     
 89  
     public InboundConnectionCacheBlockingImpl( final String cacheType,
 90  
             final int highWaterMark, final int numberToReclaim,
 91  
             Logger logger ) {
 92  
         
 93  3
         super( cacheType, highWaterMark, numberToReclaim, logger ) ;
 94  
         
 95  3
         this.connectionMap = new HashMap<C,ConnectionState<C>>() ;
 96  
         
 97  3
         if (debug()) {
 98  0
             dprint(".constructor completed: " + getCacheType() );
 99  
         }
 100  3
     }
 101  
     
 102  
     // We do not need to define equals or hashCode for this class.
 103  
     
 104  
     public synchronized void requestReceived( final C conn ) {
 105  1029
         if (debug())
 106  0
             dprint( "->requestReceived: connection " + conn ) ;
 107  
         
 108  
         try {
 109  1029
             ConnectionState<C> cs = getConnectionState( conn ) ;
 110  
             
 111  1029
             final int totalConnections = totalBusy + totalIdle ;
 112  1029
             if (totalConnections > highWaterMark())
 113  4
                 reclaim() ;
 114  
             
 115  1029
             ConcurrentQueue.Handle<C> reclaimHandle = cs.reclaimableHandle ;
 116  1029
             if (reclaimHandle != null) {
 117  990
                 if (debug())
 118  0
                     dprint( ".requestReceived: " + conn
 119  
                             + " removed from reclaimableQueue" ) ;
 120  990
                 reclaimHandle.remove() ;
 121  
             }
 122  
             
 123  1029
             int count = cs.busyCount++ ;
 124  1029
             if (count == 0) {
 125  1028
                 if (debug())
 126  0
                     dprint( ".requestReceived: " + conn
 127  
                             + " transition from idle to busy" ) ;
 128  
                 
 129  1028
                 totalIdle-- ;
 130  1028
                 totalBusy++ ;
 131  
             }
 132  
         } finally {
 133  1029
             if (debug())
 134  0
                 dprint( "<-requestReceived: connection " + conn ) ;
 135  
         }
 136  1029
     }
 137  
     
 138  
     public synchronized void requestProcessed( final C conn,
 139  
             final int numResponsesExpected ) {
 140  
         
 141  1009
         if (debug())
 142  0
             dprint( "->requestProcessed: connection " + conn
 143  
                     + " expecting " + numResponsesExpected + " responses" ) ;
 144  
         
 145  
         try {
 146  1009
             final ConnectionState<C> cs = connectionMap.get( conn ) ;
 147  
             
 148  1009
             if (cs == null) {
 149  1
                 if (debug())
 150  0
                     dprint( ".release: connection " + conn + " was closed" ) ;
 151  
                 
 152  
                 return ;
 153  
             } else {
 154  1008
                 cs.expectedResponseCount += numResponsesExpected ;
 155  1008
                 int numResp = cs.expectedResponseCount ;
 156  1008
                 int numBusy = --cs.busyCount ;
 157  
                 
 158  1008
                 if (debug()) {
 159  0
                     dprint( ".release: " + numResp + " responses expected" ) ;
 160  0
                     dprint( ".release: " + numBusy +
 161  
                             " busy count for connection" ) ;
 162  
                 }
 163  
                 
 164  1008
                 if (numBusy == 0) {
 165  1007
                     totalBusy-- ;
 166  1007
                     totalIdle++ ;
 167  
                     
 168  1007
                     if (numResp == 0) {
 169  2
                         if (debug())
 170  0
                             dprint( ".release: "
 171  
                                     + "queuing reclaimable connection "
 172  
                                     + conn ) ;
 173  
                         
 174  2
                         if ((totalBusy+totalIdle) > highWaterMark()) {
 175  2
                             close( conn ) ;
 176  
                         } else {
 177  0
                             cs.reclaimableHandle =
 178  
                                     reclaimableConnections.offer( conn ) ;
 179  
                         }
 180  
                     }
 181  
                 }
 182  
             }
 183  
         } finally {
 184  1009
             if (debug())
 185  0
                 dprint( "<-requestProcessed" ) ;
 186  
         }
 187  1008
     }
 188  
     
 189  
     /** Decrement the number of expected responses.  When a connection is idle
 190  
      * and has no expected responses, it can be reclaimed.
 191  
      * @param conn  a connection
 192  
      */
 193  
     public synchronized void responseSent( final C conn ) {
 194  1006
         if (debug())
 195  0
             dprint( "->responseSent: " + conn ) ;
 196  
         
 197  
         try {
 198  1006
             final ConnectionState<C> cs = connectionMap.get( conn ) ;
 199  1006
             if (cs == null) {
 200  1
                 if (debug())
 201  0
                     dprint( ".release: connection " + conn + " was closed" ) ;
 202  
                 
 203  
                 return ;
 204  
             }
 205  
             
 206  1005
             final int waitCount = --cs.expectedResponseCount ;
 207  1005
             if (waitCount == 0) {
 208  1005
                 if (debug())
 209  0
                     dprint( ".responseSent: " + conn + " is now reclaimable" ) ;
 210  
                 
 211  1005
                 if ((totalBusy+totalIdle) > highWaterMark()) {
 212  1
                     if (debug()) {
 213  0
                         dprint( ".responseSent: " + conn
 214  
                                 + " closing connection" ) ;
 215  
                     }
 216  1
                     close( conn ) ;
 217  
                 } else {
 218  1004
                     cs.reclaimableHandle =
 219  
                             reclaimableConnections.offer( conn ) ;
 220  
                     
 221  1004
                     if (debug()) {
 222  0
                         dprint( ".responseSent: " + conn
 223  
                                 + " is now reclaimable" ) ;
 224  
                     }
 225  
                 }
 226  
             } else {
 227  0
                 if (debug()) {
 228  0
                     dprint( ".responseSent: " + conn + " waitCount="
 229  
                             + waitCount ) ;
 230  
                 }
 231  
             }
 232  
         } finally {
 233  1006
             if (debug()) {
 234  0
                 dprint( "<-responseSent: " + conn ) ;
 235  
             }
 236  
         }
 237  1005
     }
 238  
     
 239  
     /** Close a connection, regardless of whether the connection is busy
 240  
      * or not.
 241  
      * @param conn  a connection
 242  
      */
 243  
     public synchronized void close( final C conn ) {
 244  40
         if (debug())
 245  0
             dprint( "->close: " + conn ) ;
 246  
         
 247  
         try {
 248  40
             final ConnectionState<C> cs = connectionMap.remove( conn ) ;
 249  40
             if (cs != null) {
 250  38
                 int count = cs.busyCount ;
 251  38
                 if (debug())
 252  0
                     dprint( ".close: " + conn + " count = " + count ) ;
 253  
                 
 254  38
                 if (count == 0)
 255  17
                     totalIdle-- ;
 256  
                 else
 257  21
                     totalBusy-- ;
 258  
                 
 259  38
                 final ConcurrentQueue.Handle rh = cs.reclaimableHandle ;
 260  38
                 if (rh != null) {
 261  14
                     if (debug())
 262  0
                         dprint( ".close: " + conn + " connection was reclaimable" ) ;
 263  
                     
 264  14
                     rh.remove() ;
 265  
                 }
 266  
                 
 267  
                 try {
 268  38
                     conn.close() ;
 269  0
                 } catch (IOException exc) {
 270  0
                     if (debug())
 271  0
                         dprint( ".close: " + conn + " close threw "  + exc ) ;
 272  38
                 }
 273  
             }
 274  
         } finally {
 275  40
             if (debug())
 276  0
                 dprint( "<-close: " + conn ) ;
 277  
         }
 278  40
     }
 279  
     
 280  
     // Atomically either get the ConnectionState for conn OR
 281  
     // create a new one AND put it in the cache
 282  
     private ConnectionState<C> getConnectionState( C conn ) {
 283  
         // This should be the only place a CacheEntry is constructed.
 284  1029
         if (debug())
 285  0
             dprint( "->getConnectionState: " + conn ) ;
 286  
         
 287  
         try {
 288  1029
             ConnectionState<C> result = connectionMap.get( conn ) ;
 289  1029
             if (result == null) {
 290  38
                 if (debug())
 291  0
                     dprint( ".getConnectionState: " + conn +
 292  
                             " creating new ConnectionState instance" ) ;
 293  38
                 result = new ConnectionState<C>( conn ) ;
 294  38
                 connectionMap.put( conn, result ) ;
 295  38
                 totalIdle++ ;
 296  
             }
 297  
             
 298  1029
             return result ;
 299  
         } finally {
 300  1029
             if (debug())
 301  0
                 dprint( "<-getConnectionState: " + conn ) ;
 302  
         }
 303  
     }
 304  
 }
 305  
 
 306  
 // End of file.