Skip to content

Commit 5ed4c8c

Browse files
committed
cache timers and current date to improve performance
1 parent 16d7a88 commit 5ed4c8c

File tree

5 files changed

+87
-14
lines changed

5 files changed

+87
-14
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package robaho.net.httpserver;
2+
3+
import java.time.Instant;
4+
import java.time.ZoneOffset;
5+
import java.time.format.TextStyle;
6+
import java.util.Locale;
7+
import java.util.TimerTask;
8+
9+
class ActivityTimer {
10+
private static volatile long now = System.currentTimeMillis();
11+
private static volatile String dateAndTime = formatDate();
12+
13+
private static String formatDate() {
14+
var now = Instant.now();
15+
var datetime = now.atOffset(ZoneOffset.UTC);
16+
StringBuilder sb = new StringBuilder(32);
17+
sb.append(datetime.getDayOfWeek().getDisplayName(TextStyle.SHORT,Locale.US));
18+
sb.append(", ");
19+
int day = datetime.getDayOfMonth();
20+
if(day<10) sb.append("0");
21+
sb.append(day);
22+
sb.append(" ");
23+
sb.append(datetime.getMonth().getDisplayName(TextStyle.SHORT,Locale.US));
24+
sb.append(" ");
25+
sb.append(datetime.getYear());
26+
sb.append(" ");
27+
int hour = datetime.getHour();
28+
if(hour<10) sb.append("0");
29+
sb.append(hour);
30+
sb.append(":");
31+
int minute = datetime.getMinute();
32+
if(minute<10) sb.append("0");
33+
sb.append(minute);
34+
sb.append(":");
35+
int second = datetime.getSecond();
36+
if(second<10) sb.append("0");
37+
sb.append(second);
38+
sb.append(" GMT");
39+
return sb.toString();
40+
}
41+
42+
public static long now() {
43+
return now;
44+
}
45+
/**
46+
* return the formatted current date and time suitable for use with the Date http header. this
47+
* is OK to cache since the resolution is only seconds, and we will update more often than that
48+
*/
49+
public static String dateAndTime() {
50+
return dateAndTime;
51+
}
52+
53+
static void updateNow() {
54+
now = System.currentTimeMillis();
55+
dateAndTime = formatDate();
56+
}
57+
58+
static TimerTask createTask() {
59+
return new TimerTask() {
60+
@Override
61+
public void run() {
62+
updateNow();
63+
}
64+
};
65+
}
66+
}

src/main/java/robaho/net/httpserver/ExchangeImpl.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@
2727

2828
import java.io.*;
2929
import java.net.*;
30+
3031
import javax.net.ssl.*;
32+
3133
import java.util.*;
3234
import java.lang.System.Logger;
3335
import java.lang.System.Logger.Level;
3436
import java.nio.charset.Charset;
3537
import java.nio.charset.StandardCharsets;
3638
import java.time.Instant;
3739
import java.time.ZoneId;
40+
import java.time.ZoneOffset;
3841
import java.time.format.DateTimeFormatter;
42+
import java.time.format.TextStyle;
3943
import java.util.stream.Stream;
44+
4045
import com.sun.net.httpserver.*;
4146

4247
import robaho.net.httpserver.websockets.WebSocketHandler;
@@ -216,6 +221,8 @@ PlaceholderOutputStream getPlaceholderResponseBody() {
216221
return uos_orig;
217222
}
218223

224+
// hard-coded formatting for Date header, rather than using slower DateFormatter
225+
219226
public void sendResponseHeaders(int rCode, long contentLen)
220227
throws IOException {
221228
final Logger logger = getServerImpl().getLogger();
@@ -229,7 +236,7 @@ public void sendResponseHeaders(int rCode, long contentLen)
229236
ros.write(statusLine.getBytes(ISO_CHARSET));
230237
boolean noContentToSend = false; // assume there is content
231238
boolean noContentLengthHeader = false; // must not send Content-length is set
232-
rspHdrs.set("Date", FORMATTER.format(Instant.now()));
239+
rspHdrs.set("Date", ActivityTimer.dateAndTime());
233240

234241
if (this.getAttribute(Attributes.SOCKET_WRITE_BUFFER) != null) {
235242
int bufferSize = (Integer) this.getAttribute(Attributes.SOCKET_WRITE_BUFFER);

src/main/java/robaho/net/httpserver/HttpConnection.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
package robaho.net.httpserver;
2727

28-
import java.io.BufferedOutputStream;
2928
import java.io.FilterInputStream;
3029
import java.io.FilterOutputStream;
3130
import java.io.IOException;
@@ -144,15 +143,15 @@ private class ActivityTimerInputStream extends FilterInputStream {
144143

145144
private ActivityTimerInputStream(InputStream inputStream) {
146145
super(inputStream);
147-
lastActivityTime = System.currentTimeMillis();
146+
lastActivityTime = ActivityTimer.now();
148147
}
149148

150149
@Override
151150
public int read() throws IOException {
152151
try {
153152
return super.read();
154153
} finally {
155-
lastActivityTime = System.currentTimeMillis();
154+
lastActivityTime = ActivityTimer.now();
156155
}
157156
}
158157

@@ -161,7 +160,7 @@ public long skip(long n) throws IOException {
161160
try {
162161
return super.skip(n);
163162
} finally {
164-
lastActivityTime = System.currentTimeMillis();
163+
lastActivityTime = ActivityTimer.now();
165164
}
166165
}
167166

@@ -170,7 +169,7 @@ public int read(byte b[], int off, int len) throws IOException {
170169
try {
171170
return super.read(b, off, len);
172171
} finally {
173-
lastActivityTime = System.currentTimeMillis();
172+
lastActivityTime = ActivityTimer.now();
174173
}
175174
}
176175

@@ -180,14 +179,14 @@ private class ActivityTimerOutputStream extends FilterOutputStream {
180179

181180
private ActivityTimerOutputStream(OutputStream outputStream) {
182181
super(outputStream);
183-
lastActivityTime = System.currentTimeMillis();
182+
lastActivityTime = ActivityTimer.now();
184183
}
185184
@Override
186185
public void write(int b) throws IOException {
187186
try {
188187
out.write(b);
189188
} finally {
190-
lastActivityTime = System.currentTimeMillis();
189+
lastActivityTime = ActivityTimer.now();
191190
}
192191
}
193192

@@ -196,7 +195,7 @@ public void write(byte b[], int off, int len) throws IOException {
196195
try {
197196
out.write(b, off, len);
198197
} finally {
199-
lastActivityTime = System.currentTimeMillis();
198+
lastActivityTime = ActivityTimer.now();
200199
}
201200
}
202201
}

src/main/java/robaho/net/httpserver/ServerImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ public boolean isLoggable(LogRecord record) {
150150
dispatcher = new Dispatcher();
151151
timer = new Timer("connection-cleaner", true);
152152
timer.schedule(new ConnectionCleanerTask(), IDLE_TIMER_TASK_SCHEDULE, IDLE_TIMER_TASK_SCHEDULE);
153+
timer.schedule(ActivityTimer.createTask(),750);
153154
logger.log(Level.DEBUG, "HttpServer created " + protocol + " " + addr);
154155
if(Boolean.getBoolean("robaho.net.httpserver.EnableStats")) {
155156
createContext("/__stats",new StatsHandler());
@@ -736,18 +737,18 @@ class ConnectionCleanerTask extends TimerTask {
736737

737738
@Override
738739
public void run() {
739-
final long currentTime = System.currentTimeMillis();
740+
long now = ActivityTimer.now();
740741

741742
for (var c : allConnections) {
742-
if (currentTime - c.lastActivityTime >= IDLE_INTERVAL && !c.inRequest) {
743+
if (now- c.lastActivityTime >= IDLE_INTERVAL && !c.inRequest) {
743744
logger.log(Level.DEBUG, "closing idle connection");
744745
idleCloseCount.incrementAndGet();
745746
closeConnection(c);
746747
// idle.add(c);
747-
} else if (c.noActivity && (currentTime - c.lastActivityTime >= NEWLY_ACCEPTED_CONN_IDLE_INTERVAL)) {
748+
} else if (c.noActivity && (now - c.lastActivityTime >= NEWLY_ACCEPTED_CONN_IDLE_INTERVAL)) {
748749
logger.log(Level.WARNING, "closing newly accepted idle connection");
749750
closeConnection(c);
750-
} else if (MAX_REQ_TIME != -1 && c.inRequest && (currentTime - c.lastActivityTime >= MAX_REQ_TIME)) {
751+
} else if (MAX_REQ_TIME != -1 && c.inRequest && (now - c.lastActivityTime >= MAX_REQ_TIME)) {
751752
logger.log(Level.WARNING, "closing connection due to request processing time");
752753
closeConnection(c);
753754
}

src/test/java/DateFormatterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public void testDateFormat() throws Exception {
103103
if (date.equals("null"))
104104
fail("Date not present");
105105
Matcher matcher = pattern.matcher(date);
106-
assertTrue(matcher.matches());
106+
assertTrue(matcher.matches(),date);
107107
}
108108
}
109109

0 commit comments

Comments
 (0)