get rid of the really really frequent temporary object creation
This commit is contained in:
@ -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[_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) {
|
||||
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) {
|
||||
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) {}
|
||||
}
|
||||
cur.addAll(_events);
|
||||
_events.clear();
|
||||
writeStart = (_lastWrite + 1) % _events.length;
|
||||
writeEnd = _eventNext;
|
||||
_lastWrite = (writeEnd == 0 ? _events.length-1 : writeEnd - 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (cur.size() > 0) {
|
||||
writeEvents(cur);
|
||||
cur.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
int cur = start;
|
||||
while (cur != end) {
|
||||
if (shouldLog(_events[cur].getStat())) {
|
||||
String when = null;
|
||||
synchronized (_fmt) {
|
||||
when = _fmt.format(new Date(evt.getTime()));
|
||||
when = _fmt.format(new Date(_events[cur].getTime()));
|
||||
}
|
||||
_out.write(when);
|
||||
_out.write(" ");
|
||||
if (evt.getScope() == null)
|
||||
if (_events[cur].getScope() == null)
|
||||
_out.write("noScope ");
|
||||
else
|
||||
_out.write(evt.getScope() + " ");
|
||||
_out.write(evt.getStat()+" ");
|
||||
_out.write(evt.getValue()+" ");
|
||||
_out.write(evt.getDuration()+"\n");
|
||||
_out.write(_events[cur].getScope() + " ");
|
||||
_out.write(_events[cur].getStat()+" ");
|
||||
_out.write(_events[cur].getValue()+" ");
|
||||
_out.write(_events[cur].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; }
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user