Update of /cvsroot/freenet/freenet/src/freenet/support
In directory sc8-pr-cvs1:/tmp/cvs-serv25857/src/freenet/support

Modified Files:
      Tag: stable
        BlockingQueue.java CryptBucket.java Fields.java 
        FileBucket.java FileLoggerHook.java LRUQueue.java 
        LimitCounter.java Logger.java LoggerHook.java 
        MultiValueTable.java SimpleDataObjectStore.java 
        TempBucketFactory.java TempFileBucket.java 
Added Files:
      Tag: stable
        PooledRandomAccessFile.java RandomAccessFilePool.java 
Log Message:
5029: Merge from unstable after months of work. MASSIVE changes.
Highlights:
* Next Generation Routing, massive related changes
* Major changes to handling of messages and connections (PeerHandler and related 
changes)
* Even more non-blocking I/O
* Documentation improvements
* Lots of new diagnostics and config options
* Lots of bug fixes and performance tweaking
* Probably lots of new bugs too!


--- NEW FILE: PooledRandomAccessFile.java ---
package freenet.support;

import java.io.*;

/**
 * Interface for pooled RandomAccessFile-like objects.
 * Purpose of pooling is to save FDs.
 * Classes implementing this interface should be synchronized.
 * @see RandomAccessFilePool
 */
public interface PooledRandomAccessFile {
    public long length() throws IOException;
    public void seek(long pos) throws IOException;
    /** Synchronize. Provided to avoid requiring locking in client.
     * In java.io.RandomAccessFile this would go via the FileDescriptor.
     */
    public void sync() throws IOException;
    public int read() throws IOException;
    public int read(byte[] b, int off, int len) throws IOException;
    public void write(int b) throws IOException;
    public void write(byte[] b, int off, int len) throws IOException;
    public long getFilePointer() throws IOException;
    /** Close the underlying RandomAccessFile, if we are short on
     * handles. Call this when you have temporarily finished with a
     * RAF, but don't want to close() yet.
     */
    public void closeRAF();
    public void close() throws IOException;
}

--- NEW FILE: RandomAccessFilePool.java ---
package freenet.support;

import java.io.*;
import freenet.Core;

/**
 * A pool of PooledRandomAccessFiles. These are similar to 
 * java.io.RandomAccessFiles, but we have a maximum number of file
 * descriptors. If there are more RAFs than that allocated, we keep only
 * the MRU fds open.
 *
 * Synchronized.
 */
public class RandomAccessFilePool {
    int maxOpenFiles;
    volatile int totalOpenFiles;
    LRUQueue queue;
    
    public int totalOpenFiles() {
        return totalOpenFiles;
    }
    
    public int maxOpenFiles() {
        return maxOpenFiles;
    }
    
    public RandomAccessFilePool(int maxFDsOpen) {
        this.maxOpenFiles = maxFDsOpen;
        queue = new LRUQueue();
        if(maxFDsOpen < 2) throw new IllegalArgumentException("Unreasonable maximum 
number of open files "+maxFDsOpen);
    }
    
    public PooledRandomAccessFile open(File f, String mode) 
        throws IOException {
        return new MyPooledRandomAccessFile(f, mode);
    }
    
    class MyPooledRandomAccessFile implements PooledRandomAccessFile {
        File filename;
        String mode;
        RandomAccessFile raf;
        boolean closed = false;
        long position = 0; // Not guaranteed to be up to date unless raf closed
        
        public MyPooledRandomAccessFile(File f, String mode) throws IOException {
            this.filename = f;
            this.mode = mode;
            reopen();
        }
        
        synchronized void reopen() throws IOException {
            if(raf == null) {
                if(closed) 
                    throw new IOException("Already closed or failed to save position");
                boolean firstIteration = true;
                while(totalOpenFiles >= maxOpenFiles) {
                    PooledRandomAccessFile fClose = null;
                    synchronized(RandomAccessFilePool.this) {
                        if(firstIteration) {
                            totalOpenFiles++; // the one we are about to open
                            queue.push(this);
                            firstIteration = false;
                        }
                        // Do it here to try to avoid livelock
                        
                        if(totalOpenFiles > maxOpenFiles) {
                            fClose = (PooledRandomAccessFile)(queue.pop());
                        }
                    }
                    // Close LRU
                    // Since this is MRU we shouldn't have lock contention
                    if(fClose == this)
                        throw new IllegalStateException("aaaaargh! Popped self!");
                    if(fClose != null) fClose.closeRAF();
                }
                raf = new RandomAccessFile(filename, mode);
                if(position != 0) {
                    raf.seek(position);
                }
            }
        }
        
        public long length() throws IOException {
            synchronized(this) {
                if(raf != null)
                    return raf.length();
            }
            return filename.length();
        }
        
        public synchronized void seek(long pos) throws IOException {
            reopen();
            raf.seek(pos);
            position = pos;
        }
        
        /**
         * Not in RandomAccessFile API, but because of synchronization
         * issues, it is better to put it here */
        public synchronized void sync() throws IOException {
            // No need to reopen
            if(raf != null) {
                raf.getFD().sync();
            }
        }
        
        public synchronized int read() throws IOException {
            reopen();
            return raf.read();
        }
        
        public synchronized int read(byte[] buf, int off, int len) 
            throws IOException {
            reopen();
            return raf.read(buf, off, len);
        }
        
        public synchronized void write(int b) throws IOException {
            reopen();
            raf.write(b);
        }
        
        public synchronized void write(byte[] b, int offset, int len) 
            throws IOException {
            reopen();
            raf.write(b, offset, len);
        }
        
        public synchronized long getFilePointer() throws IOException {
            if(raf == null)
                return position;
            else
                return raf.getFilePointer();
        }
        
        public synchronized void closeRAF() {
            if(raf == null) return;
            synchronized(RandomAccessFilePool.this) {
                if(totalOpenFiles < maxOpenFiles)
                    return;
            }
            try {
                position = raf.getFilePointer();
            } catch (IOException e) {
                closed = true;
                position = 0;
            } catch (Throwable t) {
                Core.logger.log(this, "Caught "+t+" saving file pointer for "+
                                raf, Logger.ERROR);
            }
            try {
                raf.close();
            } catch (IOException e) {
            } catch (Throwable t) {
                Core.logger.log(this, "Caught "+t+" closing "+raf, 
                                Logger.ERROR);
                // assume it is closed...
            }
            synchronized(RandomAccessFilePool.this) {
                totalOpenFiles--;
            }
            raf = null;
        }
        
        public synchronized void close() throws IOException {
            closed = true;
            raf.close();
            raf = null;
            synchronized(RandomAccessFilePool.this) {
                totalOpenFiles--;
            }
        }
    }
}

Index: BlockingQueue.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/BlockingQueue.java,v
retrieving revision 1.1.1.1.4.1.2.6
retrieving revision 1.1.1.1.4.1.2.7
diff -u -w -r1.1.1.1.4.1.2.6 -r1.1.1.1.4.1.2.7
--- BlockingQueue.java  5 Aug 2003 19:41:29 -0000       1.1.1.1.4.1.2.6
+++ BlockingQueue.java  28 Oct 2003 20:20:45 -0000      1.1.1.1.4.1.2.7
@@ -1,8 +1,8 @@
 package freenet.support;
 import freenet.*;
-import freenet.support.Logger;
 
