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 AbstractIoService 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      public IoServiceStatistics(AbstractIoService service) {
98          this.service = service;
99      }
100 
101     /**
102      * @return The maximum number of sessions which were being managed at the
103      *         same time.
104      */
105     public final int getLargestManagedSessionCount() {
106         return service.getListeners().getLargestManagedSessionCount();
107     }
108 
109     /**
110      * @return The cumulative number of sessions which were managed (or are
111      *         being managed) by this service, which means 'currently managed
112      *         session count + closed session count'.
113      */
114     public final long getCumulativeManagedSessionCount() {
115         return service.getListeners().getCumulativeManagedSessionCount();
116     }
117 
118     /**
119      * @return the time in millis when the last I/O operation (read or write)
120      *         occurred.
121      */
122     public final long getLastIoTime() {
123         throughputCalculationLock.lock();
124 
125         try {
126             return Math.max(lastReadTime, lastWriteTime);
127         } finally {
128             throughputCalculationLock.unlock();
129         }
130     }
131 
132     /**
133      * @return The time in millis when the last read operation occurred.
134      */
135     public final long getLastReadTime() {
136         throughputCalculationLock.lock();
137 
138         try {
139             return lastReadTime;
140         } finally {
141             throughputCalculationLock.unlock();
142         }
143     }
144 
145     /**
146      * @return The time in millis when the last write operation occurred.
147      */
148     public final long getLastWriteTime() {
149         throughputCalculationLock.lock();
150 
151         try {
152             return lastWriteTime;
153         } finally {
154             throughputCalculationLock.unlock();
155         }
156     }
157 
158     /**
159      * @return The number of bytes this service has read so far
160      */
161     public final long getReadBytes() {
162         throughputCalculationLock.lock();
163 
164         try {
165             return readBytes;
166         } finally {
167             throughputCalculationLock.unlock();
168         }
169     }
170 
171     /**
172      * @return The number of bytes this service has written so far
173      */
174     public final long getWrittenBytes() {
175         throughputCalculationLock.lock();
176 
177         try {
178             return writtenBytes;
179         } finally {
180             throughputCalculationLock.unlock();
181         }
182     }
183 
184     /**
185      * @return The number of messages this services has read so far
186      */
187     public final long getReadMessages() {
188         throughputCalculationLock.lock();
189 
190         try {
191             return readMessages;
192         } finally {
193             throughputCalculationLock.unlock();
194         }
195     }
196 
197     /**
198      * @return The number of messages this service has written so far
199      */
200     public final long getWrittenMessages() {
201         throughputCalculationLock.lock();
202 
203         try {
204             return writtenMessages;
205         } finally {
206             throughputCalculationLock.unlock();
207         }
208     }
209 
210     /**
211      * @return The number of read bytes per second.
212      */
213     public final double getReadBytesThroughput() {
214         throughputCalculationLock.lock();
215 
216         try {
217             resetThroughput();
218             return readBytesThroughput;
219         } finally {
220             throughputCalculationLock.unlock();
221         }
222     }
223 
224     /**
225      * @return The number of written bytes per second.
226      */
227     public final double getWrittenBytesThroughput() {
228         throughputCalculationLock.lock();
229 
230         try {
231             resetThroughput();
232             return writtenBytesThroughput;
233         } finally {
234             throughputCalculationLock.unlock();
235         }
236     }
237 
238     /**
239      * @return The number of read messages per second.
240      */
241     public final double getReadMessagesThroughput() {
242         throughputCalculationLock.lock();
243 
244         try {
245             resetThroughput();
246             return readMessagesThroughput;
247         } finally {
248             throughputCalculationLock.unlock();
249         }
250     }
251 
252     /**
253      * @return The number of written messages per second.
254      */
255     public final double getWrittenMessagesThroughput() {
256         throughputCalculationLock.lock();
257 
258         try {
259             resetThroughput();
260             return writtenMessagesThroughput;
261         } finally {
262             throughputCalculationLock.unlock();
263         }
264     }
265 
266     /**
267      * @return The maximum number of bytes read per second since the service has
268      *         been started.
269      */
270     public final double getLargestReadBytesThroughput() {
271         throughputCalculationLock.lock();
272 
273         try {
274             return largestReadBytesThroughput;
275         } finally {
276             throughputCalculationLock.unlock();
277         }
278     }
279 
280     /**
281      * @return The maximum number of bytes written per second since the service
282      *         has been started.
283      */
284     public final double getLargestWrittenBytesThroughput() {
285         throughputCalculationLock.lock();
286 
287         try {
288             return largestWrittenBytesThroughput;
289         } finally {
290             throughputCalculationLock.unlock();
291         }
292     }
293 
294     /**
295      * @return The maximum number of messages read per second since the service
296      *         has been started.
297      */
298     public final double getLargestReadMessagesThroughput() {
299         throughputCalculationLock.lock();
300 
301         try {
302             return largestReadMessagesThroughput;
303         } finally {
304             throughputCalculationLock.unlock();
305         }
306     }
307 
308     /**
309      * @return The maximum number of messages written per second since the
310      *         service has been started.
311      */
312     public final double getLargestWrittenMessagesThroughput() {
313         throughputCalculationLock.lock();
314 
315         try {
316             return largestWrittenMessagesThroughput;
317         } finally {
318             throughputCalculationLock.unlock();
319         }
320     }
321 
322     /**
323      * @return the interval (seconds) between each throughput calculation. The
324      *         default value is <tt>3</tt> seconds.
325      */
326     public final int getThroughputCalculationInterval() {
327         return throughputCalculationInterval.get();
328     }
329 
330     /**
331      * Returns the interval (milliseconds) between each throughput calculation.
332      * The default value is <tt>3</tt> seconds.
333      */
334     public final long getThroughputCalculationIntervalInMillis() {
335         return throughputCalculationInterval.get() * 1000L;
336     }
337 
338     /**
339      * Sets the interval (seconds) between each throughput calculation.  The
340      * default value is <tt>3</tt> seconds.
341      */
342     public final void setThroughputCalculationInterval(int throughputCalculationInterval) {
343         if (throughputCalculationInterval < 0) {
344             throw new IllegalArgumentException("throughputCalculationInterval: " + throughputCalculationInterval);
345         }
346 
347         this.throughputCalculationInterval.set(throughputCalculationInterval);
348     }
349 
350     /**
351      * Sets last time at which a read occurred on the service.
352      * 
353      * @param lastReadTime
354      *            The last time a read has occurred
355      */
356     protected final void setLastReadTime(long lastReadTime) {
357         throughputCalculationLock.lock();
358 
359         try {
360             this.lastReadTime = lastReadTime;
361         } finally {
362             throughputCalculationLock.unlock();
363         }
364     }
365 
366     /**
367      * Sets last time at which a write occurred on the service.
368      * 
369      * @param lastWriteTime
370      *            The last time a write has occurred
371      */
372     protected final void setLastWriteTime(long lastWriteTime) {
373         throughputCalculationLock.lock();
374 
375         try {
376             this.lastWriteTime = lastWriteTime;
377         } finally {
378             throughputCalculationLock.unlock();
379         }
380     }
381 
382     /**
383      * Resets the throughput counters of the service if no session is currently
384      * managed.
385      */
386     private void resetThroughput() {
387         if (service.getManagedSessionCount() == 0) {
388             readBytesThroughput = 0;
389             writtenBytesThroughput = 0;
390             readMessagesThroughput = 0;
391             writtenMessagesThroughput = 0;
392         }
393     }
394 
395     /**
396      * Updates the throughput counters.
397      */
398     public void updateThroughput(long currentTime) {
399         throughputCalculationLock.lock();
400 
401         try {
402             int interval = (int) (currentTime - lastThroughputCalculationTime);
403             long minInterval = getThroughputCalculationIntervalInMillis();
404 
405             if ((minInterval == 0) || (interval < minInterval)) {
406                 return;
407             }
408 
409             long readBytes = this.readBytes;
410             long writtenBytes = this.writtenBytes;
411             long readMessages = this.readMessages;
412             long writtenMessages = this.writtenMessages;
413 
414             readBytesThroughput = (readBytes - lastReadBytes) * 1000.0 / interval;
415             writtenBytesThroughput = (writtenBytes - lastWrittenBytes) * 1000.0 / interval;
416             readMessagesThroughput = (readMessages - lastReadMessages) * 1000.0 / interval;
417             writtenMessagesThroughput = (writtenMessages - lastWrittenMessages) * 1000.0 / interval;
418 
419             if (readBytesThroughput > largestReadBytesThroughput) {
420                 largestReadBytesThroughput = readBytesThroughput;
421             }
422 
423             if (writtenBytesThroughput > largestWrittenBytesThroughput) {
424                 largestWrittenBytesThroughput = writtenBytesThroughput;
425             }
426 
427             if (readMessagesThroughput > largestReadMessagesThroughput) {
428                 largestReadMessagesThroughput = readMessagesThroughput;
429             }
430 
431             if (writtenMessagesThroughput > largestWrittenMessagesThroughput) {
432                 largestWrittenMessagesThroughput = writtenMessagesThroughput;
433             }
434 
435             lastReadBytes = readBytes;
436             lastWrittenBytes = writtenBytes;
437             lastReadMessages = readMessages;
438             lastWrittenMessages = writtenMessages;
439 
440             lastThroughputCalculationTime = currentTime;
441         } finally {
442             throughputCalculationLock.unlock();
443         }
444     }
445 
446     /**
447      * Increases the count of read bytes by <code>nbBytesRead</code> and sets
448      * the last read time to <code>currentTime</code>.
449      * 
450      * @param nbBytesRead
451      *            The number of bytes read
452      * @param currentTime
453      *            The date those bytes were read
454      */
455     public final void increaseReadBytes(long nbBytesRead, long currentTime) {
456         throughputCalculationLock.lock();
457 
458         try {
459             readBytes += nbBytesRead;
460             lastReadTime = currentTime;
461         } finally {
462             throughputCalculationLock.unlock();
463         }
464     }
465 
466     /**
467      * Increases the count of read messages by 1 and sets the last read time to
468      * <code>currentTime</code>.
469      * 
470      * @param currentTime
471      *            The time the message has been read
472      */
473     public final void increaseReadMessages(long currentTime) {
474         throughputCalculationLock.lock();
475 
476         try {
477             readMessages++;
478             lastReadTime = currentTime;
479         } finally {
480             throughputCalculationLock.unlock();
481         }
482     }
483 
484     /**
485      * Increases the count of written bytes by <code>nbBytesWritten</code> and
486      * sets the last write time to <code>currentTime</code>.
487      * 
488      * @param nbBytesWritten
489      *            The number of bytes written
490      * @param currentTime
491      *            The date those bytes were written
492      */
493     public final void increaseWrittenBytes(int nbBytesWritten, long currentTime) {
494         throughputCalculationLock.lock();
495 
496         try {
497             writtenBytes += nbBytesWritten;
498             lastWriteTime = currentTime;
499         } finally {
500             throughputCalculationLock.unlock();
501         }
502     }
503 
504     /**
505      * Increases the count of written messages by 1 and sets the last write time
506      * to <code>currentTime</code>.
507      * 
508      * @param currentTime
509      *            The date the message were written
510      */
511     public final void increaseWrittenMessages(long currentTime) {
512         throughputCalculationLock.lock();
513 
514         try {
515             writtenMessages++;
516             lastWriteTime = currentTime;
517         } finally {
518             throughputCalculationLock.unlock();
519         }
520     }
521 
522     /**
523      * @return The count of bytes scheduled for write.
524      */
525     public final int getScheduledWriteBytes() {
526         throughputCalculationLock.lock();
527 
528         try {
529             return scheduledWriteBytes;
530         } finally {
531             throughputCalculationLock.unlock();
532         }
533     }
534 
535     /**
536      * Increments by <code>increment</code> the count of bytes scheduled for write.
537      */
538     public final void increaseScheduledWriteBytes(int increment) {
539         throughputCalculationLock.lock();
540 
541         try {
542             scheduledWriteBytes += increment;
543         } finally {
544             throughputCalculationLock.unlock();
545         }
546     }
547 
548     /**
549      * @return the count of messages scheduled for write.
550      */
551     public final int getScheduledWriteMessages() {
552         throughputCalculationLock.lock();
553 
554         try {
555             return scheduledWriteMessages;
556         } finally {
557             throughputCalculationLock.unlock();
558         }
559     }
560 
561     /**
562      * Increments the count of messages scheduled for write.
563      */
564     public final void increaseScheduledWriteMessages() {
565         throughputCalculationLock.lock();
566 
567         try {
568             scheduledWriteMessages++;
569         } finally {
570             throughputCalculationLock.unlock();
571         }
572     }
573 
574     /**
575      * Decrements the count of messages scheduled for write.
576      */
577     public final void decreaseScheduledWriteMessages() {
578         throughputCalculationLock.lock();
579 
580         try {
581             scheduledWriteMessages--;
582         } finally {
583             throughputCalculationLock.unlock();
584         }
585     }
586 
587     /**
588      * Sets the time at which throughput counters where updated.
589      */
590     protected void setLastThroughputCalculationTime(long lastThroughputCalculationTime) {
591         throughputCalculationLock.lock();
592 
593         try {
594             this.lastThroughputCalculationTime = lastThroughputCalculationTime;
595         } finally {
596             throughputCalculationLock.unlock();
597         }
598     }
599 }