2 * Copyright 2008-2011 LinkedIn, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
17 package voldemort
.store
.stats
;
19 import java
.util
.Iterator
;
20 import java
.util
.concurrent
.ConcurrentHashMap
;
21 import java
.util
.concurrent
.ConcurrentMap
;
22 import java
.util
.concurrent
.atomic
.AtomicInteger
;
23 import java
.util
.concurrent
.atomic
.AtomicLong
;
25 import voldemort
.store
.socket
.SocketDestination
;
26 import voldemort
.store
.socket
.clientrequest
.ClientRequestExecutor
;
27 import voldemort
.utils
.JmxUtils
;
28 import voldemort
.utils
.pool
.KeyedResourcePool
;
31 * Some convenient statistics to track about the client requests
35 public class ClientSocketStats
{
37 private final ClientSocketStats parent
;
38 private final ConcurrentMap
<SocketDestination
, ClientSocketStats
> statsMap
;
39 private final SocketDestination destination
;
40 private final KeyedResourcePool
<SocketDestination
, ClientRequestExecutor
> pool
;
42 private final AtomicInteger monitoringInterval
= new AtomicInteger(10000);
43 private final Histogram checkoutTimeUsHistogram
= new Histogram(20000, 100);
44 private final AtomicLong totalCheckoutTimeUs
= new AtomicLong(0);
45 private final AtomicLong avgCheckoutTimeUs
= new AtomicLong(0);
46 private final AtomicInteger connectionsCreated
= new AtomicInteger(0);
47 private final AtomicInteger connectionsDestroyed
= new AtomicInteger(0);
48 private final AtomicInteger connectionsCheckedout
= new AtomicInteger(0);
49 private boolean jmxEnable
= false;
51 // private final AtomicInteger connectionsCheckedin = new AtomicInteger(0);
54 * To construct a per node stats object
56 * @param parent An optional parent stats object that will maintain
57 * aggregate data across many sockets
58 * @param destination The destination object that defines the node
59 * @param pool The socket pool that will give out connection information
61 public ClientSocketStats(ClientSocketStats parent
,
62 SocketDestination destination
,
63 KeyedResourcePool
<SocketDestination
, ClientRequestExecutor
> pool
) {
66 this.destination
= destination
;
71 * Construction of a new aggregate stats object
73 * @param pool The socket pool that will give out connection information
75 public ClientSocketStats(KeyedResourcePool
<SocketDestination
, ClientRequestExecutor
> pool
) {
77 this.statsMap
= new ConcurrentHashMap
<SocketDestination
, ClientSocketStats
>();
78 this.destination
= null;
82 /* get per node stats, create one if not exist */
83 private ClientSocketStats
getOrCreateNodeStats(SocketDestination destination
) {
84 if(destination
== null) {
87 ClientSocketStats stats
= statsMap
.get(destination
);
89 stats
= new ClientSocketStats(this, destination
, pool
);
90 statsMap
.putIfAbsent(destination
, stats
);
91 stats
= statsMap
.get(destination
);
93 JmxUtils
.registerMbean(new ClientSocketStatsJmx(stats
),
94 JmxUtils
.createObjectName("voldemort.store.socket.clientrequest",
96 + destination
.toString()
105 * Record the checkout wait time in us
107 * @param dest Destination of the socket to checkout. Will actually record
108 * if null. Otherwise will call this on self and corresponding child
109 * with this param null.
110 * @param checkoutTimeUs The number of us to wait before getting a socket
112 public void recordCheckoutTimeUs(SocketDestination dest
, long checkoutTimeUs
) {
114 getOrCreateNodeStats(dest
).recordCheckoutTimeUs(null, checkoutTimeUs
);
115 recordCheckoutTimeUs(null, checkoutTimeUs
);
117 this.totalCheckoutTimeUs
.getAndAdd(checkoutTimeUs
);
118 checkoutTimeUsHistogram
.insert(checkoutTimeUs
);
119 int checkouts
= this.connectionsCheckedout
.getAndIncrement();
121 // reset aggregated stats and all the node stats for new interval
122 if(parent
== null && statsMap
!= null) {
123 int interval
= this.monitoringInterval
.get();
124 if(checkouts
% interval
== interval
- 1) {
125 // reset all children
126 Iterator
<SocketDestination
> it
= statsMap
.keySet().iterator();
127 while(it
.hasNext()) {
128 ClientSocketStats stats
= statsMap
.get(it
.next());
129 stats
.resetForInterval();
139 * Calculate the average and reset the stats
141 public void resetForInterval() {
142 // harmless race condition:
143 this.totalCheckoutTimeUs
.set(0);
144 this.connectionsCheckedout
.set(0);
145 checkoutTimeUsHistogram
.reset();
148 public void connectionCreate(SocketDestination dest
) {
150 getOrCreateNodeStats(dest
).connectionCreate(null);
151 connectionCreate(null);
153 this.connectionsCreated
.getAndIncrement();
157 public void connectionDestroy(SocketDestination dest
) {
159 getOrCreateNodeStats(dest
).connectionDestroy(null);
160 connectionDestroy(null);
162 this.connectionsDestroyed
.getAndIncrement();
168 public int getConnectionsCreated() {
169 return connectionsCreated
.intValue();
172 public int getConnectionsDestroyed() {
173 return connectionsDestroyed
.intValue();
176 // public int getConnectionsCheckedin() {
177 // return connectionsCheckedin.intValue();
180 public int getConnectionsCheckedout() {
181 return connectionsCheckedout
.intValue();
184 public Histogram
getWaitHistogram() {
185 return this.checkoutTimeUsHistogram
;
188 public long getAveWaitUs() {
189 long ns
= totalCheckoutTimeUs
.get();
190 int count
= connectionsCheckedout
.get();
191 this.avgCheckoutTimeUs
.set(count
> 0 ?
(ns
/ count
) : -1);
192 return this.avgCheckoutTimeUs
.longValue();
195 public int getConnectionsActive(SocketDestination destination
) {
196 if(destination
== null) {
197 return pool
.getTotalResourceCount();
199 return pool
.getTotalResourceCount(destination
);
203 public int getConnectionsInPool(SocketDestination destination
) {
204 if(destination
== null) {
205 return pool
.getCheckedInResourceCount();
207 return pool
.getCheckedInResourcesCount(destination
);
211 public void setMonitoringInterval(int count
) {
212 this.monitoringInterval
.set(count
);
215 public int getMonitoringInterval() {
216 return this.monitoringInterval
.get();
219 public void enableJmx() {
223 ConcurrentMap
<SocketDestination
, ClientSocketStats
> getStatsMap() {
227 SocketDestination
getDestination() {