From d092dd79ba293bdf169e35db04c937f1057da02c Mon Sep 17 00:00:00 2001
From: jrandom <jrandom>
Date: Mon, 4 Oct 2004 13:53:10 +0000
Subject: [PATCH] get rid of the really really frequent temporary object
 creation

---
 .../src/net/i2p/stat/BufferedStatLog.java     | 129 ++++++++++++------
 1 file changed, 85 insertions(+), 44 deletions(-)

diff --git a/core/java/src/net/i2p/stat/BufferedStatLog.java b/core/java/src/net/i2p/stat/BufferedStatLog.java
index a41ef86993..fa131b9a3c 100644
--- a/core/java/src/net/i2p/stat/BufferedStatLog.java
+++ b/core/java/src/net/i2p/stat/BufferedStatLog.java
@@ -12,24 +12,34 @@ import java.util.StringTokenizer;
 
 import net.i2p.I2PAppContext;
 import net.i2p.util.I2PThread;
+import net.i2p.util.Log;
 
 /**
  * 
  */
 public class BufferedStatLog implements StatLog {
     private I2PAppContext _context;
-    private List _events;
+    private Log _log;
+    private StatEvent _events[];
+    private int _eventNext;
+    private int _lastWrite;
     /** flush stat events to disk after this many events (or 30s)*/
     private int _flushFrequency;
     private List _statFilters;
+    private String _lastFilters;
     private BufferedWriter _out;
     private String _outFile;
     
     public BufferedStatLog(I2PAppContext ctx) {
         _context = ctx;
-        _events = new ArrayList(1000);
+        _log = ctx.logManager().getLog(BufferedStatLog.class);
+        _events = new StatEvent[1000];
+        for (int i = 0; i < 1000; i++)
+            _events[i] = new StatEvent();
+        _eventNext = 0;
+        _lastWrite = _events.length-1;
         _statFilters = new ArrayList(10);
-        _flushFrequency = 1000;
+        _flushFrequency = 500;
         I2PThread writer = new I2PThread(new StatLogWriter(), "StatLogWriter");
         writer.setDaemon(true);
         writer.start();
@@ -37,9 +47,22 @@ public class BufferedStatLog implements StatLog {
     
     public void addData(String scope, String stat, long value, long duration) {
         synchronized (_events) {
-            _events.add(new StatEvent(scope, stat, value, duration));
-            if (_events.size() > _flushFrequency)
-                _events.notifyAll();
+            _events[_eventNext].init(scope, stat, value, duration);
+            _eventNext = (_eventNext + 1) % _events.length;
+            
+            if (_eventNext == _lastWrite)
+                _lastWrite = (_lastWrite + 1) % _events.length; // drop an event
+            
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("AddData next=" + _eventNext + " lastWrite=" + _lastWrite);
+            
+            if (_eventNext > _lastWrite) {
+                if (_eventNext - _lastWrite >= _flushFrequency)
+                    _events.notifyAll();
+            } else {
+                if (_events.length - 1 - _lastWrite + _eventNext >= _flushFrequency)
+                    _events.notifyAll();
+            }
         }
     }    
 
@@ -52,12 +75,17 @@ public class BufferedStatLog implements StatLog {
     private void updateFilters() {
         String val = _context.getProperty("stat.logFilters");
         if (val != null) {
-            StringTokenizer tok = new StringTokenizer(val, ",");
-            synchronized (_statFilters) {
-                _statFilters.clear();
-                while (tok.hasMoreTokens())
-                    _statFilters.add(tok.nextToken().trim());
+            if ( (_lastFilters != null) && (_lastFilters.equals(val)) ) {
+                // noop
+            } else {
+                StringTokenizer tok = new StringTokenizer(val, ",");
+                synchronized (_statFilters) {
+                    _statFilters.clear();
+                    while (tok.hasMoreTokens())
+                        _statFilters.add(tok.nextToken().trim());
+                }
             }
+            _lastFilters = val;
         } else {
             synchronized (_statFilters) { _statFilters.clear(); }
         }
@@ -79,45 +107,58 @@ public class BufferedStatLog implements StatLog {
     private class StatLogWriter implements Runnable {
         private SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd HH:mm:ss.SSS");
         public void run() {
-            List cur = new ArrayList(1000);
+            int writeStart = -1;
+            int writeEnd = -1;
             while (true) {
                 synchronized (_events) {
-                    if (_events.size() < _flushFrequency) {
-                        try { _events.wait(30*1000); } catch (InterruptedException ie) {}
-                    } 
-                    cur.addAll(_events);
-                    _events.clear();
+                    if (_eventNext > _lastWrite) {
+                        if (_eventNext - _lastWrite < _flushFrequency)
+                            try { _events.wait(30*1000); } catch (InterruptedException ie) {}
+                    } else {
+                        if (_events.length - 1 - _lastWrite + _eventNext < _flushFrequency)
+                            try { _events.wait(30*1000); } catch (InterruptedException ie) {}
+                    }
+                    writeStart = (_lastWrite + 1) % _events.length;
+                    writeEnd = _eventNext;
+                    _lastWrite = (writeEnd == 0 ? _events.length-1 : writeEnd - 1);
                 }
-                if (cur.size() > 0) {
-                    writeEvents(cur);
-                    cur.clear();
+                if (writeStart != writeEnd) {
+                    try {
+                        if (_log.shouldLog(Log.DEBUG))
+                            _log.debug("writing " + writeStart +"->"+ writeEnd);
+                        writeEvents(writeStart, writeEnd);
+                    } catch (Exception e) {
+                        _log.error("error writing " + writeStart +"->"+ writeEnd, e);
+                    }
                 }
             }
         }
         
-        private void writeEvents(List events) {
+        private void writeEvents(int start, int end) {
             try {    
                 updateFilters();
-                for (int i = 0; i < events.size(); i++) {
-                    StatEvent evt = (StatEvent)events.get(i);
-                    if (!shouldLog(evt.getStat())) continue;
-                    String when = null;
-                    synchronized (_fmt) {
-                        when = _fmt.format(new Date(evt.getTime()));
+                int cur = start;
+                while (cur != end) {
+                    if (shouldLog(_events[cur].getStat())) {
+                        String when = null;
+                        synchronized (_fmt) {
+                            when = _fmt.format(new Date(_events[cur].getTime()));
+                        }
+                        _out.write(when);
+                        _out.write(" ");
+                        if (_events[cur].getScope() == null)
+                            _out.write("noScope ");
+                        else
+                            _out.write(_events[cur].getScope() + " ");
+                        _out.write(_events[cur].getStat()+" ");
+                        _out.write(_events[cur].getValue()+" ");
+                        _out.write(_events[cur].getDuration()+"\n");
                     }
-                    _out.write(when);
-                    _out.write(" ");
-                    if (evt.getScope() == null)
-                        _out.write("noScope ");
-                    else
-                        _out.write(evt.getScope() + " ");
-                    _out.write(evt.getStat()+" ");
-                    _out.write(evt.getValue()+" ");
-                    _out.write(evt.getDuration()+"\n");
+                    cur = (cur + 1) % _events.length;
                 }
                 _out.flush();
             } catch (IOException ioe) {
-                ioe.printStackTrace();
+                _log.error("Error writing out", ioe);
             }
         }
     }
@@ -129,18 +170,18 @@ public class BufferedStatLog implements StatLog {
         private long _value;
         private long _duration;
         
-        public StatEvent(String scope, String stat, long value, long duration) {
+        public long getTime() { return _time; } 
+        public String getScope() { return _scope; }
+        public String getStat() { return _stat; }
+        public long getValue() { return _value; }
+        public long getDuration() { return _duration; }
+        
+        public void init(String scope, String stat, long value, long duration) {
             _scope = scope;
             _stat = stat;
             _value = value;
             _duration = duration;
             _time = _context.clock().now();
         }
-        
-        public long getTime() { return _time; } 
-        public String getScope() { return _scope; }
-        public String getStat() { return _stat; }
-        public long getValue() { return _value; }
-        public long getDuration() { return _duration; }
     }    
 }
-- 
GitLab