Replace LinkedHashSet by ArrayList to avoid iterators.
Motivation: In a simple load test that creates and closes several 10k streams per second I have seen Iterator objects using roughly 1.6% of the total committed heap. Modifications: Use an ArrayList instead of a LinkedHashSet to store the connection listeners. That way we can iterate over the list without creating an iterator every time. Result: Zero Iterator allocations due to notifying connection listeners.
This commit is contained in:
parent
96cd447ce9
commit
5de91c0c7a
@ -43,7 +43,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -54,7 +54,11 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class DefaultHttp2Connection implements Http2Connection {
|
public class DefaultHttp2Connection implements Http2Connection {
|
||||||
|
|
||||||
private final Set<Listener> listeners = new HashSet<Listener>(4);
|
/**
|
||||||
|
* We chose a {@link List} over a {@link Set} to avoid allocating an {@link Iterator} objects when iterating over
|
||||||
|
* the listeners.
|
||||||
|
*/
|
||||||
|
private final List<Listener> listeners = new ArrayList<Listener>(4);
|
||||||
private final IntObjectMap<Http2Stream> streamMap = new IntObjectHashMap<Http2Stream>();
|
private final IntObjectMap<Http2Stream> streamMap = new IntObjectHashMap<Http2Stream>();
|
||||||
private final ConnectionStream connectionStream = new ConnectionStream();
|
private final ConnectionStream connectionStream = new ConnectionStream();
|
||||||
private final Set<Http2Stream> activeStreams = new LinkedHashSet<Http2Stream>();
|
private final Set<Http2Stream> activeStreams = new LinkedHashSet<Http2Stream>();
|
||||||
@ -161,8 +165,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
boolean alreadyNotified = goAwayReceived();
|
boolean alreadyNotified = goAwayReceived();
|
||||||
localEndpoint.lastKnownStream(lastKnownStream);
|
localEndpoint.lastKnownStream(lastKnownStream);
|
||||||
if (!alreadyNotified) {
|
if (!alreadyNotified) {
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onGoAwayReceived(lastKnownStream, errorCode, debugData);
|
listeners.get(i).onGoAwayReceived(lastKnownStream, errorCode, debugData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,8 +181,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
boolean alreadyNotified = goAwaySent();
|
boolean alreadyNotified = goAwaySent();
|
||||||
remoteEndpoint.lastKnownStream(lastKnownStream);
|
remoteEndpoint.lastKnownStream(lastKnownStream);
|
||||||
if (!alreadyNotified) {
|
if (!alreadyNotified) {
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onGoAwaySent(lastKnownStream, errorCode, debugData);
|
listeners.get(i).onGoAwaySent(lastKnownStream, errorCode, debugData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,8 +202,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
// Remove it from the map and priority tree.
|
// Remove it from the map and priority tree.
|
||||||
streamMap.remove(stream.id());
|
streamMap.remove(stream.id());
|
||||||
|
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onStreamRemoved(stream);
|
listeners.get(i).onStreamRemoved(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,8 +380,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
createdBy().numActiveStreams++;
|
createdBy().numActiveStreams++;
|
||||||
|
|
||||||
// Notify the listeners.
|
// Notify the listeners.
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onStreamActive(this);
|
listeners.get(i).onStreamActive(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -397,8 +401,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
createdBy().numActiveStreams--;
|
createdBy().numActiveStreams--;
|
||||||
|
|
||||||
// Notify the listeners.
|
// Notify the listeners.
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onStreamClosed(this);
|
listeners.get(i).onStreamClosed(this);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Mark this stream for removal.
|
// Mark this stream for removal.
|
||||||
@ -494,8 +498,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void notifyHalfClosed(Http2Stream stream) {
|
private void notifyHalfClosed(Http2Stream stream) {
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onStreamHalfClosed(stream);
|
listeners.get(i).onStreamHalfClosed(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,8 +529,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
}
|
}
|
||||||
final short oldWeight = this.weight;
|
final short oldWeight = this.weight;
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
for (Listener l : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
l.onWeightChanged(this, oldWeight);
|
listeners.get(i).onWeightChanged(this, oldWeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,15 +710,15 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
private void notifyParentChanged(List<ParentChangedEvent> events) {
|
private void notifyParentChanged(List<ParentChangedEvent> events) {
|
||||||
for (int i = 0; i < events.size(); ++i) {
|
for (int i = 0; i < events.size(); ++i) {
|
||||||
ParentChangedEvent event = events.get(i);
|
ParentChangedEvent event = events.get(i);
|
||||||
for (Listener l : listeners) {
|
for (int j = 0; j < listeners.size(); j++) {
|
||||||
event.notifyListener(l);
|
event.notifyListener(listeners.get(j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyParentChanging(Http2Stream stream, Http2Stream newParent) {
|
private void notifyParentChanging(Http2Stream stream, Http2Stream newParent) {
|
||||||
for (Listener l : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
l.onPriorityTreeParentChanging(stream, newParent);
|
listeners.get(i).onPriorityTreeParentChanging(stream, newParent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,8 +863,8 @@ public class DefaultHttp2Connection implements Http2Connection {
|
|||||||
connectionStream.takeChild(stream, false, events);
|
connectionStream.takeChild(stream, false, events);
|
||||||
|
|
||||||
// Notify the listeners of the event.
|
// Notify the listeners of the event.
|
||||||
for (Listener listener : listeners) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listener.onStreamAdded(stream);
|
listeners.get(i).onStreamAdded(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyParentChanged(events);
|
notifyParentChanged(events);
|
||||||
|
@ -229,12 +229,13 @@ public interface Http2Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a listener of stream life-cycle events. Adding the same listener multiple times has no effect.
|
* Adds a listener of stream life-cycle events.
|
||||||
*/
|
*/
|
||||||
void addListener(Listener listener);
|
void addListener(Listener listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a listener of stream life-cycle events.
|
* Removes a listener of stream life-cycle events. If the same listener was added multiple times
|
||||||
|
* then only the first occurence gets removed.
|
||||||
*/
|
*/
|
||||||
void removeListener(Listener listener);
|
void removeListener(Listener listener);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user