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    *   https://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 java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
20  
21  import io.netty.util.internal.ReferenceCountUpdater;
22  
23  /**
24   * Abstract base class for {@link ByteBuf} implementations that count references.
25   */
26  public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
27      private static final long REFCNT_FIELD_OFFSET =
28              ReferenceCountUpdater.getUnsafeOffset(AbstractReferenceCountedByteBuf.class, "refCnt");
29      private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> AIF_UPDATER =
30              AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
31  
32      private static final ReferenceCountUpdater<AbstractReferenceCountedByteBuf> updater =
33              new ReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {
34          @Override
35          protected AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> updater() {
36              return AIF_UPDATER;
37          }
38          @Override
39          protected long unsafeOffset() {
40              return REFCNT_FIELD_OFFSET;
41          }
42      };
43  
44      // Value might not equal "real" reference count, all access should be via the updater
45      @SuppressWarnings({"unused", "FieldMayBeFinal"})
46      private volatile int refCnt;
47  
48      protected AbstractReferenceCountedByteBuf(int maxCapacity) {
49          super(maxCapacity);
50          updater.setInitialValue(this);
51      }
52  
53      @Override
54      boolean isAccessible() {
55          // Try to do non-volatile read for performance as the ensureAccessible() is racy anyway and only provide
56          // a best-effort guard.
57          return updater.isLiveNonVolatile(this);
58      }
59  
60      @Override
61      public int refCnt() {
62          return updater.refCnt(this);
63      }
64  
65      /**
66       * An unsafe operation intended for use by a subclass that sets the reference count of the buffer directly
67       */
68      protected final void setRefCnt(int refCnt) {
69          updater.setRefCnt(this, refCnt);
70      }
71  
72      /**
73       * An unsafe operation intended for use by a subclass that resets the reference count of the buffer to 1
74       */
75      protected final void resetRefCnt() {
76          updater.resetRefCnt(this);
77      }
78  
79      @Override
80      public ByteBuf retain() {
81          return updater.retain(this);
82      }
83  
84      @Override
85      public ByteBuf retain(int increment) {
86          return updater.retain(this, increment);
87      }
88  
89      @Override
90      public ByteBuf touch() {
91          return this;
92      }
93  
94      @Override
95      public ByteBuf touch(Object hint) {
96          return this;
97      }
98  
99      @Override
100     public boolean release() {
101         return handleRelease(updater.release(this));
102     }
103 
104     @Override
105     public boolean release(int decrement) {
106         return handleRelease(updater.release(this, decrement));
107     }
108 
109     private boolean handleRelease(boolean result) {
110         if (result) {
111             deallocate();
112         }
113         return result;
114     }
115 
116     /**
117      * Called once {@link #refCnt()} is equals 0.
118      */
119     protected abstract void deallocate();
120 }