Skip to content

Commit 5f7089e

Browse files
committed
Adding per-host statistics
1 parent 552e4cd commit 5f7089e

File tree

7 files changed

+202
-58
lines changed

7 files changed

+202
-58
lines changed

client/src/main/java/org/asynchttpclient/ClientStats.java

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,63 +13,80 @@
1313
*/
1414
package org.asynchttpclient;
1515

16+
import java.util.Collections;
17+
import java.util.Map;
1618
import java.util.Objects;
1719

1820
/**
19-
* A record class representing the state of an (@link org.asynchttpclient.AsyncHttpClient)
21+
* A record class representing the state of an (@link org.asynchttpclient.AsyncHttpClient).
2022
*/
2123
public class ClientStats {
2224

23-
private final long activeConnectionCount;
24-
private final long idleConnectionCount;
25+
private final Map<String, HostStats> statsPerHost;
2526

26-
public ClientStats(long activeConnectionCount,
27-
long idleConnectionCount) {
28-
this.activeConnectionCount = activeConnectionCount;
29-
this.idleConnectionCount = idleConnectionCount;
27+
public ClientStats(Map<String, HostStats> statsPerHost) {
28+
this.statsPerHost = Collections.unmodifiableMap(statsPerHost);
3029
}
3130

3231
/**
33-
* @return The sum of {@link #getActiveConnectionCount()} and {@link #getIdleConnectionCount()},
32+
* @return A map from hostname to statistics on that host's connections.
33+
* The returned map is an {@link java.util.Collections.UnmodifiableMap}.
34+
*/
35+
public Map<String, HostStats> getStatsPerHost() {
36+
return statsPerHost;
37+
}
38+
39+
/**
40+
* @return The sum of {@link #getTotalActiveConnectionCount()} and {@link #getTotalIdleConnectionCount()},
3441
* a long representing the total number of connections in the connection pool.
3542
*/
3643
public long getTotalConnectionCount() {
37-
return activeConnectionCount + idleConnectionCount;
44+
return statsPerHost
45+
.values()
46+
.stream()
47+
.mapToLong(HostStats::getHostConnectionCount)
48+
.sum();
3849
}
3950

4051
/**
41-
* @return A long representing the number of active connection in the connection pool.
52+
* @return A long representing the number of active connections in the connection pool.
4253
*/
43-
public long getActiveConnectionCount() {
44-
return activeConnectionCount;
54+
public long getTotalActiveConnectionCount() {
55+
return statsPerHost
56+
.values()
57+
.stream()
58+
.mapToLong(HostStats::getHostActiveConnectionCount)
59+
.sum();
4560
}
4661

4762
/**
48-
*
4963
* @return A long representing the number of idle connections in the connection pool.
5064
*/
51-
public long getIdleConnectionCount() {
52-
return idleConnectionCount;
65+
public long getTotalIdleConnectionCount() {
66+
return statsPerHost
67+
.values()
68+
.stream()
69+
.mapToLong(HostStats::getHostIdleConnectionCount)
70+
.sum();
5371
}
5472

5573
@Override
5674
public String toString() {
5775
return "There are " + getTotalConnectionCount() +
58-
" total connections, " + getActiveConnectionCount() +
59-
" are active and " + getIdleConnectionCount() + " are idle.";
76+
" total connections, " + getTotalActiveConnectionCount() +
77+
" are active and " + getTotalIdleConnectionCount() + " are idle.";
6078
}
6179

6280
@Override
6381
public boolean equals(final Object o) {
6482
if (this == o) return true;
6583
if (o == null || getClass() != o.getClass()) return false;
6684
final ClientStats that = (ClientStats) o;
67-
return activeConnectionCount == that.activeConnectionCount &&
68-
idleConnectionCount == that.idleConnectionCount;
85+
return Objects.equals(statsPerHost, that.statsPerHost);
6986
}
7087

7188
@Override
7289
public int hashCode() {
73-
return Objects.hash(activeConnectionCount, idleConnectionCount);
90+
return Objects.hashCode(statsPerHost);
7491
}
7592
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
14+
package org.asynchttpclient;
15+
16+
import java.util.Objects;
17+
18+
/**
19+
* A record class representing the status of connections to some host.
20+
*/
21+
public class HostStats {
22+
23+
private final long activeConnectionCount;
24+
private final long idleConnectionCount;
25+
26+
public HostStats(long activeConnectionCount,
27+
long idleConnectionCount) {
28+
this.activeConnectionCount = activeConnectionCount;
29+
this.idleConnectionCount = idleConnectionCount;
30+
}
31+
32+
/**
33+
* @return The sum of {@link #getHostActiveConnectionCount()} and {@link #getHostIdleConnectionCount()},
34+
* a long representing the total number of connections to this host.
35+
*/
36+
public long getHostConnectionCount() {
37+
return activeConnectionCount + idleConnectionCount;
38+
}
39+
40+
/**
41+
* @return A long representing the number of active connections to the host.
42+
*/
43+
public long getHostActiveConnectionCount() {
44+
return activeConnectionCount;
45+
}
46+
47+
/**
48+
* @return A long representing the number of idle connections in the connection pool.
49+
*/
50+
public long getHostIdleConnectionCount() {
51+
return idleConnectionCount;
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "There are " + getHostConnectionCount() +
57+
" total connections, " + getHostActiveConnectionCount() +
58+
" are active and " + getHostIdleConnectionCount() + " are idle.";
59+
}
60+
61+
@Override
62+
public boolean equals(final Object o) {
63+
if (this == o) return true;
64+
if (o == null || getClass() != o.getClass()) return false;
65+
final HostStats hostStats = (HostStats) o;
66+
return activeConnectionCount == hostStats.activeConnectionCount &&
67+
idleConnectionCount == hostStats.idleConnectionCount;
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return Objects.hash(activeConnectionCount, idleConnectionCount);
73+
}
74+
}

client/src/main/java/org/asynchttpclient/channel/ChannelPool.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
*/
1414
package org.asynchttpclient.channel;
1515

16+
import java.util.Map;
17+
1618
import io.netty.channel.Channel;
1719

1820
public interface ChannelPool {
@@ -72,7 +74,7 @@ public interface ChannelPool {
7274
void flushPartitions(ChannelPoolPartitionSelector selector);
7375

7476
/**
75-
* @return The number of idle channels.
77+
* @return The number of idle channels per host.
7678
*/
77-
long getIdleChannelCount();
79+
Map<String, Long> getIdleChannelCountPerHost();
7880
}

client/src/main/java/org/asynchttpclient/channel/NoopChannelPool.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
*/
1414
package org.asynchttpclient.channel;
1515

16+
import java.util.Collections;
17+
import java.util.Map;
18+
1619
import io.netty.channel.Channel;
1720

1821
public enum NoopChannelPool implements ChannelPool {
@@ -52,7 +55,7 @@ public void flushPartitions(ChannelPoolPartitionSelector selector) {
5255
}
5356

5457
@Override
55-
public long getIdleChannelCount() {
56-
return 0;
58+
public Map<String, Long> getIdleChannelCountPerHost() {
59+
return Collections.emptyMap();
5760
}
5861
}

client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,23 @@
4040
import io.netty.util.concurrent.GlobalEventExecutor;
4141

4242
import java.io.IOException;
43+
import java.net.InetSocketAddress;
44+
import java.util.Map;
4345
import java.util.Map.Entry;
46+
import java.util.Optional;
47+
import java.util.OptionalLong;
4448
import java.util.concurrent.ConcurrentHashMap;
4549
import java.util.concurrent.Semaphore;
4650
import java.util.concurrent.ThreadFactory;
4751
import java.util.concurrent.TimeUnit;
52+
import java.util.function.Function;
53+
import java.util.stream.Collectors;
54+
import java.util.stream.Stream;
4855

4956
import javax.net.ssl.SSLEngine;
5057
import javax.net.ssl.SSLException;
5158

52-
import org.asynchttpclient.AsyncHandler;
53-
import org.asynchttpclient.AsyncHttpClientConfig;
54-
import org.asynchttpclient.ClientStats;
55-
import org.asynchttpclient.SslEngineFactory;
59+
import org.asynchttpclient.*;
5660
import org.asynchttpclient.channel.ChannelPool;
5761
import org.asynchttpclient.channel.ChannelPoolPartitioning;
5862
import org.asynchttpclient.channel.NoopChannelPool;
@@ -491,9 +495,26 @@ public EventLoopGroup getEventLoopGroup() {
491495
}
492496

493497
public ClientStats getClientStats() {
494-
final long totalConnectionCount = openChannels.size();
495-
final long idleConnectionCount = channelPool.getIdleChannelCount();
496-
final long activeConnectionCount = totalConnectionCount - idleConnectionCount;
497-
return new ClientStats(activeConnectionCount, idleConnectionCount);
498+
final Map<String, Long> totalConnectionsPerHost = openChannels
499+
.stream()
500+
.map(Channel::remoteAddress)
501+
.filter(a -> a.getClass() == InetSocketAddress.class)
502+
.map(a -> (InetSocketAddress) a)
503+
.map(InetSocketAddress::getHostName)
504+
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
505+
final Map<String, Long> idleConnectionsPerHost = channelPool.getIdleChannelCountPerHost();
506+
final Map<String, HostStats> statsPerHost = totalConnectionsPerHost
507+
.entrySet()
508+
.stream()
509+
.collect(Collectors.toMap(
510+
Entry::getKey,
511+
entry -> {
512+
final long totalConnectionCount = entry.getValue();
513+
final long idleConnectionCount = idleConnectionsPerHost.getOrDefault(entry.getKey(), 0L);
514+
final long activeConnectionCount = totalConnectionCount - idleConnectionCount;
515+
return new HostStats(activeConnectionCount, idleConnectionCount);
516+
}
517+
));
518+
return new ClientStats(statsPerHost);
498519
}
499520
}

client/src/main/java/org/asynchttpclient/netty/channel/DefaultChannelPool.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
import io.netty.util.Timer;
2222
import io.netty.util.TimerTask;
2323

24+
import java.net.InetSocketAddress;
2425
import java.util.*;
2526
import java.util.concurrent.ConcurrentHashMap;
2627
import java.util.concurrent.ConcurrentLinkedDeque;
2728
import java.util.concurrent.TimeUnit;
2829
import java.util.concurrent.atomic.AtomicBoolean;
30+
import java.util.function.Function;
31+
import java.util.stream.Collectors;
2932

3033
import org.asynchttpclient.AsyncHttpClientConfig;
3134
import org.asynchttpclient.channel.ChannelPool;
@@ -120,6 +123,10 @@ public boolean takeOwnership() {
120123
return owned.compareAndSet(false, true);
121124
}
122125

126+
public Channel getChannel() {
127+
return channel;
128+
}
129+
123130
@Override
124131
// only depends on channel
125132
public boolean equals(Object o) {
@@ -357,8 +364,16 @@ public void flushPartitions(ChannelPoolPartitionSelector selector) {
357364
}
358365

359366
@Override
360-
public long getIdleChannelCount() {
361-
return partitions.values().stream().mapToLong(ConcurrentLinkedDeque::size).sum();
367+
public Map<String, Long> getIdleChannelCountPerHost() {
368+
return partitions
369+
.values()
370+
.stream()
371+
.flatMap(ConcurrentLinkedDeque::stream)
372+
.map(idle -> idle.getChannel().remoteAddress())
373+
.filter(a -> a.getClass() == InetSocketAddress.class)
374+
.map(a -> (InetSocketAddress) a)
375+
.map(InetSocketAddress::getHostName)
376+
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
362377
}
363378

364379
public enum PoolLeaseStrategy {

0 commit comments

Comments
 (0)