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      * @return 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      * @param throughputCalculationInterval The interval between two calculation
343      */
344     public final void setThroughputCalculationInterval(int throughputCalculationInterval) {
345         if (throughputCalculationInterval < 0) {
346             throw new IllegalArgumentException("throughputCalculationInterval: " + throughputCalculationInterval);
347         }
348 
349         this.throughputCalculationInterval.set(throughputCalculationInterval);
350     }
351 
352     /**
353      * Sets last time at which a read occurred on the service.
354      * 
355      * @param lastReadTime
356      *            The last time a read has occurred
357      */
358     protected final void setLastReadTime(long lastReadTime) {
359         throughputCalculationLock.lock();
360 
361         try {
362             this.lastReadTime = lastReadTime;
363         } finally {
364             throughputCalculationLock.unlock();
365         }
366     }
367 
368     /**
369      * Sets last time at which a write occurred on the service.
370      * 
371      * @param lastWriteTime
372      *            The last time a write has occurred
373      */
374     protected final void setLastWriteTime(long lastWriteTime) {
375         throughputCalculationLock.lock();
376 
377         try {
378             this.lastWriteTime = lastWriteTime;
379         } finally {
380             throughputCalculationLock.unlock();
381         }
382     }
383 
384     /**
385      * Resets the throughput counters of the service if no session is currently
386      * managed.
387      */
388     private void resetThroughput() {
389         if (service.getManagedSessionCount() == 0) {
390             readBytesThroughput = 0;
391             writtenBytesThroughput = 0;
392             readMessagesThroughput = 0;
393             writtenMessagesThroughput = 0;
394         }
395     }
396 
397     /**
398      * Updates the throughput counters.
399      * 
400      * @param currentTime The current time
401      */
402     public void updateThroughput(long currentTime) {
403         throughputCalculationLock.lock();
404 
405         try {
406             int interval = (int) (currentTime - lastThroughputCalculationTime);
407             long minInterval = getThroughputCalculationIntervalInMillis();
408 
409             if ((minInterval == 0) || (interval < minInterval)) {
410                 return;
411             }
412 
413             long readBytes = this.readBytes;
414             long writtenBytes = this.writtenBytes;
415             long readMessages = this.readMessages;
416             long writtenMessages = this.writtenMessages;
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 }