420034 Removed threads/timers from Date caching

This commit is contained in:
Greg Wilkins 2013-10-24 11:07:40 +11:00
parent ebf11ebfb8
commit d5f83a8159
9 changed files with 134 additions and 169 deletions

View File

@ -24,6 +24,10 @@ import java.util.TimeZone;
import org.eclipse.jetty.util.StringUtil;
/**
* ThreadLocal Date formatters for HTTP style dates.
*
*/
public class DateGenerator
{
private static final TimeZone __GMT = TimeZone.getTimeZone("GMT");

View File

@ -23,6 +23,10 @@ import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* ThreadLocal data parsers for HTTP style dates
*
*/
class DateParser
{
private static final TimeZone __GMT = TimeZone.getTimeZone("GMT");

View File

@ -397,8 +397,7 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
{
if (_logDateFormat != null)
{
_logDateCache = new DateCache(_logDateFormat, _logLocale);
_logDateCache.setTimeZoneID(_logTimeZone);
_logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
}
if (_ignorePaths != null && _ignorePaths.length > 0)

View File

@ -28,7 +28,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@ -49,7 +48,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.DateCache;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.URIUtil;
@ -83,9 +81,9 @@ public class Server extends HandlerWrapper implements Attributes
private boolean _stopAtShutdown;
private boolean _dumpAfterStart=false;
private boolean _dumpBeforeStop=false;
private HttpField _dateField;
private volatile DateField _dateField;
/* ------------------------------------------------------------ */
public Server()
{
@ -264,11 +262,27 @@ public class Server extends HandlerWrapper implements Attributes
_dumpBeforeStop = dumpBeforeStop;
}
/* ------------------------------------------------------------ */
public HttpField getDateField()
{
return _dateField;
long now=System.currentTimeMillis();
long seconds = now/1000;
DateField df = _dateField;
if (df==null || df._seconds!=seconds)
{
synchronized (this) // Trade some contention for less garbage
{
df = _dateField;
if (df==null || df._seconds!=seconds)
{
HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.DATE,DateGenerator.formatDate(now));
_dateField=new DateField(seconds,field);
return field;
}
}
}
return df._dateField;
}
/* ------------------------------------------------------------ */
@ -313,25 +327,6 @@ public class Server extends HandlerWrapper implements Attributes
if (isDumpAfterStart())
dumpStdErr();
// use DateCache timer for Date field reformat
final DateGenerator date = new DateGenerator();
long now=System.currentTimeMillis();
long tick=1000*((now/1000)+1)-now;
_dateField=new HttpGenerator.CachedHttpField(HttpHeader.DATE,date.formatDate(now));
DateCache.getTimer().scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
long now=System.currentTimeMillis();
_dateField=new HttpGenerator.CachedHttpField(HttpHeader.DATE,date.formatDate(now));
if (!isRunning())
this.cancel();
}
},tick,1000);
mex.ifExceptionThrow();
}
@ -536,9 +531,9 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public void clearAttributes()
{
Enumeration names = _attributes.getAttributeNames();
Enumeration<String> names = _attributes.getAttributeNames();
while (names.hasMoreElements())
removeBean(_attributes.getAttribute((String)names.nextElement()));
removeBean(_attributes.getAttribute(names.nextElement()));
_attributes.clearAttributes();
}
@ -647,4 +642,19 @@ public class Server extends HandlerWrapper implements Attributes
{
System.err.println(getVersion());
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private static class DateField
{
final long _seconds;
final HttpField _dateField;
public DateField(long seconds, HttpField dateField)
{
super();
_seconds = seconds;
_dateField = dateField;
}
}
}

View File

@ -117,7 +117,7 @@ public class DebugHandler extends HandlerWrapper implements Connection.Listener
private void print(String name,String message)
{
long now=System.currentTimeMillis();
final String d=_date.format(now);
final String d=_date.formatNow(now);
final int ms=(int)(now%1000);
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" "+message);

View File

