View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.core.service;
21  
22  import java.util.concurrent.atomic.AtomicInteger;
23  import java.util.concurrent.locks.Lock;
24  import java.util.concurrent.locks.ReentrantLock;
25  
26  /**
27   * Provides usage statistics for an {@link AbstractIoService} instance.
28   * 
29   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
30   * @since 2.0.0-M3
31   */
32  public class IoServiceStatistics {
33  
34      private IoService service;
35  
36      /** The number of bytes read per second */
37      private double readBytesThroughput;
38  
39      /** The number of bytes written per second */
40      private double writtenBytesThroughput;
41  
42      /** The number of messages read per second */
43      private double readMessagesThroughput;
44  
45      /** The number of messages written per second */
46      private double writtenMessagesThroughput;
47  
48      /** The biggest number of bytes read per second */
49      private double largestReadBytesThroughput;
50  
51      /** The biggest number of bytes written per second */
52      private double largestWrittenBytesThroughput;
53  
54      /** The biggest number of messages read per second */
55      private double largestReadMessagesThroughput;
56  
57      /** The biggest number of messages written per second */
58      private double largestWrittenMessagesThroughput;
59  
60      /** The number of read bytes since the service has been started */
61      private long readBytes;
62  
63      /** The number of written bytes since the service has been started */
64      private long writtenBytes;
65  
66      /** The number of read messages since the service has been started */
67      private long readMessages;
68  
69      /** The number of written messages since the service has been started */
70      private long writtenMessages;
71  
72      /** The time the last read operation occurred */
73      private long lastReadTime;
74  
75      /** The time the last write operation occurred */
76      private long lastWriteTime;
77  
78      private long lastReadBytes;
79  
80      private long lastWrittenBytes;
81  
82      private long lastReadMessages;
83  
84      private long lastWrittenMessages;
85  
86      private long lastThroughputCalculationTime;
87  
88      private int scheduledWriteBytes;
89  
90      private int scheduledWriteMessages;
91  
92      /** The time (in second) between the computation of the service's statistics */
93      private final AtomicInteger throughputCalculationInterval = new AtomicInteger(3);
94  
95      private final Lock throughputCalculationLock = new ReentrantLock();
96  
97      /**
98       * Creates a new IoServiceStatistics instance
99       * 
100      * @param service The {@link IoService} for which we want statistics
101      */
102     public IoServiceStatistics(IoService service) {
103         this.service = service;
104     }
105 
106     /**
107      * @return The maximum number of sessions which were being managed at the
108      *         same time.
109      */
110     public final int getLargestManagedSessionCount() {
111         return ((AbstractIoService)service).getListeners().getLargestManagedSessionCount();
112     }
113 
114     /**
115      * @return The cumulative number of sessions which were managed (or are
116      *         being managed) by this service, which means 'currently managed
117      *         session count + closed session count'.
118      */
119     public final long getCumulativeManagedSessionCount() {
120         return ((AbstractIoService)service).getListeners().getCumulativeManagedSessionCount();
121     }
122 
123     /**
124      * @return the time in millis when the last I/O operation (read or write)
125      *         occurred.
126      */
127     public final long getLastIoTime() {
128         throughputCalculationLock.lock();
129 
130         try {
131             return Math.max(lastReadTime, lastWriteTime);
132         } finally {
133             throughputCalculationLock.unlock();
134         }
135     }
136 
137     /**
138      * @return The time in millis when the last read operation occurred.
139      */
140     public final long getLastReadTime() {
141         throughputCalculationLock.lock();
142 
143         try {
144             return lastReadTime;
145         } finally {
146             throughputCalculationLock.unlock();
147         }
148     }
149 
150     /**
151      * @return The time in millis when the last write operation occurred.
152      */
153     public final long getLastWriteTime() {
154         throughputCalculationLock.lock();
155 
156         try {
157             return lastWriteTime;
158         } finally {
159             throughputCalculationLock.unlock();
160         }
161     }
162 
163     /**
164      * @return The number of bytes this service has read so far
165      */
166     public final long getReadBytes() {
167         throughputCalculationLock.lock();
168 
169         try {
170             return readBytes;
171         } finally {
172             throughputCalculationLock.unlock();
173         }
174     }
175 
176     /**
177      * @return The number of bytes this service has written so far
178      */
179     public final long getWrittenBytes() {
180         throughputCalculationLock.lock();
181 
182         try {
183             return writtenBytes;
184         } finally {
185             throughputCalculationLock.unlock();
186         }
187     }
188 
189     /**
190      * @return The number of messages this services has read so far
191      */
192     public final long getReadMessages() {
193         throughputCalculationLock.lock();
194 
195         try {
196             return readMessages;
197         } finally {
198             throughputCalculationLock.unlock();
199         }
200     }
201 
202     /**
203      * @return The number of messages this service has written so far
204      */
205     public final long getWrittenMessages() {
206         throughputCalculationLock.lock();
207 
208         try {
209             return writtenMessages;
210         } finally {
211             throughputCalculationLock.unlock();
212         }
213     }
214 
215     /**
216      * @return The number of read bytes per second.
217      */
218     public final double getReadBytesThroughput() {
219         throughputCalculationLock.lock();
220 
221         try {
222             resetThroughput();
223             return readBytesThroughput;
224         } finally {
225             throughputCalculationLock.unlock();
226         }
227     }
228 
229     /**
230      * @return The number of written bytes per second.
231      */
232     public final double getWrittenBytesThroughput() {
233         throughputCalculationLock.lock();
234 
235         try {
236             resetThroughput();
237             return writtenBytesThroughput;
238         } finally {
239             throughputCalculationLock.unlock();
240         }
241     }
242 
243     /**
244      * @return The number of read messages per second.
245      */
246     public final double getReadMessagesThroughput() {
247         throughputCalculationLock.lock();
248 
249         try {
250             resetThroughput();
251             return readMessagesThroughput;
252         } finally {
253             throughputCalculationLock.unlock();
254         }
255     }
256 
257     /**
258      * @return The number of written messages per second.
259      */
260     public final double getWrittenMessagesThroughput() {
261         throughputCalculationLock.lock();
262 
263         try {
264             resetThroughput();
265             return writtenMessagesThroughput;
266         } finally {
267             throughputCalculationLock.unlock();
268         }
269     }
270 
271     /**
272      * @return The maximum number of bytes read per second since the service has
273      *         been started.
274      */
275     public final double getLargestReadBytesThroughput() {
276         throughputCalculationLock.lock();
277 
278         try {
279             return largestReadBytesThroughput;
280         } finally {
281             throughputCalculationLock.unlock();
282         }
283     }
284 
285     /**
286      * @return The maximum number of bytes written per second since the service
287      *         has been started.
288      */
289     public final double getLargestWrittenBytesThroughput() {
290         throughputCalculationLock.lock();
291 
292         try {
293             return largestWrittenBytesThroughput;
294         } finally {
295             throughputCalculationLock.unlock();
296         }
297     }
298 
299     /**
300      * @return The maximum number of messages read per second since the service
301      *         has been started.
302      */
303     public final double getLargestReadMessagesThroughput() {
304         throughputCalculationLock.lock();
305 
306         try {
307             return largestReadMessagesThroughput;
308         } finally {
309             throughputCalculationLock.unlock();
310         }
311     }
312 
313     /**
314      * @return The maximum number of messages written per second since the
315      *         service has been started.
316      */
317     public final double getLargestWrittenMessagesThroughput() {
318         throughputCalculationLock.lock();
319 
320         try {
321             return largestWrittenMessagesThroughput;
322         } finally {
323             throughputCalculationLock.unlock();
324         }
325     }
326 
327     /**
328      * @return the interval (seconds) between each throughput calculation. The
329      *         default value is <tt>3</tt> seconds.
330      */
331     public final int getThroughputCalculationInterval() {
332         return throughputCalculationInterval.get();
333     }
334 
335     /**
336      * @return the interval (milliseconds) between each throughput calculation.
337      * The default value is <tt>3</tt> seconds.
338      */
339     public final long getThroughputCalculationIntervalInMillis() {
340         return throughputCalculationInterval.get() * 1000L;
341     }
342 
343     /**
344      * Sets the interval (seconds) between each throughput calculation.  The
345      * default value is <tt>3</tt> seconds.
346      * 
347      * @param throughputCalculationInterval The interval between two calculation
348      */
349     public final void setThroughputCalculationInterval(int throughputCalculationInterval) {
350         if (throughputCalculationInterval < 0) {
351             throw new IllegalArgumentException("throughputCalculationInterval: " + throughputCalculationInterval);
352         }
353 
354         this.throughputCalculationInterval.set(throughputCalculationInterval);
355     }
356 
357     /**
358      * Sets last time at which a read occurred on the service.
359      * 
360      * @param lastReadTime
361      *            The last time a read has occurred
362      */
363     protected final void setLastReadTime(long lastReadTime) {
364         throughputCalculationLock.lock();
365 
366         try {
367             this.lastReadTime = lastReadTime;
368         } finally {
369             throughputCalculationLock.unlock();
370         }
371     }
372 
373     /**
374      * Sets last time at which a write occurred on the service.
375      * 
376      * @param lastWriteTime
377      *            The last time a write has occurred
378      */
379     protected final void setLastWriteTime(long lastWriteTime) {
380         throughputCalculationLock.lock();
381 
382         try {
383             this.lastWriteTime = lastWriteTime;
384         } finally {
385             throughputCalculationLock.unlock();
386         }
387     }
388 
389     /**
390      * Resets the throughput counters of the service if no session is currently
391      * managed.
392      */
393     private void resetThroughput() {
394         if (service.getManagedSessionCount() == 0) {
395             readBytesThroughput = 0;
396             writtenBytesThroughput = 0;
397             readMessagesThroughput = 0;
398             writtenMessagesThroughput = 0;
399         }
400     }
401 
402     /**
403      * Updates the throughput counters.
404      * 
405      * @param currentTime The current time
406      */
407     public void updateThroughput(long currentTime) {
408         throughputCalculationLock.lock();
409 
410         try {
411             int interval = (int) (currentTime - lastThroughputCalculationTime);
412             long minInterval = getThroughputCalculationIntervalInMillis();
413 
414             if ((minInterval == 0) || (interval < minInterval)) {
415                 return;
416             }
417 
418             readBytesThroughput = (readBytes - lastReadBytes) * 1000.0 / interval;
419             writtenBytesThroughput = (writtenBytes - lastWrittenBytes) * 1000.0 / interval;
420             readMessagesThroughput = (readMessages - lastReadMessages) * 1000.0 / interval;
421             writtenMessagesThroughput = (writtenMessages - lastWrittenMessages) * 1000.0 / interval;
422 
423             if (readBytesThroughput > largestReadBytesThroughput) {
424                 largestReadBytesThroughput = readBytesThroughput;
425             }
426 
427             if (writtenBytesThroughput > largestWrittenBytesThroughput) {
428                 largestWrittenBytesThroughput = writtenBytesThroughput;
429             }
430 
431             if (readMessagesThroughput > largestReadMessagesThroughput) {
432                 largestReadMessagesThroughput = readMessagesThroughput;
433             }
434 
435             if (writtenMessagesThroughput > largestWrittenMessagesThroughput) {
436                 largestWrittenMessagesThroughput = writtenMessagesThroughput;
437             }
438 
439             lastReadBytes = readBytes;
440             lastWrittenBytes = writtenBytes;
441             lastReadMessages = readMessages;
442             lastWrittenMessages = writtenMessages;
443 
444             lastThroughputCalculationTime = currentTime;
445         } finally {
446             throughputCalculationLock.unlock();
447         }
448     }
449 
450     /**
451      * Increases the count of read bytes by <code>nbBytesRead</code> and sets
452      * the last read time to <code>currentTime</code>.
453      * 
454      * @param nbBytesRead
455      *            The number of bytes read
456      * @param currentTime
457      *            The date those bytes were read
458      */
459     public final void increaseReadBytes(long nbBytesRead, long currentTime) {
460         throughputCalculationLock.lock();
461 
462         try {
463             readBytes += nbBytesRead;
464             lastReadTime = currentTime;
465         } finally {
466             throughputCalculationLock.unlock();
467         }
468     }
469 
470     /**
471      * Increases the count of read messages by 1 and sets the last read time to
472      * <code>currentTime</code>.
473      * 
474      * @param currentTime
475      *            The time the message has been read
476      */
477     public final void increaseReadMessages(long currentTime) {
478         throughputCalculationLock.lock();
479 
480         try {
481             readMessages++;
482             lastReadTime = currentTime;
483         } finally {
484             throughputCalculationLock.unlock();
485         }
486     }
487 
488     /**
489      * Increases the count of written bytes by <code>nbBytesWritten</code> and
490      * sets the last write time to <code>currentTime</code>.
491      * 
492      * @param nbBytesWritten
493      *            The number of bytes written
494      * @param currentTime
495      *            The date those bytes were written
496      */
497     public final void increaseWrittenBytes(int nbBytesWritten, long currentTime) {
498         throughputCalculationLock.lock();
499 
500         try {
501             writtenBytes += nbBytesWritten;
502             lastWriteTime = currentTime;
503         } finally {
504             throughputCalculationLock.unlock();
505         }
506     }
507 
508     /**
509      * Increases the count of written messages by 1 and sets the last write time
510      * to <code>currentTime</code>.
511      * 
512      * @param currentTime
513      *            The date the message were written
514      */
515     public final void increaseWrittenMessages(long currentTime) {
516         throughputCalculationLock.lock();
517 
518         try {
519             writtenMessages++;
520             lastWriteTime = currentTime;
521         } finally {
522             throughputCalculationLock.unlock();
523         }
524     }
525 
526     /**
527      * @return The count of bytes scheduled for write.
528      */
529     public final int getScheduledWriteBytes() {
530         throughputCalculationLock.lock();
531 
532         try {
533             return scheduledWriteBytes;
534         } finally {
535             throughputCalculationLock.unlock();
536         }
537     }
538 
539     /**
540      * Increments by <code>increment</code> the count of bytes scheduled for write.
541      * 
542      * @param increment The number of added bytes fro write
543      */
544     public final void increaseScheduledWriteBytes(int increment) {
545         throughputCalculationLock.lock();
546 
547         try {
548             scheduledWriteBytes += increment;
549         } finally {
550             throughputCalculationLock.unlock();
551         }
552     }
553 
554     /**
555      * @return the count of messages scheduled for write.
556      */
557     public final int getScheduledWriteMessages() {
558         throughputCalculationLock.lock();
559 
560         try {
561             return scheduledWriteMessages;
562         } finally {
563             throughputCalculationLock.unlock();
564         }
565     }
566 
567     /**
568      * Increments the count of messages scheduled for write.
569      */
570     public final void increaseScheduledWriteMessages() {
571         throughputCalculationLock.lock();
572 
573         try {
574             scheduledWriteMessages++;
575         } finally {
576             throughputCalculationLock.unlock();
577         }
578     }
579 
580     /**
581      * Decrements the count of messages scheduled for write.
582      */
583     public final void decreaseScheduledWriteMessages() {
584         throughputCalculationLock.lock();
585 
586         try {
587             scheduledWriteMessages--;
588         } finally {
589             throughputCalculationLock.unlock();
590         }
591     }
592 
593     /**
594      * Sets the time at which throughput counters where updated.
595      * 
596      * @param lastThroughputCalculationTime The time at which throughput counters where updated.
597      */
598     protected void setLastThroughputCalculationTime(long lastThroughputCalculationTime) {
599         throughputCalculationLock.lock();
600 
601         try {
602             this.lastThroughputCalculationTime = lastThroughputCalculationTime;
603         } finally {
604             throughputCalculationLock.unlock();
605         }
606     }
607 }