420034 Removed threads/timers from Date caching
This commit is contained in:
parent
ebf11ebfb8
commit
d5f83a8159
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Reference in New Issue