001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.nio;
019
020import com.google.errorprone.annotations.RestrictedApi;
021import org.apache.hadoop.hbase.io.ByteBuffAllocator;
022import org.apache.hadoop.hbase.io.ByteBuffAllocator.Recycler;
023import org.apache.yetus.audience.InterfaceAudience;
024
025import org.apache.hbase.thirdparty.io.netty.util.AbstractReferenceCounted;
026import org.apache.hbase.thirdparty.io.netty.util.ReferenceCounted;
027import org.apache.hbase.thirdparty.io.netty.util.ResourceLeakDetector;
028import org.apache.hbase.thirdparty.io.netty.util.ResourceLeakDetectorFactory;
029import org.apache.hbase.thirdparty.io.netty.util.ResourceLeakTracker;
030
031/**
032 * Maintain an reference count integer inside to track life cycle of {@link ByteBuff}, if the
033 * reference count become 0, it'll call {@link Recycler#free()} exactly once.
034 */
035@InterfaceAudience.Private
036public class RefCnt extends AbstractReferenceCounted {
037
038  private static final ResourceLeakDetector<RefCnt> detector =
039    ResourceLeakDetectorFactory.instance().newResourceLeakDetector(RefCnt.class);
040  private final Recycler recycler;
041  private final ResourceLeakTracker<RefCnt> leak;
042
043  /**
044   * Create an {@link RefCnt} with an initial reference count = 1. If the reference count become
045   * zero, the recycler will do nothing. Usually, an Heap {@link ByteBuff} will use this kind of
046   * refCnt to track its life cycle, it help to abstract the code path although it's not really
047   * needed to track on heap ByteBuff.
048   */
049  public static RefCnt create() {
050    return new RefCnt(ByteBuffAllocator.NONE);
051  }
052
053  public static RefCnt create(Recycler recycler) {
054    return new RefCnt(recycler);
055  }
056
057  public RefCnt(Recycler recycler) {
058    this.recycler = recycler;
059    this.leak = recycler == ByteBuffAllocator.NONE ? null : detector.track(this);
060  }
061
062  @Override
063  public ReferenceCounted retain() {
064    maybeRecord();
065    return super.retain();
066  }
067
068  @Override
069  public ReferenceCounted retain(int increment) {
070    maybeRecord();
071    return super.retain(increment);
072  }
073
074  @Override
075  public boolean release() {
076    maybeRecord();
077    return super.release();
078  }
079
080  @Override
081  public boolean release(int decrement) {
082    maybeRecord();
083    return super.release(decrement);
084  }
085
086  @Override
087  protected final void deallocate() {
088    this.recycler.free();
089    if (leak != null) {
090      this.leak.close(this);
091    }
092  }
093
094  @Override
095  public RefCnt touch() {
096    maybeRecord();
097    return this;
098  }
099
100  @Override
101  public final ReferenceCounted touch(Object hint) {
102    maybeRecord(hint);
103    return this;
104  }
105
106  @RestrictedApi(explanation = "Should only be called in tests", link = "",
107      allowedOnPath = ".*/src/test/.*")
108  public Recycler getRecycler() {
109    return recycler;
110  }
111
112  private void maybeRecord() {
113    maybeRecord(null);
114  }
115
116  private void maybeRecord(Object hint) {
117    if (leak != null) {
118      leak.record(hint);
119    }
120  }
121}