View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * 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 distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  package io.netty.handler.codec.http2;
16  
17  import static java.util.concurrent.TimeUnit.NANOSECONDS;
18  import static java.util.concurrent.TimeUnit.SECONDS;
19  import io.netty.channel.ChannelHandlerAdapter;
20  import io.netty.channel.ChannelHandlerContext;
21  
22  import java.util.ArrayDeque;
23  import java.util.Queue;
24  import java.util.concurrent.ScheduledFuture;
25  
26  /**
27   * A {@link Http2StreamRemovalPolicy} that periodically runs garbage collection on streams that have
28   * been marked for removal.
29   */
30  public class DefaultHttp2StreamRemovalPolicy extends ChannelHandlerAdapter implements
31          Http2StreamRemovalPolicy, Runnable {
32  
33      /**
34       * The interval (in ns) at which the removed priority garbage collector runs.
35       */
36      private static final long GARBAGE_COLLECTION_INTERVAL = SECONDS.toNanos(5);
37  
38      private final Queue<Garbage> garbage = new ArrayDeque<Garbage>();
39      private ScheduledFuture<?> timerFuture;
40      private Action action;
41  
42      @Override
43      public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
44          // Schedule the periodic timer for performing the policy check.
45          timerFuture = ctx.channel().eventLoop().scheduleWithFixedDelay(this,
46                  GARBAGE_COLLECTION_INTERVAL,
47                  GARBAGE_COLLECTION_INTERVAL,
48                  NANOSECONDS);
49      }
50  
51      @Override
52      public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
53          // Cancel the periodic timer.
54          if (timerFuture != null) {
55              timerFuture.cancel(false);
56              timerFuture = null;
57          }
58      }
59  
60      @Override
61      public void setAction(Action action) {
62          this.action = action;
63      }
64  
65      @Override
66      public void markForRemoval(Http2Stream stream) {
67          garbage.add(new Garbage(stream));
68      }
69  
70      /**
71       * Runs garbage collection of any streams marked for removal >
72       * {@link #GARBAGE_COLLECTION_INTERVAL} nanoseconds ago.
73       */
74      @Override
75      public void run() {
76          if (garbage.isEmpty() || action == null) {
77              return;
78          }
79  
80          long time = System.nanoTime();
81          for (;;) {
82              Garbage next = garbage.peek();
83              if (next == null) {
84                  break;
85              }
86              if (time - next.removalTime > GARBAGE_COLLECTION_INTERVAL) {
87                  garbage.remove();
88                  action.removeStream(next.stream);
89              } else {
90                  break;
91              }
92          }
93      }
94  
95      /**
96       * Wrapper around a stream and its removal time.
97       */
98      private static final class Garbage {
99          private final long removalTime = System.nanoTime();
100         private final Http2Stream stream;
101 
102         Garbage(Http2Stream stream) {
103             this.stream = stream;
104         }
105     }
106 }