@ -57,8 +57,7 @@ public class JSONDateConvertor implements JSON.Convertor
public JSONDateConvertor(String format,TimeZone zone,boolean fromJSON)
{
_dateCache=new DateCache(format);
_dateCache.setTimeZone(zone);
_dateCache=new DateCache(format,null,zone);
_fromJSON=fromJSON;
_format=new SimpleDateFormat(format);
_format.setTimeZone(zone);
@ -66,8 +65,7 @@ public class JSONDateConvertor implements JSON.Convertor
public JSONDateConvertor(String format, TimeZone zone, boolean fromJSON, Locale locale)
{
_dateCache = new DateCache(format, locale);
_dateCache.setTimeZone(zone);
_dateCache = new DateCache(format, locale, zone);
_fromJSON = fromJSON;
_format = new SimpleDateFormat(format, new DateFormatSymbols(locale));
_format.setTimeZone(zone);

View File

@ -18,23 +18,19 @@
package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
/* ------------------------------------------------------------ */
/** Date Format Cache.
* Computes String representations of Dates and caches
* the results so that subsequent requests within the same minute
* the results so that subsequent requests within the same second
* will be fast.
*
* Only format strings that contain either "ss" or "ss.SSS" are
* handled.
* Only format strings that contain either "ss". Sub second formatting is
* not handled.
*
* The timezone of the date may be included as an ID with the "zzz"
* format string or as an offset with the "ZZZ" format string.
@ -49,30 +45,15 @@ public class DateCache
public static final String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy";
private final String _formatString;
private String _tzFormatString;
private SimpleDateFormat _tzFormat;
private final String _tzFormatString;
private final SimpleDateFormat _tzFormat;
private final Locale _locale ;
private volatile Tick _tick;
private Locale _locale = null;
private DateFormatSymbols _dfs = null;
private static Timer __timer;
public static Timer getTimer()
{
synchronized (DateCache.class)
{
if (__timer==null)
__timer=new Timer("DateCache",true);
return __timer;
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private static class Tick
public static class Tick
{
final long _seconds;
final String _string;
@ -99,85 +80,28 @@ public class DateCache
*/
public DateCache(String format)
{
_formatString=format;
setTimeZone(TimeZone.getDefault());
synchronized (DateCache.class)
{
long now=System.currentTimeMillis();
long tick=1000*((now/1000)+1)-now;
formatNow();
getTimer().scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
formatNow();
}
},
tick,
1000);
}
this(format,null,TimeZone.getDefault());
}
/* ------------------------------------------------------------ */
public DateCache(String format,Locale l)
{
this(format);
this(format,l,TimeZone.getDefault());
}
/* ------------------------------------------------------------ */
public DateCache(String format,Locale l,String tz)
{
this(format,l,TimeZone.getTimeZone(tz));
}
/* ------------------------------------------------------------ */
public DateCache(String format,Locale l,TimeZone tz)
{
_formatString=format;
_locale = l;
setTimeZone(TimeZone.getDefault());
}
/* ------------------------------------------------------------ */
public DateCache(String format,DateFormatSymbols s)
{
this(format);
_dfs = s;
setTimeZone(TimeZone.getDefault());
}
/* ------------------------------------------------------------ */
/** Set the timezone.
* @param tz TimeZone
*/
public void setTimeZone(TimeZone tz)
{
setTzFormatString(tz);
if( _locale != null )
{
_tzFormat=new SimpleDateFormat(_tzFormatString,_locale);
}
else if( _dfs != null )
{
_tzFormat=new SimpleDateFormat(_tzFormatString,_dfs);
}
else
{
_tzFormat=new SimpleDateFormat(_tzFormatString);
}
_tzFormat.setTimeZone(tz);
_tick=null;
}
/* ------------------------------------------------------------ */
public TimeZone getTimeZone()
{
return _tzFormat.getTimeZone();
}
/* ------------------------------------------------------------ */
/** Set the timezone.
* @param timeZoneId TimeZoneId the ID of the zone as used by
* TimeZone.getTimeZone(id)
*/
public void setTimeZoneID(String timeZoneId)
{
setTimeZone(TimeZone.getTimeZone(timeZoneId));
}
/* ------------------------------------------------------------ */
private void setTzFormatString(final TimeZone tz )
{
int zIndex = _formatString.indexOf( "ZZZ" );
if( zIndex >= 0 )
{
@ -196,7 +120,7 @@ public class DateCache
sb.append( '-' );
}
int raw = tzOffset / (1000*60); // Convert to seconds
int raw = tzOffset / (1000*60); // Convert to seconds
int hr = raw / 60;
int min = raw % 60;
@ -213,8 +137,26 @@ public class DateCache
}
else
_tzFormatString=_formatString;
if( _locale != null )
{
_tzFormat=new SimpleDateFormat(_tzFormatString,_locale);
}
else
{
_tzFormat=new SimpleDateFormat(_tzFormatString);
}
_tzFormat.setTimeZone(tz);
_tick=null;
}
/* ------------------------------------------------------------ */
public TimeZone getTimeZone()
{
return _tzFormat.getTimeZone();
}
/* ------------------------------------------------------------ */
@ -243,6 +185,8 @@ public class DateCache
/* ------------------------------------------------------------ */
/** Format a date according to our stored formatter.
* If it happens to be in the same second as the last formatNow
* call, then the format is reused.
* @param inDate
* @return Formatted date
*/
@ -267,51 +211,58 @@ public class DateCache
}
/* ------------------------------------------------------------ */
public String now()
/** Format a date according to our stored formatter.
* The passed time is expected to be close to the current time, so it is
* compared to the last value passed and if it is within the same second,
* the format is reused. Otherwise a new cached format is created.
* @param now
* @return Formatted date
*/
public String formatNow(long now)
{
return _tick._string;
long seconds = now / 1000;
Tick tick=_tick;
// Is this the cached time
if (tick!=null && tick._seconds==seconds)
return tick._string;
return formatTick(now)._string;
}
/* ------------------------------------------------------------ */
protected void formatNow()
public String now()
{
return formatNow(System.currentTimeMillis());
}
/* ------------------------------------------------------------ */
public Tick tick()
{
return formatTick(System.currentTimeMillis());
}
/* ------------------------------------------------------------ */
protected Tick formatTick(long now)
{
long now = System.currentTimeMillis();
long seconds = now / 1000;
// Synchronize to protect _tzFormat
synchronized (this)
{
String s= _tzFormat.format(new Date(now));
_tick=new Tick(seconds,s);
// recheck the tick, to save multiple formats
if (_tick==null || _tick._seconds!=seconds)
{
String s= _tzFormat.format(new Date(now));
return _tick=new Tick(seconds,s);
}
return _tick;
}
}
/* ------------------------------------------------------------ */
/** Format to string buffer.
* @param inDate Date the format
* @param buffer StringBuilder
*/
public void format(long inDate, StringBuilder buffer)
{
buffer.append(format(inDate));
}
/* ------------------------------------------------------------ */
public String getFormatString()
{
return _formatString;
}
/* ------------------------------------------------------------ */
private volatile ByteBuffer _buffer;
private volatile Object _last;
public synchronized ByteBuffer formatBuffer(long date)
{
String d = format(date);
if (d==_last)
return _buffer;
_last=d;
_buffer=BufferUtil.toBuffer(d);
return _buffer;
}
}