 import java.util.*;
+import java.util.logging.LogManager;
 
 /*
   This code is part of the Java Adaptive Network Client by Ian Clarke. 
@@ -19,7 +19,7 @@
  * @author Scott G. Miller <[EMAIL PROTECTED]>
  */
 public final class BlockingQueue {
-    protected LinkedList queue;
+    protected final LinkedList queue;
 
     /**
      * Construct an empty BlockingQueue.
@@ -39,11 +39,23 @@
      * @param o the object to enqueue
      */
     public void enqueue(Object o) {
+    boolean logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
        enqueuedAt = System.currentTimeMillis();
+       if(logDEBUG)
+               Core.logger.log(this, "enqueueing "+o, Logger.DEBUG);
        synchronized(queue) {
+               if(logDEBUG)
+               Core.logger.log(this, "enqueueing "+o+" (locked)",
+                           Logger.DEBUG);
            queue.add(o);
            queue.notifyAll();
-       }
+           if(logDEBUG)
+               Core.logger.log(this, "enqueued "+o+" (locked)"+
+                           " to "+queue.getClass()+":"+queue, Logger.DEBUG);
+       }
+       if(logDEBUG)
+               Core.logger.log(this, "enqueued "+o+" (locked)",
+                       Logger.DEBUG);
     }
     
     public Object dequeue() throws InterruptedException {
@@ -63,6 +75,8 @@
      * and something interrupts this thread.
      */
     public Object dequeue(int millis) throws InterruptedException {
+               boolean logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
+               boolean logMINOR = Core.logger.shouldLog(Logger.MINOR,this);
         synchronized(queue) {
             //if (queue.isEmpty()) {
             //    synchronized(queue) {
@@ -78,20 +92,26 @@
                dequeuedCounted++;
                final int timeout = 200;
                while (queue.isEmpty()) {
+                       if(logDEBUG) Core.logger.log(this, "Waiting... 
"+queue.getClass()+":"+
+                                   queue, Logger.DEBUG);
                    long now = System.currentTimeMillis();
                    queue.wait(timeout); // wicked evil JVMs! (1.4.2 especially) - we 
have seen some interesting freezes here...
                    long andnow = System.currentTimeMillis();
                    if (andnow - now >= (timeout) && !queue.isEmpty()) {
                        long x = andnow - enqueuedAt;
-                       String err = "Waited more than "+timeout+"ms to dequeue, 
"+queue.size()+" in queue, "+x+" millis since enqueued last item, "+dequeuedCounted+" 
maximum waits so far - could indicate serious JVM bug. Please report to [EMAIL 
PROTECTED] along with JVM and OS/kernel.";
+
                        if(queue.size() > 5 && x > (5*timeout)) {
+                               String err = "Waited more than "+timeout+"ms to 
dequeue, "+queue.size()+" in queue, "+x+" millis since enqueued last item, 
"+dequeuedCounted+" maximum waits so far - could indicate serious JVM bug. Please 
report to [EMAIL PROTECTED] along with JVM and OS/kernel.";
                            Core.logger.log(this, err, Logger.NORMAL);
                            System.err.println(err);
                        } else {
+                               if(logMINOR) {
+                                       String err = "Waited more than "+timeout+"ms 
to dequeue, "+queue.size()+" in queue, "+x+" millis since enqueued last item, 
"+dequeuedCounted+" maximum waits so far - could indicate serious JVM bug. Please 
report to [EMAIL PROTECTED] along with JVM and OS/kernel.";
                            Core.logger.log(this, err, Logger.MINOR);
                        }
                    }
                }
+               }
                return innerDequeue();
            }else {
                long x = System.currentTimeMillis();
@@ -104,7 +124,12 @@
            }
         }
     }
-    
+    //Returns a snapshot of the current contents of the queue
+    public Object[] toArray(){
+               synchronized(queue) {
+                       return queue.toArray();
+               }
+    }
     // override in subclasses
     protected Object innerDequeue() {
        Object tmp = queue.removeFirst();

Index: CryptBucket.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/CryptBucket.java,v
retrieving revision 1.1.1.1.6.1
retrieving revision 1.1.1.1.6.2
diff -u -w -r1.1.1.1.6.1 -r1.1.1.1.6.2
--- CryptBucket.java    1 Apr 2003 21:04:53 -0000       1.1.1.1.6.1
+++ CryptBucket.java    28 Oct 2003 20:20:45 -0000      1.1.1.1.6.2
@@ -30,7 +30,7 @@
        if (bc == null)
            throw new IllegalArgumentException();
        key = new byte[bc.getKeySize() >> 3];
-       Core.randSource.nextBytes(key);
+       Core.getRandSource().nextBytes(key);
     }
 
