get rid of the really really frequent temporary object creation

This commit is contained in:
jrandom
2004-10-04 13:53:10 +00:00
committed by zzz
parent a3ba968386
commit d092dd79ba

View File

@ -12,24 +12,34 @@ import java.util.StringTokenizer;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/** /**
* *
*/ */
public class BufferedStatLog implements StatLog { public class BufferedStatLog implements StatLog {
private I2PAppContext _context; 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)*/ /** flush stat events to disk after this many events (or 30s)*/
private int _flushFrequency; private int _flushFrequency;
private List _statFilters; private List _statFilters;
private String _lastFilters;
private BufferedWriter _out; private BufferedWriter _out;
private String _outFile; private String _outFile;
public BufferedStatLog(I2PAppContext ctx) { public BufferedStatLog(I2PAppContext ctx) {
_context = 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); _statFilters = new ArrayList(10);
_flushFrequency = 1000; _flushFrequency = 500;
I2PThread writer = new I2PThread(new StatLogWriter(), "StatLogWriter"); I2PThread writer = new I2PThread(new StatLogWriter(), "StatLogWriter");
writer.setDaemon(true); writer.setDaemon(true);
writer.start(); writer.start();
@ -37,9 +47,22 @@ public class BufferedStatLog implements StatLog {
public void addData(String scope, String stat, long value, long duration) { public void addData(String scope, String stat, long value, long duration) {
synchronized (_events) { synchronized (_events) {
_events.add(new StatEvent(scope, stat, value, duration)); _events[_eventNext].init(scope, stat, value, duration);
if (_events.size() > _flushFrequency) _eventNext = (_eventNext + 1) % _events.length;
_events.notifyAll();
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() { private void updateFilters() {
String val = _context.getProperty("stat.logFilters"); String val = _context.getProperty("stat.logFilters");
if (val != null) { if (val != null) {
StringTokenizer tok = new StringTokenizer(val, ","); if ( (_lastFilters != null) && (_lastFilters.equals(val)) ) {
synchronized (_statFilters) { // noop
_statFilters.clear(); } else {
while (tok.hasMoreTokens()) StringTokenizer tok = new StringTokenizer(val, ",");
_statFilters.add(tok.nextToken().trim()); synchronized (_statFilters) {
_statFilters.clear();
while (tok.hasMoreTokens())
_statFilters.add(tok.nextToken().trim());
}
} }
_lastFilters = val;
} else { } else {
synchronized (_statFilters) { _statFilters.clear(); } synchronized (_statFilters) { _statFilters.clear(); }
} }
@ -79,45 +107,58 @@ public class BufferedStatLog implements StatLog {
private class StatLogWriter implements Runnable { private class StatLogWriter implements Runnable {
private SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd HH:mm:ss.SSS"); private SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd HH:mm:ss.SSS");
public void run() { public void run() {
List cur = new ArrayList(1000); int writeStart = -1;
int writeEnd = -1;
while (true) { while (true) {
synchronized (_events) { synchronized (_events) {
if (_events.size() < _flushFrequency) { if (_eventNext > _lastWrite) {
try { _events.wait(30*1000); } catch (InterruptedException ie) {} if (_eventNext - _lastWrite < _flushFrequency)
} try { _events.wait(30*1000); } catch (InterruptedException ie) {}
cur.addAll(_events); } else {
_events.clear(); 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) { if (writeStart != writeEnd) {
writeEvents(cur); try {
cur.clear(); 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 { try {
updateFilters(); updateFilters();
for (int i = 0; i < events.size(); i++) { int cur = start;
StatEvent evt = (StatEvent)events.get(i); while (cur != end) {
if (!shouldLog(evt.getStat())) continue; if (shouldLog(_events[cur].getStat())) {
String when = null; String when = null;
synchronized (_fmt) { synchronized (_fmt) {
when = _fmt.format(new Date(evt.getTime())); 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); cur = (cur + 1) % _events.length;
_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");
} }
_out.flush(); _out.flush();
} catch (IOException ioe) { } 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 _value;
private long _duration; 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; _scope = scope;
_stat = stat; _stat = stat;
_value = value; _value = value;
_duration = duration; _duration = duration;
_time = _context.clock().now(); _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; }
} }
} }