View File

@ -548,7 +548,7 @@ public class StdErrLog extends AbstractLogger
{
long now = System.currentTimeMillis();
int ms=(int)(now%1000);
String d = _dateCache.now();
String d = _dateCache.formatNow(now);
tag(buffer,d,ms,level);
format(buffer,msg,args);
}

View File

@ -44,14 +44,13 @@ public class DateCacheTest
{
//@WAS: Test t = new Test("org.eclipse.jetty.util.DateCache");
// 012345678901234567890123456789
DateCache dc = new DateCache("EEE, dd MMM yyyy HH:mm:ss zzz ZZZ",Locale.US);
dc.setTimeZone(TimeZone.getTimeZone("GMT"));
DateCache dc = new DateCache("EEE, dd MMM yyyy HH:mm:ss zzz ZZZ",Locale.US,TimeZone.getTimeZone("GMT"));
Thread.sleep(2000);
long now=System.currentTimeMillis();
long end=now+3000;
String f=dc.format(now);
String f=dc.formatNow(now);
String last=f;
int hits=0;
@ -60,7 +59,7 @@ public class DateCacheTest
while (now<end)
{
last=f;
f=dc.format(now);
f=dc.formatNow(now);
// System.err.printf("%s %s%n",f,last==f);
if (last==f)
hits++;