     /**
@@ -46,7 +46,7 @@
        if (bc == null)
            throw new IllegalArgumentException();
        key = new byte[bc.getKeySize() >> 3];
-       Core.randSource.nextBytes(key);
+       Core.getRandSource().nextBytes(key);
     }
 
     public OutputStream getOutputStream() throws IOException {

Index: Fields.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/Fields.java,v
retrieving revision 1.7.4.8.2.2
retrieving revision 1.7.4.8.2.3
diff -u -w -r1.7.4.8.2.2 -r1.7.4.8.2.3
--- Fields.java 21 May 2003 19:54:52 -0000      1.7.4.8.2.2
+++ Fields.java 28 Oct 2003 20:20:45 -0000      1.7.4.8.2.3
@@ -17,20 +17,10 @@
 public abstract class Fields {
 
     public static void main(String[] args) {
-        System.out.println(Long.toHexString(stringToLong(args[0])));
+        System.out.println(Long.toHexString(hexToLong(args[0])));
         System.out.println(Long.toHexString(Long.parseLong(args[0], 16)));
     }
 
-    /** @deprecated */
-    public static final long stringToLong(String hex) throws NumberFormatException {
-        return hexToLong(hex);
-    }
-
-    /** @deprecated */
-    public static final String longToString(long l) {
-        return longToHex(l);
-    }
-
     /** Converts a hex string into a long.
       * 
       * Long.parseLong(hex, 16) assumes the input is nonnegative unless there
@@ -204,7 +194,7 @@
             s = '0' + s;
             
         if (out.length < off + s.length()/2)
-            throw new IndexOutOfBoundsException();
+            throw new IndexOutOfBoundsException("Output buffer too small for input 
("+out.length+"<"+off + s.length()/2+")");
             
         byte b;
         for (int i=0; i < s.length(); i++) {
@@ -295,7 +285,7 @@
         StringTokenizer st = new StringTokenizer(ls, ",");
         long[] r = new long[st.countTokens()];
         for (int i = 0 ; i < r.length ; i++) {
-            r[i] = stringToLong(st.nextToken());
+            r[i] = hexToLong(st.nextToken());
         }
         return r;
     }
@@ -303,7 +293,7 @@
     public static final String numberList(long[] ls) {
         StringBuffer sb = new StringBuffer(ls.length*18);
         for (int i = 0 ; i < ls.length ; i++) {
-            sb.append(longToString(ls[i]));
+            sb.append(longToHex(ls[i]));
             if (i != ls.length - 1)
                 sb.append(',');
         }

Index: FileBucket.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/FileBucket.java,v
retrieving revision 1.4.2.5.2.3
retrieving revision 1.4.2.5.2.4
diff -u -w -r1.4.2.5.2.3 -r1.4.2.5.2.4
--- FileBucket.java     5 Jul 2003 01:09:55 -0000       1.4.2.5.2.3
+++ FileBucket.java     28 Oct 2003 20:20:45 -0000      1.4.2.5.2.4
@@ -38,7 +38,7 @@
      */
 
     public FileBucket() {
-       file = new File(tempDir, "t" + 
Fields.longToString(Math.abs(Core.randSource.nextInt())));
+       file = new File(tempDir, "t" + 
Fields.longToHex(Math.abs(Core.getRandSource().nextInt())));
         // Useful for finding temp file leaks.
         //System.err.println("-- FileBucket.ctr(1) -- " + file.getAbsolutePath());
         //(new Exception("get stack")).printStackTrace();
@@ -85,7 +85,7 @@
            if(!append) {
                resetLength();
            }
-           if(Core.logger.shouldLog(Logger.DEBUG))
+           if(Core.logger.shouldLog(Logger.DEBUG,this))
                e = new Exception("debug");
        }
        
@@ -128,7 +128,7 @@
        
