📄 socketclientfactory.java
字号:
* <strong>AVG_DEAD</strong>. This ensures that the server will start * dropping connections. * */ private final void updateLoadAverage() { int oldavg = loadavg; if ( freeCount >= maxFree ) { loadavg = AVG_LIGHT; } else if ((freeCount >= minFree) || (idleCount >= maxIdle)) { if ((loadavg = AVG_NORMAL) < oldavg) { server.thread.setPriority(Thread.MAX_PRIORITY); } } else if ( freeCount > 0 ) { /* idleCount < MINSPARE_IDLE */ if ((loadavg = AVG_HIGH) > oldavg) { // first ensure the state is sane// checkDeadClients(); server.thread.setPriority(server.getClientThreadPriority()-2); } } else { loadavg = AVG_DEAD; } } private final synchronized void incrClientCount() { ++clientCount; ++clientEstim; updateLoadAverage(); } private final synchronized void decrClientCount() { --clientCount; updateLoadAverage(); } private final synchronized boolean incrFreeCount() { if ( clientEstim > maxClients ) { clientEstim--; return false; } ++freeCount; updateLoadAverage(); return true; } private final synchronized boolean decrFreeCount() { if ( freeCount > 0 ) { --freeCount; updateLoadAverage(); return true; } else { return false; } } private final synchronized boolean incrIdleCount() { if ((loadavg > AVG_HIGH) || (idleCount + 1 >= maxIdle)) return false; ++idleCount; updateLoadAverage(); return true; } private final synchronized boolean decrIdleCount() { if ( idleCount > 0 ) { --idleCount; updateLoadAverage(); return true; } else { return false; } } /** * Removes an idle client from the list, updates only the idle list * as the free count has already be accessed * @param the socket client to remove from the idle list */ protected boolean idleClientRemove(SocketClient client) { // If the client pool has shut down, exit straight: if ( ! alive ) return false; SocketClientState cs = client.state; synchronized (cs) { switch(cs.status) { case SocketClientState.C_IDLE: decrIdleCount(); idleList.remove(cs); cs.status = SocketClientState.C_FREE; break; case SocketClientState.C_KILL: case SocketClientState.C_BUSY: default: break; } } return true; } /** * Notify that this client has finished with its connection. * If the pool wants the client to be freed (because it has too many of * them), it makes the client kill itself (which will trigger a call to * the clientFinished method, were enventual cleanup is performed). * @param client The client that is done with its connection. */ protected boolean clientConnectionFinished (SocketClient client) { // If the client pool has shut down, exit straight: if ( ! alive ) return false; SocketClientState cs = client.state; synchronized (cs) { switch(cs.status) { case SocketClientState.C_IDLE: decrIdleCount(); idleList.remove(cs); break; case SocketClientState.C_BUSY: case SocketClientState.C_KILL: break; case SocketClientState.C_FREE: // already freeed? if (client.done) { client.done = false; return true; } default: break; } if (incrFreeCount()) { if ( debug ) System.out.println(client+": now free."); cs.status = SocketClientState.C_FREE; freeList.toHead(cs); return true; } else { if ( debug ) System.out.println(client+": terminate."); return false; } } } /** * Notify that this client has been killed. * @param client The client that has terminate. */ protected void clientFinished (SocketClient client) { // If we're not alive any more, skip: if ( ! alive ) return; SocketClientState cs = client.state; synchronized (cs) { if ( debug ) System.out.println(client+": finished "+cs.status); // Otherwise, perform the job: switch(cs.status) { case SocketClientState.C_IDLE: break; case SocketClientState.C_FREE: decrFreeCount(); freeList.remove(cs); break; case SocketClientState.C_BUSY: default: String msg = (client + ": finished with unknown status " + cs.status); server.errlog(msg); break; } cs.status = SocketClientState.C_FIN; decrClientCount(); deleteClient(cs); } } /** * The client notifies the pool that is has been activated. * The client state object is updated to unmark the client as idle. * <p>This method needs not be synchronized, as it affect only the client * state, <em>not</em> the client list. * @param client The activated client. */ protected void notifyUse(SocketClient client) { if ( debug ) System.out.println(client+": used."); SocketClientState cs = client.state; synchronized (cs) { if (cs.status == SocketClientState.C_IDLE) { decrIdleCount(); idleList.remove(cs); } cs.status = SocketClientState.C_BUSY; } } /** * The client notifies the pool that it enters idle state. * <p>This method needs not be synchronized, as it affect only the client * state, <em>not</em> the client list. * @param client The client that is going to be idle. */ protected boolean notifyIdle(SocketClient client) { SocketClientState cs = client.state; if ( alive ) { synchronized (cs) { if ( incrIdleCount() ) { if ( debug ) System.out.println(client+": idle, keep-alive."); cs.status = SocketClientState.C_IDLE; idleList.toHead(cs); return true; } else { if ( debug ) System.out.println(client+": idle, closed."); // Kill some old idle connections, give a chance for next: int killsome = Math.max((maxFree - freeCount), (maxIdle - idleCount)); killSomeClients((killsome > 0) ? killsome : 1); // And give it a change if the load is not too high if ( incrIdleCount() ) { if ( debug ) System.out.println(client+": idle, keep-alive."); cs.status = SocketClientState.C_IDLE; idleList.toHead(cs); return true; } return false; } } } else { if ( debug ) System.out.println(client+": idle (dead), closed."); // Kill some old idle connections, give a chance for next: int killsome = Math.max((maxFree - freeCount), (maxIdle - idleCount)); killSomeClients((killsome > 0) ? killsome : 1); return false; } } protected void killSomeClients(int howmany) { int count = (howmany > 0) ? howmany : Math.max((maxFree - freeCount), (maxIdle - idleCount)); if (debug) { System.out.println("Killing :" + howmany); } while ( --count >= 0 ) { SocketClientState cs = (SocketClientState) idleList.removeTail(); if ( cs != null ) { synchronized (cs) { if (cs.status == SocketClientState.C_IDLE) { if ( debug ) System.out.println(cs.client + ": kill (some-client)."); decrIdleCount(); cs.status = SocketClientState.C_KILL; cs.client.unbind(); } } } else { break; } // if the load falls back to normal operation, we are all set if ((freeCount > minFree) && (idleCount < maxIdle)) { break; } } } final protected void killSomeClients() { killSomeClients(-1); } protected void run(SocketClient client) { if ( debug ) System.out.println(client+": warming up..."); boolean threaded = threadcache.getThread(client, true); if ( debug ) System.out.println(client+": threaded="+threaded); } /** * Handle the given connection. * Find a free client, bind it to the given socket, and run it. If we * have reached our maximum allowed number of clients, kill some * connections. * <p>A client enters the LRU list (and become a candidate for kill) only * after it has handle one request (or if some timeout expires). This is * performed by the first call to <code>notifyUse</code> which will * silently insert the client into the LRU if it was not there already. * <p>This client pool does a lot of nice thinigs, but could probably be * implemented in a much better way (while keeping the features it has). * Contention arond the pool is probably concern number 1 of performances. * @param socket The connection to handle. */ public void handleConnection (Socket socket) { if ( debug ) System.out.println("new connection."); SocketClientState cs = null; switch(loadavg) { case AVG_LIGHT: // Free list is non empty, be fast: if ( decrFreeCount() ) cs = (SocketClientState) freeList.removeTail(); break; case AVG_NORMAL: case AVG_HIGH: // Free list is non empty, but we try killing a client: killSomeClients(); if ( decrFreeCount() ) { cs = (SocketClientState) freeList.removeTail(); } break; case AVG_DEAD: break; } if ( debug ) System.out.println("load "+loadavg + ", client=" + ((cs != null) ? cs.client.toString() : "unbound")); // At this point, we do have a free client, bind it: if ( cs != null ) { if ( debug ) System.out.println(cs.client+": bound."); cs.status = SocketClientState.C_BUSY; cs.client.bind(socket); } else { if ( debug ) System.out.println("*** connection refused (overloaded)."); try { socket.close(); } catch (IOException ex) { } server.errlog(socket.getInetAddress()+" refused (overloaded)."); } return; } protected synchronized void killClients(boolean force) { alive = false; // Kill all clients (first shot): SocketClientState cs = csList; while ((cs != null) && (cs.client != null)) { synchronized (cs) { // Only if a client is idely read'ing its socket, we close it cs.client.kill(cs.status==SocketClientState.C_IDLE); } cs = cs.csnext; } // Kill all clients (second shot): // Some client may be in transition during first shot, second shot // really kills everything. try { Thread.sleep(5000); } catch (Exception ex) { } cs = csList; while ((cs != null) && (cs.client != null)) { synchronized (cs) { cs.client.kill(true); } cs = cs.csnext; } } /** * Shutdown the client pool. * If force is <strong>true</strong>, kill all running clients right * now, otherwise, wait for them to terminate gracefully, and return * when done. * @param force Should we interrupt running clients. */ public void shutdown (boolean force) { // First stage: kill all clients (synchronized) killClients(force) ; // Second stage (unsynchronized), join all client threads SocketClientState cs = csList; while ((cs != null) && (cs.client != null)) { if ( debug ) System.out.println(cs.client+": join."); cs.client.join(); cs = cs.csnext; } // Some cleanup (helps the GC, and make sure everything is free) props.unregisterObserver(this); props = null; csList = null; freeList = null; idleList = null; server = null; } /** * Create the master socket for this client factory. * @exception IOException If some IO error occurs while creating the * server socket. * @return A ServerSocket instance. */ public ServerSocket createServerSocket() throws IOException { // using maxCLient in the backlog is safe, but an overkill :) if (bindAddr == null) { return new ServerSocket (server.getPort(), Math.max(128, maxClients)); } else { return new ServerSocket (server.getPort(), Math.max(128, maxClients), bindAddr); } } /** * Initialize the raw, client socket factory. * @param server The server context we are attached to. */ public void initialize(httpd server) { // Initialize instance variables: this.server = server ; this.props = server.getProperties() ; this.props.registerObserver (this) ; // Register our property sheet: PropertySet set = new SocketConnectionProp("SocketConnectionProp" , server); server.registerPropertySet(set); // Initialize parameters from properties: this.minFree = props.getInteger(MINSPARE_FREE_P, MINSPARE_FREE); this.maxFree = props.getInteger(MAXSPARE_FREE_P, MAXSPARE_FREE); this.maxIdle = props.getInteger(MAXSPARE_IDLE_P, MAXSPARE_IDLE); this.maxClients = props.getInteger(MAXCLIENTS_P, MAXCLIENTS); String bindAddrName = props.getString(BINDADDR_P, null); if (bindAddrName != null) { try { bindAddr = InetAddress.getByName(bindAddrName); } catch (Exception ex) { // nothing, fallback to default } } // Create the LRU lists: idleList = new SyncLRUList(); freeList = new SyncLRUList(); // Create the full client list: csList = new SocketClientState(); // Create all our clients: for (int i = 0 ; i < maxClients ; i++) { if ( addClient(true) == null ) throw new RuntimeException (this.getClass().getName() + "[construstructor]" + ": unable to create clients."); } // Create the thread cache: threadcache = new ThreadCache(server.getIdentifier() + "-socket-clients"); threadcache.setCachesize(props.getInteger(MAXTHREADS_P, MAXTHREADS)); threadcache.setThreadPriority(server.getClientThreadPriority()); threadcache.setIdleTimeout(props.getInteger(IDLETO_P,IDLETO)); threadcache.setGrowAsNeeded(true); threadcache.initialize(); // Start the debugging thread, if needed: if ( debugthread ) { new DebugThread(this).start(); } } /** * Empty constructor for dynamic class instantiation. */ public SocketClientFactory() { }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -