Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 7c29f5c

Browse files
pavelbucekGerrit Code Review
authored andcommitted
Merge "J-527: All Statistics objects are verified to be immutable. If required, builders are thread-safe. Deprecated snapshot() methods. Fixed SlidingWindowTimeReservoir which was unable to calculate metrics correctly for updates with time older than the time of the sliding window creation (as a result, after the application startup, first requests weren't added to the calculation due to lazy creation of SlidingWindowTimeReservoir). Extended tests."
2 parents 93e54fe + 20d861c commit 7c29f5c

17 files changed

+410
-133
lines changed

core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/ExceptionMapperStatisticsImpl.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package org.glassfish.jersey.server.internal.monitoring;
4242

4343
import java.util.Collections;
44+
import java.util.HashMap;
4445
import java.util.Map;
4546

4647
import org.glassfish.jersey.server.monitoring.ExceptionMapperStatistics;
@@ -56,10 +57,12 @@ final class ExceptionMapperStatisticsImpl implements ExceptionMapperStatistics {
5657

5758
/**
5859
* Builder of exception mapper statistics.
60+
* <p/>
61+
* This builder does not need to be threadsafe since it's called only from the jersey-background-task-scheduler.
5962
*/
6063
static class Builder {
6164

62-
private Map<Class<?>, Long> exceptionMapperExecutionCount = Maps.newHashMap();
65+
private Map<Class<?>, Long> exceptionMapperExecutionCountMap = Maps.newHashMap();
6366
private long successfulMappings;
6467
private long unsuccessfulMappings;
6568
private long totalMappings;
@@ -92,9 +95,9 @@ void addMapping(final boolean success, final int count) {
9295
void addExceptionMapperExecution(final Class<?> mapper, final int count) {
9396
cached = null;
9497

95-
Long cnt = exceptionMapperExecutionCount.get(mapper);
98+
Long cnt = exceptionMapperExecutionCountMap.get(mapper);
9699
cnt = cnt == null ? count : cnt + count;
97-
exceptionMapperExecutionCount.put(mapper, cnt);
100+
exceptionMapperExecutionCountMap.put(mapper, cnt);
98101
}
99102

100103
/**
@@ -104,7 +107,7 @@ void addExceptionMapperExecution(final Class<?> mapper, final int count) {
104107
*/
105108
public ExceptionMapperStatisticsImpl build() {
106109
if (cached == null) {
107-
cached = new ExceptionMapperStatisticsImpl(Collections.unmodifiableMap(exceptionMapperExecutionCount),
110+
cached = new ExceptionMapperStatisticsImpl(new HashMap<>(this.exceptionMapperExecutionCountMap),
108111
successfulMappings, unsuccessfulMappings, totalMappings);
109112
}
110113

@@ -119,7 +122,7 @@ public ExceptionMapperStatisticsImpl build() {
119122

120123
private ExceptionMapperStatisticsImpl(final Map<Class<?>, Long> exceptionMapperExecutionCount, final long successfulMappings,
121124
final long unsuccessfulMappings, final long totalMappings) {
122-
this.exceptionMapperExecutionCount = exceptionMapperExecutionCount;
125+
this.exceptionMapperExecutionCount = Collections.unmodifiableMap(exceptionMapperExecutionCount);
123126
this.successfulMappings = successfulMappings;
124127
this.unsuccessfulMappings = unsuccessfulMappings;
125128
this.totalMappings = totalMappings;

core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/ExecutionStatisticsImpl.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,44 +52,51 @@
5252
import jersey.repackaged.com.google.common.collect.Maps;
5353

5454
/**
55-
* Execution statistics.
55+
* Immutable Execution statistics.
5656
*
5757
* @author Miroslav Fuksa
58+
* @author Stepan Vavra (stepan.vavra at oracle.com)
5859
*/
5960
final class ExecutionStatisticsImpl implements ExecutionStatistics {
6061

6162
/**
6263
* Builder of execution statistics.
64+
* <p/>
65+
* Must be thread-safe.
6366
*/
6467
static class Builder {
6568

66-
private long lastStartTime;
69+
private volatile long lastStartTime;
6770
private final Map<Long, TimeWindowStatisticsImpl.Builder> intervalStatistics;
6871

6972
/**
7073
* Create a new builder.
7174
*/
7275
public Builder() {
73-
this.intervalStatistics = new HashMap<>(6);
74-
addInterval(0, TimeUnit.MILLISECONDS);
75-
addInterval(1, TimeUnit.SECONDS);
76-
addInterval(15, TimeUnit.SECONDS);
77-
addInterval(1, TimeUnit.MINUTES);
78-
addInterval(15, TimeUnit.MINUTES);
79-
addInterval(1, TimeUnit.HOURS);
76+
// create unmodifiable map to ensure that an iteration in the build() won't have multi-threading issues
77+
this.intervalStatistics = Collections.unmodifiableMap(new HashMap<Long, TimeWindowStatisticsImpl.Builder>(6) {
78+
{
79+
addInterval(0, TimeUnit.MILLISECONDS, this);
80+
addInterval(1, TimeUnit.SECONDS, this);
81+
addInterval(15, TimeUnit.SECONDS, this);
82+
addInterval(1, TimeUnit.MINUTES, this);
83+
addInterval(15, TimeUnit.MINUTES, this);
84+
addInterval(1, TimeUnit.HOURS, this);
85+
}
86+
});
8087
}
8188

82-
private void addInterval(final long interval, final TimeUnit timeUnit) {
89+
private void addInterval(final long interval, final TimeUnit timeUnit, final Map map) {
8390
final long intervalInMillis = timeUnit.toMillis(interval);
84-
intervalStatistics.put(intervalInMillis, new TimeWindowStatisticsImpl.Builder(intervalInMillis,
91+
map.put(intervalInMillis, new TimeWindowStatisticsImpl.Builder(intervalInMillis,
8592
TimeUnit.MILLISECONDS));
8693
}
8794

8895
/**
8996
* Add execution of a target.
9097
*
9198
* @param startTime (Unix timestamp format)
92-
* @param duration Duration of target execution in milliseconds.
99+
* @param duration Duration of target execution in milliseconds.
93100
*/
94101
void addExecution(final long startTime, final long duration) {
95102
for (final TimeWindowStatisticsImpl.Builder statBuilder : intervalStatistics.values()) {
@@ -112,18 +119,18 @@ public ExecutionStatisticsImpl build() {
112119

113120
// cache when request rate is 0
114121

115-
return new ExecutionStatisticsImpl(lastStartTime, Collections.unmodifiableMap(newIntervalStatistics));
122+
return new ExecutionStatisticsImpl(lastStartTime, newIntervalStatistics);
116123
}
117124
}
118125

119126
static final ExecutionStatistics EMPTY = new Builder().build();
120127

121-
private final Date lastStartTime;
128+
private final long lastStartTime;
122129
private final Map<Long, TimeWindowStatistics> timeWindowStatistics;
123130

124131
@Override
125132
public Date getLastStartTime() {
126-
return lastStartTime;
133+
return new Date(lastStartTime);
127134
}
128135

129136
@Override
@@ -133,13 +140,13 @@ public Map<Long, TimeWindowStatistics> getTimeWindowStatistics() {
133140

134141
@Override
135142
public ExecutionStatistics snapshot() {
136-
// snapshot functionality not yet implemented
143+
// this object is immutable (TimeWindowStatistics are immutable as well)
137144
return this;
138145
}
139146

140147
private ExecutionStatisticsImpl(final long lastStartTime, final Map<Long, TimeWindowStatistics> timeWindowStatistics) {
141-
this.lastStartTime = new Date(lastStartTime);
142-
this.timeWindowStatistics = timeWindowStatistics;
148+
this.lastStartTime = lastStartTime;
149+
this.timeWindowStatistics = Collections.unmodifiableMap(timeWindowStatistics);
143150
}
144151

145152
}

core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringStatisticsImpl.java

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,33 @@
5959

6060
/**
6161
* Monitoring statistics implementation.
62+
* <p/>
63+
* This object is loosely immutable (i.e., {@link #getResourceClassStatistics()} and {@link #getUriStatistics()} gets updated on
64+
* access). As a result, it is unnecessary to call {@link #snapshot()}.
6265
*
6366
* @author Miroslav Fuksa
6467
*/
6568
final class MonitoringStatisticsImpl implements MonitoringStatistics {
6669

6770
/**
6871
* Builder of monitoring statistics.
72+
* <p/>
73+
* This builder does not need to be threadsafe as it's only accessed by jersey-background-task-scheduler. However, {@link
74+
* #BUILDING_FUNCTION} is triggered when it is accessed (e.g., by servlet-container thread-pool threads) which adds threadsafe
75+
* constraint on some of the sub-builders.
76+
* <p/>
77+
* Sub-Builders that require thread-safety
78+
* <pre><ul>
79+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.ExecutionStatisticsImpl.Builder}</li>
80+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.ResourceStatisticsImpl.Builder}</li>
81+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.ResourceMethodStatisticsImpl.Builder}</li>
82+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.TimeWindowStatisticsImpl.Builder}</li>
83+
* </ul>
84+
* The rest does not need to be thread-safe
85+
* <ul>
86+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.ExceptionMapperStatisticsImpl.Builder}</li>
87+
* <li>{@link org.glassfish.jersey.server.internal.monitoring.ResponseStatisticsImpl.Builder}</li>
88+
* </ul></pre>
6989
*/
7090
static class Builder {
7191

@@ -90,7 +110,7 @@ public int compare(final Class<?> o1, final Class<?> o2) {
90110
}
91111
});
92112

93-
private ExecutionStatisticsImpl.Builder requestStatisticsBuilder;
113+
private ExecutionStatisticsImpl.Builder executionStatisticsBuilder;
94114

95115
/**
96116
* Create a new builder.
@@ -102,6 +122,7 @@ public int compare(final Class<?> o1, final Class<?> o2) {
102122

103123
/**
104124
* Create a new builder and initialize it from resource model.
125+
*
105126
* @param resourceModel resource model.
106127
*/
107128
Builder(final ResourceModel resourceModel) {
@@ -143,6 +164,7 @@ private ResourceStatisticsImpl.Builder getOrCreateResourceBuilder(final Resource
143164

144165
/**
145166
* Get the exception mapper statistics builder.
167+
*
146168
* @return Builder of internal exception mapper statistics.
147169
*/
148170
ExceptionMapperStatisticsImpl.Builder getExceptionMapperStatisticsBuilder() {
@@ -153,26 +175,25 @@ ExceptionMapperStatisticsImpl.Builder getExceptionMapperStatisticsBuilder() {
153175
* Add global request execution.
154176
*
155177
* @param startTime time of the execution.
156-
* @param duration duration of the execution.
178+
* @param duration duration of the execution.
157179
*/
158180
void addRequestExecution(final long startTime, final long duration) {
159-
if (requestStatisticsBuilder == null) {
160-
requestStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
181+
if (executionStatisticsBuilder == null) {
182+
executionStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
161183
}
162-
requestStatisticsBuilder.addExecution(startTime, duration);
184+
executionStatisticsBuilder.addExecution(startTime, duration);
163185
}
164186

165187
/**
166188
* Add execution of a resource method.
167189
*
168-
* @param uri String uri which was executed.
169-
* @param resourceMethod Resource method.
170-
* @param methodTime Time spent on execution of resource method itself (Unix timestamp format).
171-
* @param methodDuration Time of execution of the resource method.
172-
* @param requestTime Time of whole request processing (from receiving
173-
* the request until writing the response). (Unix timestamp format)
174-
* @param requestDuration Time when the request matching to the executed resource method has been received
175-
* by Jersey.
190+
* @param uri String uri which was executed.
191+
* @param resourceMethod Resource method.
192+
* @param methodTime Time spent on execution of resource method itself (Unix timestamp format).
193+
* @param methodDuration Time of execution of the resource method.
194+
* @param requestTime Time of whole request processing (from receiving the request until writing the response). (Unix
195+
* timestamp format)
196+
* @param requestDuration Time when the request matching to the executed resource method has been received by Jersey.
176197
*/
177198
void addExecution(final String uri, final ResourceMethod resourceMethod,
178199
final long methodTime, final long methodDuration,
@@ -194,18 +215,18 @@ void addExecution(final String uri, final ResourceMethod resourceMethod,
194215
.addResourceMethodExecution(methodTime, methodDuration, requestTime, requestDuration);
195216
}
196217

197-
198218
/**
199219
* Add a response status code produces by Jersey.
220+
*
200221
* @param responseCode Response status code.
201222
*/
202223
void addResponseCode(final int responseCode) {
203224
responseStatisticsBuilder.addResponseCode(responseCode);
204225
}
205226

206-
207227
/**
208228
* Build a new instance of monitoring statistics.
229+
*
209230
* @return New instance of {@code MonitoringStatisticsImpl}.
210231
*/
211232
MonitoringStatisticsImpl build() {
@@ -214,8 +235,8 @@ MonitoringStatisticsImpl build() {
214235
final Map<Class<?>, ResourceStatistics> classStats = Collections.unmodifiableMap(
215236
Maps.transformValues(resourceClassStatistics, BUILDING_FUNCTION));
216237

217-
final ExecutionStatistics requestStats = requestStatisticsBuilder == null
218-
? ExecutionStatisticsImpl.EMPTY : requestStatisticsBuilder.build();
238+
final ExecutionStatistics requestStats = executionStatisticsBuilder == null
239+
? ExecutionStatisticsImpl.EMPTY : executionStatisticsBuilder.build();
219240

220241
return new MonitoringStatisticsImpl(
221242
uriStats, classStats, requestStats,
@@ -230,7 +251,6 @@ MonitoringStatisticsImpl build() {
230251
private final Map<String, ResourceStatistics> uriStatistics;
231252
private final Map<Class<?>, ResourceStatistics> resourceClassStatistics;
232253

233-
234254
private MonitoringStatisticsImpl(final Map<String, ResourceStatistics> uriStatistics,
235255
final Map<Class<?>, ResourceStatistics> resourceClassStatistics,
236256
final ExecutionStatistics requestStatistics,
@@ -243,24 +263,31 @@ private MonitoringStatisticsImpl(final Map<String, ResourceStatistics> uriStatis
243263
this.exceptionMapperStatistics = exceptionMapperStatistics;
244264
}
245265

246-
247266
@Override
248267
public ExecutionStatistics getRequestStatistics() {
249268
return requestStatistics;
250269
}
251270

252-
253271
@Override
254272
public ResponseStatistics getResponseStatistics() {
255273
return responseStatistics;
256274
}
257275

258-
276+
/**
277+
* Refreshed (re-built) on every access. (uses {@link Maps#transformValues(Map, Function)})
278+
*
279+
* @return resource statistics
280+
*/
259281
@Override
260282
public Map<String, ResourceStatistics> getUriStatistics() {
261283
return uriStatistics;
262284
}
263285

286+
/**
287+
* Refreshed (re-built) on every access. (uses {@link Maps#transformValues(Map, Function)})
288+
*
289+
* @return resource statistics
290+
*/
264291
@Override
265292
public Map<Class<?>, ResourceStatistics> getResourceClassStatistics() {
266293
return resourceClassStatistics;
@@ -273,7 +300,8 @@ public ExceptionMapperStatistics getExceptionMapperStatistics() {
273300

274301
@Override
275302
public MonitoringStatistics snapshot() {
276-
// snapshot functionality not yet implemented
303+
// snapshot is not needed, this object is loosely immutable (see javadoc of Maps getters)
304+
// all the other Statistics objects are immutable
277305
return this;
278306
}
279307
}

0 commit comments

Comments
 (0)