        public FileBucketInputStream(File f) throws IOException {
            super(f);
-           if(Core.logger.shouldLog(Logger.DEBUG))
+           if(Core.logger.shouldLog(Logger.DEBUG,this))
                e = new Exception("debug");
        }
     }
@@ -170,7 +170,7 @@
 
     public void finalize() throws Throwable
     {
-       if(Core.logger.shouldLog(Logger.DEBUG))
+       if(Core.logger.shouldLog(Logger.DEBUG,this))
            Core.logger.log(this, "FileBucket Finalizing "+file.getName(), 
Logger.DEBUG);
        if(newFile && file.exists()) {
            Core.logger.log(this, "Deleting bucket "+file.getName(), Logger.DEBUGGING);
@@ -178,7 +178,7 @@
             if (file.exists())
                 Core.logger.log(this, "Delete failed on bucket "+file.getName(), 
Logger.ERROR);
        }
-       if(Core.logger.shouldLog(Logger.DEBUG))
+       if(Core.logger.shouldLog(Logger.DEBUG,this))
            Core.logger.log(this, "FileBucket Finalized "+file.getName(), 
Logger.DEBUG);
     }
     

Index: FileLoggerHook.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/FileLoggerHook.java,v
retrieving revision 1.4.4.5.2.9
retrieving revision 1.4.4.5.2.10
diff -u -w -r1.4.4.5.2.9 -r1.4.4.5.2.10
--- FileLoggerHook.java 23 Aug 2003 12:04:43 -0000      1.4.4.5.2.9
+++ FileLoggerHook.java 28 Oct 2003 20:20:45 -0000      1.4.4.5.2.10
@@ -4,6 +4,8 @@
 import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Calendar;
 import java.util.LinkedList;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -26,6 +28,8 @@
     
     private volatile boolean closed = false;
     
