View Javadoc
1   /*
2    * Copyright 2013 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  
17  package io.netty.buffer;
18  
19  import io.netty.util.IllegalReferenceCountException;
20  
21  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
22  
23  import static io.netty.util.internal.ObjectUtil.checkPositive;
24  
25  /**
26   * Abstract base class for {@link ByteBuf} implementations that count references.
27   */
28  public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
29  
30      private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater =
31              AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
32  
33      private volatile int refCnt;
34  
35      protected AbstractReferenceCountedByteBuf(int maxCapacity) {
36          super(maxCapacity);
37          refCntUpdater.set(this, 1);
38      }
39  
40      @Override
41      public int refCnt() {
42          return refCnt;
43      }
44  
45      /**
46       * An unsafe operation intended for use by a subclass that sets the reference count of the buffer directly
47       */
48      protected final void setRefCnt(int refCnt) {
49          refCntUpdater.set(this, refCnt);
50      }
51  
52      @Override
53      public ByteBuf retain() {
54          return retain0(1);
55      }
56  
57      @Override
58      public ByteBuf retain(int increment) {
59          return retain0(checkPositive(increment, "increment"));
60      }
61  
62      private ByteBuf retain0(final int increment) {
63          int oldRef = refCntUpdater.getAndAdd(this, increment);
64          if (oldRef <= 0 || oldRef + increment < oldRef) {
65              // Ensure we don't resurrect (which means the refCnt was 0) and also that we encountered an overflow.
66              refCntUpdater.getAndAdd(this, -increment);
67              throw new IllegalReferenceCountException(oldRef, increment);
68          }
69          return this;
70      }
71  
72      @Override
73      public ByteBuf touch() {
74          return this;
75      }
76  
77      @Override
78      public ByteBuf touch(Object hint) {
79          return this;
80      }
81  
82      @Override
83      public boolean release() {
84          return release0(1);
85      }
86  
87      @Override
88      public boolean release(int decrement) {
89          return release0(checkPositive(decrement, "decrement"));
90      }
91  
92      private boolean release0(int decrement) {
93          int oldRef = refCntUpdater.getAndAdd(this, -decrement);
94          if (oldRef == decrement) {
95              deallocate();
96              return true;
97          } else if (oldRef < decrement || oldRef - decrement > oldRef) {
98              // Ensure we don't over-release, and avoid underflow.
99              refCntUpdater.getAndAdd(this, decrement);
100             throw new IllegalReferenceCountException(oldRef, -decrement);
101         }
102         return false;
103     }
104     /**
105      * Called once {@link #refCnt()} is equals 0.
106      */
107     protected abstract void deallocate();
108 }