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.util; 019 020import java.lang.ref.Reference; 021import java.util.concurrent.locks.ReentrantReadWriteLock; 022import org.apache.yetus.audience.InterfaceAudience; 023 024@InterfaceAudience.Private 025public class IdReadWriteLockWithObjectPool<T> extends IdReadWriteLock<T> { 026 // The number of lock we want to easily support. It's not a maximum. 027 private static final int NB_CONCURRENT_LOCKS = 1000; 028 /** 029 * The pool to get entry from, entries are mapped by {@link Reference} and will be automatically 030 * garbage-collected by JVM 031 */ 032 private final ObjectPool<T, ReentrantReadWriteLock> lockPool; 033 private final ReferenceType refType; 034 035 public IdReadWriteLockWithObjectPool() { 036 this(ReferenceType.WEAK); 037 } 038 039 /** 040 * Constructor of IdReadWriteLockWithObjectPool 041 * @param referenceType type of the reference used in lock pool, {@link ReferenceType#WEAK} by 042 * default. Use {@link ReferenceType#SOFT} if the key set is limited and the 043 * locks will be reused with a high frequency 044 */ 045 public IdReadWriteLockWithObjectPool(ReferenceType referenceType) { 046 this.refType = referenceType; 047 switch (referenceType) { 048 case SOFT: 049 lockPool = new SoftObjectPool<>(new ObjectPool.ObjectFactory<T, ReentrantReadWriteLock>() { 050 @Override 051 public ReentrantReadWriteLock createObject(T id) { 052 return new ReentrantReadWriteLock(); 053 } 054 }, NB_CONCURRENT_LOCKS); 055 break; 056 case WEAK: 057 default: 058 lockPool = new WeakObjectPool<>(new ObjectPool.ObjectFactory<T, ReentrantReadWriteLock>() { 059 @Override 060 public ReentrantReadWriteLock createObject(T id) { 061 return new ReentrantReadWriteLock(); 062 } 063 }, NB_CONCURRENT_LOCKS); 064 } 065 } 066 067 public static enum ReferenceType { 068 WEAK, 069 SOFT 070 } 071 072 /** 073 * Get the ReentrantReadWriteLock corresponding to the given id 074 * @param id an arbitrary number to identify the lock 075 */ 076 @Override 077 public ReentrantReadWriteLock getLock(T id) { 078 lockPool.purge(); 079 ReentrantReadWriteLock readWriteLock = lockPool.get(id); 080 return readWriteLock; 081 } 082 083 /** For testing */ 084 int purgeAndGetEntryPoolSize() { 085 gc(); 086 Threads.sleep(200); 087 lockPool.purge(); 088 return lockPool.size(); 089 } 090 091 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "DM_GC", justification = "Intentional") 092 private void gc() { 093 System.gc(); 094 } 095 096 public ReferenceType getReferenceType() { 097 return this.refType; 098 } 099}