One of the problems I've noticed browsing through the server source is the
lack of thread management in the code.  The policy seems to be 'accept a
connection, generate a thread, and forget about it'.  This leaves the
server open to connection flood or DoS attacks.  Java threads are nice,
and they help efficiency, but when there are to many of them, things get
ugly.

I did some connection testing on Freenet and the server really starts to
behave badly with numerous connections.  The threads compete for processor
time, so connections take longer to finish, thus there is more time for
new connections, yielding more threads, and so on.

A simple solution to this might be to use thread pooling.  This worked
very effectively in Gamora (a pet project of mine).  Essentially, you
maintain a pool of N threads, where N is the most you want running at any
given time.  As new jobs come in, they are issued to the pool manager,
which assigns them to a thread, up to N.  Beyond N, they are added to a
run-queue and assigned as threads become available.

The result is a non-blocking system that allows connections to continue to
flow in, but places them on hold so that the system doesn't run away from
you.  If you pick your N right, high enough that your server is never
idle, but low enough that the threads aren't thrashing, this actually
improves performance considerably.  

Below is a patch against build 118 that executes all of its connections in
a Thread pool with N=50.  You'll need the ethread package,
ftp://ftp.gamora.org/pub/gamora/ethreads.  Just shove her in your
classpath.

Feel free to tinker, play, and flame the hell out of me. :)

--------8<------------------------------------------------------
diff -urN Freenet/ConnectionHandler.java Freenet-ethread/ConnectionHandler.java
--- Freenet/ConnectionHandler.java      Sun Apr  9 10:48:36 2000
+++ Freenet-ethread/ConnectionHandler.java      Tue Apr 11 19:35:33 2000
@@ -3,6 +3,8 @@
 import java.net.*;
 import java.io.*;
 import java.io.EOFException;
+import org.gamora.ethreads.*;
+
 /*
   This code is part of the Java Adaptive Network Client by Ian Clarke. 
   It is distributed under the GNU General Public Licence (GPL) 
@@ -16,9 +18,10 @@
  * @author <a href="mailto:blanu at uts.cc.utexas.edu">Brandon Wiley</a>
  **/

-public class ConnectionHandler extends Thread
+public class ConnectionHandler implements ERunnable
 {
   // Protected/Private Fields
+    private static EThread exec_instance;
     private static long ids=0;
     private long id;
   private Connection c;
@@ -165,7 +168,7 @@
     //I'm letting this force close now, maybe it should synchronize somehow 
(it can't sync to c.in anyways, since that is always waiting on a read in the 
RawMessage constructor).
     public void close() {
        closed = true;
-       this.interrupt();
+       exec_instance.getThread().interrupt();
     }

     /**
@@ -182,7 +185,8 @@
      **/

     public boolean isOpen() {
-       return isAlive() && !closed;
+       return exec_instance!=null && !closed;
+       //      return isAlive() && !closed;
     }

     public Address peer() {
@@ -199,5 +203,9 @@

     public Address local(ListeningAddress laddr) {
        return c.getMyAddress(laddr);
+    }
+
+    public void setExecutionInstance(EThread e) {
+       exec_instance=e;
     }
 }
diff -urN Freenet/Core.java Freenet-ethread/Core.java
--- Freenet/Core.java   Tue Apr 11 09:12:35 2000
+++ Freenet-ethread/Core.java   Tue Apr 11 19:37:54 2000
@@ -4,6 +4,7 @@
 import java.util.*;
 import java.net.*;
 import java.io.*;
+import org.gamora.ethreads.*;

 /*
   This code is part of the Java Adaptive Network Client by Ian Clarke. 
@@ -40,6 +41,7 @@
     public HandshakeHandler hh;
     public Listener listener;
     public boolean listen = true; // provides a way to turn off listening
+    public ThreadManager threads;

     public Core(ListeningAddress myAddress, MessageHandler mh, 
HandshakeHandler hh) {
        try {
@@ -51,6 +53,8 @@
        this.mh = mh;
        this.hh = hh;
        Logger.log("Core.java","Node running on "+listener,Logger.NORMAL);
+       threads=new ThreadPool(50);
+       threads.start();
     }

     public void acceptConnections()
@@ -70,7 +74,7 @@
               throw new RuntimeException("Problem accepting next connection");
             }
           c = new ConnectionHandler(conn, mh);
-          c.start();
+         threads.run(c);
         }
     }

@@ -119,7 +123,7 @@
        }

        ConnectionHandler ch = new ConnectionHandler(c, mh);
-       ch.start(); // start listening on this connection
+       threads.run(ch); // start listening on this connection
        return ch;
     }






_______________________________________________
Freenet-dev mailing list
Freenet-dev at lists.sourceforge.net
http://lists.sourceforge.net/mailman/listinfo/freenet-dev

Reply via email to