View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    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
    14   * under the License.
    15   */
    16  package org.jboss.netty.handler.traffic;
    17
    18  import java.util.concurrent.TimeUnit;
    19  import java.util.concurrent.atomic.AtomicBoolean;
    20  import java.util.concurrent.atomic.AtomicLong;
    21
    22  import org.jboss.netty.channel.ChannelHandlerContext;
    23  import org.jboss.netty.util.Timeout;
    24  import org.jboss.netty.util.Timer;
    25  import org.jboss.netty.util.TimerTask;
    26
    27  /**
    28   * TrafficCounter is associated with {@link AbstractTrafficShapingHandler}.<br>
    29   * <br>
    30   * A TrafficCounter has for goal to count the traffic in order to enable to limit the traffic or not,
    31   * globally or per channel. It compute statistics on read and written bytes at the specified
    32   * interval and call back the {@link AbstractTrafficShapingHandler} doAccounting method at every
    33   * specified interval. If this interval is set to 0, therefore no accounting will be done and only
    34   * statistics will be computed at each receive or write operations.
    35   */
    36  public class TrafficCounter {
    37      /**
    38       * Current written bytes
    39       */
    40      private final AtomicLong currentWrittenBytes = new AtomicLong();
    41
    42      /**
    43       * Current read bytes
    44       */
    45      private final AtomicLong currentReadBytes = new AtomicLong();
    46
    47      /**
    48       * Long life written bytes
    49       */
    50      private final AtomicLong cumulativeWrittenBytes = new AtomicLong();
    51
    52      /**
    53       * Long life read bytes
    54       */
    55      private final AtomicLong cumulativeReadBytes = new AtomicLong();
    56
    57      /**
    58       * Last Time where cumulative bytes where reset to zero
    59       */
    60      private long lastCumulativeTime;
    61
    62      /**
    63       * Last writing bandwidth
    64       */
    65      private long lastWriteThroughput;
    66
    67      /**
    68       * Last reading bandwidth
    69       */
    70      private long lastReadThroughput;
    71
    72      /**
    73       * Last Time Check taken
    74       */
    75      private final AtomicLong lastTime = new AtomicLong();
    76
    77      /**
    78       * Last written bytes number during last check interval
    79       */
    80      private long lastWrittenBytes;
    81
    82      /**
    83       * Last read bytes number during last check interval
    84       */
    85      private long lastReadBytes;
    86
    87      /**
    88       * Delay between two captures
    89       */
    90      AtomicLong checkInterval = new AtomicLong(
    91              AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL);
    92
    93      // default 1 s
    94
    95      /**
    96       * Name of this Monitor
    97       */
    98      final String name;
    99
    100     /**
    101      * The associated TrafficShapingHandler
    102      */
    103     private final AbstractTrafficShapingHandler trafficShapingHandler;
    104
    105     /**
    106      * One Timer for all Counter
    107      */
    108     private final Timer timer;  // replace executor
    109     /**
    110      * Monitor created once in start()
    111      */
    112     private TimerTask timerTask;
    113     /**
    114      * used in stop() to cancel the timer
    115      */
    116    private volatile Timeout timeout;
    117
    118     /**
    119      * Is Monitor active
    120      */
    121     AtomicBoolean monitorActive = new AtomicBoolean();
    122
    123     /**
    124      * Class to implement monitoring at fix delay
    125      *
    126      */
    127     private static class TrafficMonitoringTask implements TimerTask {
    128         /**
    129          * The associated TrafficShapingHandler
    130          */
    131         private final AbstractTrafficShapingHandler trafficShapingHandler1;
    132
    133         /**
    134          * The associated TrafficCounter
    135          */
    136         private final TrafficCounter counter;
    137
    138         /**
    139          * @param trafficShapingHandler
    140          * @param counter
    141          */
    142         protected TrafficMonitoringTask(
    143                 AbstractTrafficShapingHandler trafficShapingHandler,
    144                 TrafficCounter counter) {
    145             trafficShapingHandler1 = trafficShapingHandler;
    146             this.counter = counter;
    147         }
    148
    149         public void run(Timeout timeout) throws Exception {
    150             if (!counter.monitorActive.get()) {
    151                 return;
    152             }
    153             long endTime = System.currentTimeMillis();
    154             counter.resetAccounting(endTime);
    155             if (trafficShapingHandler1 != null) {
    156                 trafficShapingHandler1.doAccounting(counter);
    157             }
    158             timeout =
    159                 counter.timer.newTimeout(this, counter.checkInterval.get(), TimeUnit.MILLISECONDS);
    160         }
    161     }
    162
    163     /**
    164      * Start the monitoring process
    165      */
    166     public void start() {
    167         synchronized (lastTime) {
    168             if (monitorActive.get()) {
    169                 return;
    170             }
    171             lastTime.set(System.currentTimeMillis());
    172             if (checkInterval.get() > 0) {
    173                 monitorActive.set(true);
    174                 timerTask = new TrafficMonitoringTask(trafficShapingHandler, this);
    175                 timeout =
    176                     timer.newTimeout(timerTask, checkInterval.get(), TimeUnit.MILLISECONDS);
    177             }
    178         }
    179     }
    180
    181     /**
    182      * Stop the monitoring process
    183      */
    184     public void stop() {
    185         synchronized (lastTime) {
    186             if (!monitorActive.get()) {
    187                 return;
    188             }
    189             monitorActive.set(false);
    190             resetAccounting(System.currentTimeMillis());
    191             if (trafficShapingHandler != null) {
    192                 trafficShapingHandler.doAccounting(this);
    193             }
    194             if (timeout != null) {
    195                 timeout.cancel();
    196             }
    197         }
    198     }
    199
    200     /**
    201      * Reset the accounting on Read and Write
    202      *
    203      * @param newLastTime
    204      */
    205     void resetAccounting(long newLastTime) {
    206         synchronized (lastTime) {
    207             long interval = newLastTime - lastTime.getAndSet(newLastTime);
    208             if (interval == 0) {
    209                 // nothing to do
    210                 return;
    211             }
    212             lastReadBytes = currentReadBytes.getAndSet(0);
    213             lastWrittenBytes = currentWrittenBytes.getAndSet(0);
    214             lastReadThroughput = lastReadBytes / interval * 1000;
    215             // nb byte / checkInterval in ms * 1000 (1s)
    216             lastWriteThroughput = lastWrittenBytes / interval * 1000;
    217             // nb byte / checkInterval in ms * 1000 (1s)
    218         }
    219     }
    220
    221     /**
    222      * Constructor with the {@link AbstractTrafficShapingHandler} that hosts it, the Timer to use, its
    223      * name, the checkInterval between two computations in millisecond
    224      * @param trafficShapingHandler the associated AbstractTrafficShapingHandler
    225      * @param timer
    226      *            Could be a HashedWheelTimer
    227      * @param name
    228      *            the name given to this monitor
    229      * @param checkInterval
    230      *            the checkInterval in millisecond between two computations
    231      */
    232     public TrafficCounter(AbstractTrafficShapingHandler trafficShapingHandler,
    233             Timer timer, String name, long checkInterval) {
    234         this.trafficShapingHandler = trafficShapingHandler;
    235         this.timer = timer;
    236         this.name = name;
    237         lastCumulativeTime = System.currentTimeMillis();
    238         configure(checkInterval);
    239     }
    240
    241     /**
    242      * Change checkInterval between
    243      * two computations in millisecond
    244      *
    245      * @param newcheckInterval
    246      */
    247     public void configure(long newcheckInterval) {
    248         long newInterval = newcheckInterval / 10 * 10;
    249         if (checkInterval.get() != newInterval) {
    250             checkInterval.set(newInterval);
    251             if (newInterval <= 0) {
    252                 stop();
    253                 // No more active monitoring
    254                 lastTime.set(System.currentTimeMillis());
    255             } else {
    256                 // Start if necessary
    257                 start();
    258             }
    259         }
    260     }
    261
    262     /**
    263      * Computes counters for Read.
    264      *
    265      * @param ctx
    266      *            the associated channelHandlerContext
    267      * @param recv
    268      *            the size in bytes to read
    269      */
    270     void bytesRecvFlowControl(ChannelHandlerContext ctx, long recv) {
    271         currentReadBytes.addAndGet(recv);
    272         cumulativeReadBytes.addAndGet(recv);
    273     }
    274
    275     /**
    276      * Computes counters for Write.
    277      *
    278      * @param write
    279      *            the size in bytes to write
    280      */
    281     void bytesWriteFlowControl(long write) {
    282         currentWrittenBytes.addAndGet(write);
    283         cumulativeWrittenBytes.addAndGet(write);
    284     }
    285
    286     /**
    287      *
    288      * @return the current checkInterval between two computations of traffic counter
    289      *         in millisecond
    290      */
    291     public long getCheckInterval() {
    292         return checkInterval.get();
    293     }
    294
    295     /**
    296      *
    297      * @return the Read Throughput in bytes/s computes in the last check interval
    298      */
    299     public long getLastReadThroughput() {
    300         return lastReadThroughput;
    301     }
    302
    303     /**
    304      *
    305      * @return the Write Throughput in bytes/s computes in the last check interval
    306      */
    307     public long getLastWriteThroughput() {
    308         return lastWriteThroughput;
    309     }
    310
    311     /**
    312      *
    313      * @return the number of bytes read during the last check Interval
    314      */
    315     public long getLastReadBytes() {
    316         return lastReadBytes;
    317     }
    318
    319     /**
    320      *
    321      * @return the number of bytes written during the last check Interval
    322      */
    323     public long getLastWrittenBytes() {
    324         return lastWrittenBytes;
    325     }
    326
    327     /**
    328     *
    329     * @return the current number of bytes read since the last checkInterval
    330     */
    331     public long getCurrentReadBytes() {
    332         return currentReadBytes.get();
    333     }
    334
    335     /**
    336      *
    337      * @return the current number of bytes written since the last check Interval
    338      */
    339     public long getCurrentWrittenBytes() {
    340         return currentWrittenBytes.get();
    341     }
    342
    343     /**
    344      * @return the Time in millisecond of the last check as of System.currentTimeMillis()
    345      */
    346     public long getLastTime() {
    347         return lastTime.get();
    348     }
    349
    350     /**
    351      * @return the cumulativeWrittenBytes
    352      */
    353     public long getCumulativeWrittenBytes() {
    354         return cumulativeWrittenBytes.get();
    355     }
    356
    357     /**
    358      * @return the cumulativeReadBytes
    359      */
    360     public long getCumulativeReadBytes() {
    361         return cumulativeReadBytes.get();
    362     }
    363
    364     /**
    365      * @return the lastCumulativeTime in millisecond as of System.currentTimeMillis()
    366      * when the cumulative counters were reset to 0.
    367      */
    368     public long getLastCumulativeTime() {
    369         return lastCumulativeTime;
    370     }
    371
    372     /**
    373      * Reset both read and written cumulative bytes counters and the associated time.
    374      */
    375     public void resetCumulativeTime() {
    376         lastCumulativeTime = System.currentTimeMillis();
    377         cumulativeReadBytes.set(0);
    378         cumulativeWrittenBytes.set(0);
    379     }
    380
    381     /**
    382      * @return the name
    383      */
    384     public String getName() {
    385         return name;
    386     }
    387
    388     /**
    389      * String information
    390      */
    391     @Override
    392     public String toString() {
    393         return "Monitor " + name + " Current Speed Read: " +
    394                 (lastReadThroughput >> 10) + " KB/s, Write: " +
    395                 (lastWriteThroughput >> 10) + " KB/s Current Read: " +
    396                 (currentReadBytes.get() >> 10) + " KB Current Write: " +
    397                 (currentWrittenBytes.get() >> 10) + " KB";
    398     }
    399 }