+    protected static int INTERVAL = GregorianCalendar.MINUTE;
+    
     private static String uname;
     static {
         try {
@@ -56,6 +60,16 @@
     
     protected OutputStream uout;
     
+    protected boolean logOverwrite = false;
+    
+    /* Base filename for rotating logs */
+    protected String baseFilename = null;
+    
+    /* Whether to redirect stdout */
+    protected boolean redirectStdOut = false;
+    /* Whether to redirect stderr */
+    protected boolean redirectStdErr = false;
+    
     /**
      * Something wierd happens when the disk gets full, also we don't want to block
      * So run the actual write on another thread
@@ -65,6 +79,7 @@
     
     protected static int MAX_LIST_SIZE=100000;
     protected static long MAX_LIST_BYTES=10*(1<<20);
+    protected static boolean useNativeGzip = false;
     
     // FIXME: should reimplement LinkedList with minimal locking
     
@@ -72,10 +87,42 @@
        MAX_LIST_SIZE = len;
     }
     
+    public static void setUseNativeGzip(boolean x) {
+       useNativeGzip = x;
+    }
+    
     public static void setMaxListBytes(long len) {
        MAX_LIST_BYTES = len;
     }
     
+    public static void setInterval(String intervalName) {
+       if(intervalName.equalsIgnoreCase("MINUTE"))
+           INTERVAL = Calendar.MINUTE;
+       else if(intervalName.equalsIgnoreCase("HOUR"))
+           INTERVAL = Calendar.HOUR;
+       else if(intervalName.equalsIgnoreCase("DAY"))
+           INTERVAL = Calendar.DAY_OF_MONTH;
+       else if(intervalName.equalsIgnoreCase("WEEK"))
+           INTERVAL = Calendar.WEEK_OF_YEAR;
+       else if(intervalName.equalsIgnoreCase("MONTH"))
+           INTERVAL = Calendar.MONTH;
+       else if(intervalName.equalsIgnoreCase("YEAR"))
+           INTERVAL = Calendar.YEAR;
+       else throw new IllegalArgumentException("invalid interval "+intervalName);
+    }
+    
+    protected String getHourLogName(Calendar c) {
+       return baseFilename + "-" + c.get(c.YEAR) + "-" + pad2(c.get(c.MONTH)) +
+           "-" + pad2(c.get(c.DAY_OF_MONTH)) + "-" + pad2(c.get(c.HOUR_OF_DAY)) +
+           (INTERVAL == c.MINUTE ? ("-" + pad2(c.get(c.MINUTE))) : "");
+    }
+    
+    protected String pad2(int x) {
+       String s = Integer.toString(x);
+       if(s.length() == 1) s = "0" + s;
+       return s;
+    }
+    
     class WriterThread extends Thread {
        WriterThread() {
            super("Log File Writer Thread");
@@ -83,8 +130,80 @@
        
        public void run() {
            Object o = null;
+           long thisTime = System.currentTimeMillis();
+           long prevTime;
+           long nextHour = -1;
+           GregorianCalendar gc = null;
+           String filename = null;
+           if(baseFilename != null) {
+               gc = new GregorianCalendar();
+               filename = getHourLogName(gc);
+               uout = openNewLogFile(filename);
+               switch(INTERVAL) {
+               case Calendar.YEAR:
+                   gc.set(Calendar.MONTH, 0);
+               case Calendar.MONTH:
+                   gc.set(Calendar.DAY_OF_MONTH, 0);
+               case Calendar.WEEK_OF_YEAR:
+                   if(INTERVAL == Calendar.WEEK_OF_YEAR)
+                       gc.set(Calendar.DAY_OF_WEEK, 0);
+               case Calendar.DAY_OF_MONTH:
+                   gc.set(Calendar.HOUR, 0);
+               case Calendar.HOUR:
+                   gc.set(Calendar.MINUTE, 0);
+               case Calendar.MINUTE:
+                   gc.set(Calendar.SECOND, 0);
+                   gc.set(Calendar.MILLISECOND, 0);
+               }
+               gc.add(INTERVAL, 1);
+               nextHour = gc.getTimeInMillis();
+               System.err.println("Start time: "+gc);
+               lout = new PrintStream(uout);
+           }
+           freenet.Core.logStream = lout; // FIXME
+           if(redirectStdOut)
+               System.setOut(lout);
+           if(redirectStdErr)
+               System.setErr(lout);
            while(true) {
                try {
+                   prevTime = thisTime;
+                   thisTime = System.currentTimeMillis();
+                   if(baseFilename != null) {
+                       if(thisTime > nextHour) {
+                           // Switch logs
+                           try {
+                               uout.flush();
+                           } catch (IOException e) {
+                               System.err.println("Flushing on change caught "+e);
+                           }
+                           String oldFilename = filename;
+                           filename = getHourLogName(gc);
+                           OutputStream os = openNewLogFile(filename);
+                           OutputStream oldUout = uout;
+                           uout = os;
+                           lout = new PrintStream(uout);
+                           if(redirectStdOut)
+                               System.setOut(lout);
+                           if(redirectStdErr)
+                               System.setErr(lout);
+                           freenet.Core.logStream = lout; // FIXME
+                           try {
+                               oldUout.close();
+                           } catch (IOException e) {
+                               System.err.println("Closing on change caught "+e);
+                           }
+                           System.err.println("Almost rotated");
+                           if(useNativeGzip) {
+                               CompressorThread ct = new 
CompressorThread(oldFilename);
+                               ct.start();
+                               // Don't care about result
+                           } // FIXME: implement a portable default compressor
+                           gc.add(INTERVAL, 1);
+                           nextHour = gc.getTimeInMillis();
+                           System.err.println("Rotated");
+                       }
+                   }
                    if(uout != null) {
                        myWrite(uout, null);
                    } else lout.flush();
@@ -94,6 +213,7 @@
                            try {
                                list.wait(500);
                            } catch (InterruptedException e) {};
+                           if(list.size() == 0) continue;
                        }
                        o = list.removeFirst();
                        listBytes -= (((byte[])o).length+16);
@@ -132,11 +252,83 @@
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {};
                    sleepTime += sleepTime;
+                   if(sleepTime > 3600) sleepTime = 3600;
                } else
                    return;
            }
        }
        
+       protected OutputStream openNewLogFile(String filename) {
+           while(true) {
+               long sleepTime = 1000;
+               try {
+                   System.err.println("Creating new logfile "+filename);
+                   return new FileOutputStream(filename, !logOverwrite);
+               } catch (IOException e) {
+                   System.err.println("Could not create FOS "+filename+": "+e);
+                   System.err.println("Sleeping "+sleepTime/1000+" seconds");
+                   try {
+                       Thread.sleep(sleepTime);
+                   } catch (InterruptedException ex) {};
+                   sleepTime += sleepTime;
+               }
+           }
+       }
+    }
+    
+    protected int runningCompressors = 0;
+    protected Object runningCompressorsSync = new Object();
+    
+    class CompressorThread extends Thread {
+       protected String filename;
+       
+       public CompressorThread(String fn) {
+           super("Logfile compressor thread");
+           this.filename = fn;
+       }
+       
+       public void run() {
+           synchronized(runningCompressorsSync) {
+               runningCompressors++;
+               if(runningCompressors > 3) { // try to absorb a spike...
+                   System.err.println("Too many compressors ("+
+                                      runningCompressors+") running!");
+                   return;
+               }
+           }
+           try {
+               System.err.println("Starting gzip "+filename);
+               Process r = Runtime.getRuntime().exec(new String[] {
+                   "gzip", filename });
+               System.err.println("Started gzip "+filename);
+               InputStream is = r.getInputStream();
+               InputStream es = r.getErrorStream();
+               while(true) {
+                   byte[] buf = new byte[1024];
+                   try {
+                       is.read(buf, 0, buf.length);
+                   } catch (IOException e) {};
+                   try {
+                       es.read(buf, 0, buf.length);
+                   } catch (IOException e) {};
+                   try {
+                       r.exitValue();
+                       break;
+                   } catch (IllegalThreadStateException e) {}
+               }
+               System.err.println("Finished gzip "+filename);
+               is.close();
+               es.close();
+           } catch (IOException e) {
+               System.err.println("Cannot compress old logfile "+
+                                  filename);
+               e.printStackTrace(System.err);
+           } finally {
+               synchronized(runningCompressorsSync) {
+                   runningCompressors--;
+               }
+           }
+       }
     }
     
     /**
@@ -152,17 +344,23 @@
      * @exception IOException if the file couldn't be opened for append.
      */
     public FileLoggerHook(String filename, String fmt, 
-                          String dfmt, int threshold, boolean assumeWorking)
+                         String dfmt, int threshold, boolean assumeWorking,
+                         boolean logOverwrite)
        throws IOException {
-        this(new FileOutputStream(filename, true), fmt, dfmt, threshold);
+       this(false, filename, fmt, dfmt, threshold, assumeWorking, 
+            logOverwrite);
+    }
        
+    private void checkStdStreams() {
         // Redirect System.err and System.out to the Logger Printstream
         // if they don't exist (like when running under javaw)
-       if(!assumeWorking) {
            System.out.print(" \b");
-           if(System.out.checkError()) System.setOut(lout);
+       if(System.out.checkError()) {
+           redirectStdOut = true;
+       }
            System.err.print(" \b"); 
-           if(System.err.checkError()) System.setErr(lout);
+       if(System.err.checkError()) {
+           redirectStdErr = true;
        }
     }
     
@@ -182,7 +380,40 @@
      */
     public FileLoggerHook(PrintStream stream, String fmt, String dfmt,
                           int threshold) {
+       this(fmt, dfmt, threshold);
         lout = stream;
+       WriterThread wt = new WriterThread();
+       //wt.setDaemon(true);
+       CloserThread ct = new CloserThread();
+       Runtime.getRuntime().addShutdownHook(ct);
+       wt.start();
+    }
+    
+    public FileLoggerHook(boolean rotate, String baseFilename, String fmt, 
+                         String dfmt, int threshold, boolean assumeWorking,
+                         boolean logOverwrite) 
+       throws IOException {
+       this(fmt, dfmt, threshold);
+       this.logOverwrite = logOverwrite;
+       //System.err.println("Creating FileLoggerHook with threshold "+threshold);
+       if(!assumeWorking)
+           checkStdStreams();
+       if(rotate) {
+           lout = null;
+           this.baseFilename = baseFilename;
+       } else {
+           lout = new PrintStream(new FileOutputStream(baseFilename, 
+                                                       !logOverwrite));
+       }
+       WriterThread wt = new WriterThread();
+       //wt.setDaemon(true);
+       CloserThread ct = new CloserThread();
+       Runtime.getRuntime().addShutdownHook(ct);
+       wt.start();
+    }
+    
+    private FileLoggerHook(String fmt, String dfmt,
+                          int threshold) {
         this.threshold = threshold;
         if (dfmt != null && !dfmt.equals("")) {
             try {
@@ -231,15 +462,10 @@
 
         this.str = new String[strVec.size()];
        str = (String[])strVec.toArray(str);
-       WriterThread wt = new WriterThread();
-       //wt.setDaemon(true);
-       CloserThread ct = new CloserThread();
-       Runtime.getRuntime().addShutdownHook(ct);
-       wt.start();
     }
     
     public void log(Object o, Class c, String msg, Throwable e, int priority){
-       if (!acceptPriority(priority)) return;
+       if (!shouldLog(priority, c)) return;
        
        if(closed) return;
 

Index: LRUQueue.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/LRUQueue.java,v
retrieving revision 1.3
retrieving revision 1.3.6.1
diff -u -w -r1.3 -r1.3.6.1
--- LRUQueue.java       12 Apr 2002 21:44:10 -0000      1.3
+++ LRUQueue.java       28 Oct 2003 20:20:45 -0000      1.3.6.1
@@ -1,16 +1,19 @@
 package freenet.support;
 
 import java.util.Enumeration;
+import java.util.Hashtable;
 
 public class LRUQueue {
 
     /*
-     * I moves this over to a linked list from a vector, because thinking
-     * about the way it was was keeping me awake at night. 
-     *
-     * It is still O(n) but at least this looses all the memcopies.
+     * I've just converted this to using the DLList and Hashtable
+     * this makes it Hashtable time instead of O(N) for push and
+     * remove, and Hashtable time instead of O(1) for pop.  Since
+     * push is by far the most done operation, this should be an
+     * overall improvement.
      */
     private final DoublyLinkedListImpl list = new DoublyLinkedListImpl();
+    private final Hashtable hash = new Hashtable();
 
     /**
      *       push()ing an object that is already in
@@ -19,37 +22,37 @@
      *       a duplicate entry in the queue.
      */
     public final synchronized void push(Object obj) {
-        QItem insert = null;
-        for (Enumeration e = list.forwardElements() ; e.hasMoreElements() ;) {
-            QItem qi = (QItem) e.nextElement();
-            if (obj.equals(qi.obj)) {
-                insert = qi;
-                list.remove(qi);
-                break;
-            }
-        }
-        if (insert == null)
+        QItem insert = (QItem)hash.get(obj);        
+        if (insert == null) {
             insert = new QItem(obj);
+            hash.put(obj,insert);
+        } else {
+            list.remove(insert);
+        }
 
         list.unshift(insert);
     } 
 
     // Least recently pushed Object.
     public final synchronized Object pop() {
-        return list.size() > 0 ? ((QItem) list.pop()).obj : null;
+        if ( list.size() > 0 ) {
+            return ((QItem)hash.remove(((QItem)list.pop()).obj)).obj;
+        } else {
+            return null;
+        }
     }
 
     public final int size() {
         return list.size();
     }
 
-    public final synchronized void remove(Object obj) {
-        for (Enumeration e = list.forwardElements() ; e.hasMoreElements() ;) {
-            QItem qi = (QItem) e.nextElement();
-            if (obj.equals(qi.obj)) {
-                list.remove(qi);
-                break;
-            }
+    public final synchronized boolean remove(Object obj) {
+       QItem i = (QItem)(hash.remove(obj));
+       if(i != null) {
+           list.remove(i);
+           return true;
+       } else {
+           return false;
         }
     }
 

Index: LimitCounter.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/LimitCounter.java,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.6.1
diff -u -w -r1.1.1.1 -r1.1.1.1.6.1
--- LimitCounter.java   13 Jan 2002 05:24:57 -0000      1.1.1.1
+++ LimitCounter.java   28 Oct 2003 20:20:45 -0000      1.1.1.1.6.1
@@ -31,6 +31,12 @@
         checkTimeout();
         return count > maxCount;
     }
+    
+    // Currently dumps the current status to a string
+       public synchronized String toString() {
+               checkTimeout();
+               return count+"/"+maxCount+" ("+Float.toString(((float)count / 
(float)maxCount*100f))+"%)";
+       }
 
     // for the *current interval*.
     public synchronized float rate() {

Index: Logger.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/Logger.java,v
retrieving revision 1.7.4.1
retrieving revision 1.7.4.1.2.1
diff -u -w -r1.7.4.1 -r1.7.4.1.2.1
--- Logger.java 9 Jan 2003 01:42:36 -0000       1.7.4.1
+++ Logger.java 28 Oct 2003 20:20:45 -0000      1.7.4.1.2.1
@@ -25,6 +25,7 @@
      *                     this.
      */
     public Logger(int threshold) {
+//     System.err.println("Creating Logger with threshold "+threshold);
         this.threshold = threshold;
         hooks = new Vector();
     }
@@ -38,7 +39,7 @@
      *                 Logger.NORMAL, Logger.MINOR, or Logger.DEBUGGING.
      **/
     public void log(Object source, String message, int priority) {
-        if (!acceptPriority(priority)) return;
+        if (!shouldLog(priority,source)) return;
         log(source, source == null ? null : source.getClass(), 
             message, null, priority);
     }
@@ -54,7 +55,7 @@
      */
     public void log(Object o, String message, Throwable e, 
                     int priority) {
-        if (!acceptPriority(priority)) return;
+        if (!shouldLog(priority,o)) return;
         log(o, o == null ? null : o.getClass(), message, e, priority);
     }
 
@@ -66,7 +67,7 @@
      *                 Logger.NORMAL, Logger.MINOR, or Logger.DEBUGGING.
      */
     public void log(Class c, String message, int priority) {
-        if (!acceptPriority(priority)) return;
+        if (!shouldLog(priority,c)) return;
         log(null, c, message, null, priority);
     }
 
@@ -80,7 +81,7 @@
      */
     public void log(Class c, String message, Throwable e,
                     int priority) {
-        if (!acceptPriority(priority)) return;
+        if (!shouldLog(priority,c)) return;
         log(null, c, message, e, priority);
     }
 

Index: LoggerHook.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/LoggerHook.java,v
retrieving revision 1.5.4.1
retrieving revision 1.5.4.1.2.1
diff -u -w -r1.5.4.1 -r1.5.4.1.2.1
--- LoggerHook.java     9 Jan 2003 01:42:36 -0000       1.5.4.1
+++ LoggerHook.java     28 Oct 2003 20:20:45 -0000      1.5.4.1.2.1
@@ -1,9 +1,24 @@
 package freenet.support;
 
+import java.util.StringTokenizer;
+import java.util.Vector;
+
 public abstract class LoggerHook  {
 
     public int threshold;
 
+    public static final class DetailedThreshold {
+       final String section;
+       final int dThreshold;
+       public DetailedThreshold(String section, int thresh) {
+           this.section = section;
+           this.dThreshold = thresh;
+       }
+    }
+    
+    public DetailedThreshold[] detailedThresholds = 
+       new DetailedThreshold[0];
+    
     /** These indicate the verbosity levels for calls to log() **/
     
     /** This message indicates an error which prevents correct functionality**/
@@ -36,15 +51,8 @@
 
   public abstract long anyFlags(); // accept if any of these bits set
 
-  public boolean acceptPriority(int prio)
-  {
-      long mf = minFlags();
-      long nf = notFlags();
-      long af = anyFlags();
-      if ((prio & mf) != mf) return false;
-      if ((prio & nf) != 0) return false;
-      if ((prio & af) != 0) return true;
-      return false;
+  public boolean acceptPriority(int prio) {
+      return prio >= threshold;
   }
 
     /**
@@ -55,4 +63,53 @@
         this.threshold = thresh;
     }
 
+    public void setDetailedThresholds(String details) {
+//     System.err.println("Setting detailed thresholds for "+this+
+//                        ": "+details);
+       if(details == null || details.length() == 0) return;
+       StringTokenizer st = new StringTokenizer(details,",",false);
+       Vector stuff = new Vector();
+       while(st.hasMoreTokens()) {
+           String token = st.nextToken();
+//         System.err.println("Got token: "+token);
+           if(token.length() == 0) continue;
+           int x = token.indexOf(':');
+           if(x < 0) continue;
+           if(x == token.length() - 1) continue;
+           String section = token.substring(0, x);
+           String value = token.substring(x+1, token.length());
+           int thresh = Logger.priorityOf(value);
+//         System.err.println("Pair: "+section+" : "+value);
+           stuff.add(new DetailedThreshold(section, thresh));
+       }
+       DetailedThreshold[] newThresholds = 
+           new DetailedThreshold[stuff.size()];
+       stuff.toArray(newThresholds);
+       detailedThresholds = newThresholds;
+    }
+    
+    public boolean shouldLog(int priority, Class c) {
+       int thresh = threshold;
+//     System.err.println(this+"shouldLog("+priority+","+c+"), thresh="+thresh);
+       if(c != null) {
+           String cname = c.getName();
+           if(detailedThresholds.length > 0) {
+               for(int i=0;i<detailedThresholds.length;i++) {
+                   DetailedThreshold dt = detailedThresholds[i];
+                   if(cname.startsWith(dt.section)) {
+                       thresh = dt.dThreshold;
+//                     System.err.println(cname+" starts with "+dt.section+"("+
+//                                        dt.dThreshold+")");
+                   }
+               }
+           }
+       }
+//     System.err.println("Leaving: "+this+"shouldLog("+priority+","+c+
+//                        "), thresh="+thresh);
+       return priority >= thresh;
+    }
+    
+    public final boolean shouldLog(int prio, Object o) {
+       return shouldLog(prio, o.getClass());
+    }
 }

Index: MultiValueTable.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/MultiValueTable.java,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.6.1
diff -u -w -r1.1.1.1 -r1.1.1.1.6.1
--- MultiValueTable.java        13 Jan 2002 05:24:57 -0000      1.1.1.1
+++ MultiValueTable.java        28 Oct 2003 20:20:45 -0000      1.1.1.1.6.1
@@ -68,6 +68,18 @@
                 v.elements());
     }
 
+    public int countAll(Object key) {
+       Vector v = (Vector)table.get(key);
+       if(v != null) 
+               return v.size();
+        else
+               return 0;
+    }
+    
+    public Object getSync(Object key) {
+       return table.get(key);
+    }
+    
     public Object[] getArray(Object key) {
         synchronized (table) {
             Vector v = (Vector) table.get(key);

Index: SimpleDataObjectStore.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/SimpleDataObjectStore.java,v
retrieving revision 1.4.2.4.2.3
retrieving revision 1.4.2.4.2.4
diff -u -w -r1.4.2.4.2.3 -r1.4.2.4.2.4
--- SimpleDataObjectStore.java  2 Aug 2003 02:36:19 -0000       1.4.2.4.2.3
+++ SimpleDataObjectStore.java  28 Oct 2003 20:20:45 -0000      1.4.2.4.2.4
@@ -1,3 +1,4 @@
+/* -*- Mode: java; c-basic-indent: 4; tab-width: 4 -*- */
 package freenet.support;
 import freenet.Core;
 import freenet.support.Comparator;

Index: TempBucketFactory.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/TempBucketFactory.java,v
retrieving revision 1.2.2.4.2.2
retrieving revision 1.2.2.4.2.3
diff -u -w -r1.2.2.4.2.2 -r1.2.2.4.2.3
--- TempBucketFactory.java      2 Aug 2003 02:36:19 -0000       1.2.2.4.2.2
+++ TempBucketFactory.java      28 Oct 2003 20:20:45 -0000      1.2.2.4.2.3
@@ -73,12 +73,12 @@
     do {
       if (tmpDir != null) {
         f = new File(tmpDir, "tbf_" +
-            Long.toHexString(Math.abs(Core.randSource.nextInt())));
+            Long.toHexString(Math.abs(Core.getRandSource().nextInt())));
        Core.logger.log(this, "Temp file in "+tmpDir,
                        Core.logger.DEBUG);
       } else {
         f = new File("tbf_" +
-            Long.toHexString(Math.abs(Core.randSource.nextInt())));
+            Long.toHexString(Math.abs(Core.getRandSource().nextInt())));
        Core.logger.log(this, "Temp file in pwd",
                        Core.logger.DEBUG);
       }

Index: TempFileBucket.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/support/TempFileBucket.java,v
retrieving revision 1.1.2.6.2.4
retrieving revision 1.1.2.6.2.5
diff -u -w -r1.1.2.6.2.4 -r1.1.2.6.2.5
--- TempFileBucket.java 13 May 2003 01:55:46 -0000      1.1.2.6.2.4
+++ TempFileBucket.java 28 Oct 2003 20:20:45 -0000      1.1.2.6.2.5
@@ -286,7 +286,7 @@
          ol = l;
       }
       if(fakeLength != l) {
-         if(Core.logger.shouldLog(Logger.DEBUG))
+         if(Core.logger.shouldLog(Logger.DEBUG,this))
              Core.logger.log(this, "getLengthSynchronized("+len+"): increasing "+
                              fakeLength+" to: "+l+" (real length: "+length+")",
                              Logger.DEBUG);
@@ -313,7 +313,7 @@
                                             long restartCount) throws IOException {
          super(s, append, restartCount);
          streams.addElement(this);
-         if(Core.logger.shouldLog(Logger.DEBUG))
+         if(Core.logger.shouldLog(Logger.DEBUG,this))
              Core.logger.log(this, "Created HookedFileBucketOutputStream("+s+","+
                              append+","+restartCount+")", Logger.DEBUG);
       }

_______________________________________________
cvs mailing list
[EMAIL PROTECTED]
http://dodo.freenetproject.org/cgi-bin/mailman/listinfo/cvs

Reply via email to