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.util.concurrent.CountDownLatch; 021import java.util.concurrent.atomic.AtomicBoolean; 022import java.util.concurrent.atomic.AtomicReference; 023import org.apache.hadoop.hbase.HBaseClassTestRule; 024import org.apache.hadoop.hbase.testclassification.MiscTests; 025import org.apache.hadoop.hbase.testclassification.SmallTests; 026import org.junit.Assert; 027import org.junit.Before; 028import org.junit.ClassRule; 029import org.junit.Test; 030import org.junit.experimental.categories.Category; 031 032@Category({ MiscTests.class, SmallTests.class }) 033public class TestWeakObjectPool { 034 035 @ClassRule 036 public static final HBaseClassTestRule CLASS_RULE = 037 HBaseClassTestRule.forClass(TestWeakObjectPool.class); 038 039 ObjectPool<String, Object> pool; 040 041 @Before 042 public void setUp() { 043 pool = new WeakObjectPool<>(new ObjectPool.ObjectFactory<String, Object>() { 044 @Override 045 public Object createObject(String key) { 046 return new Object(); 047 } 048 }); 049 } 050 051 @Test 052 public void testKeys() { 053 Object obj1 = pool.get("a"); 054 Object obj2 = pool.get(new String("a")); 055 056 Assert.assertSame(obj1, obj2); 057 058 Object obj3 = pool.get("b"); 059 060 Assert.assertNotSame(obj1, obj3); 061 } 062 063 @Test 064 public void testWeakReference() throws Exception { 065 Object obj1 = pool.get("a"); 066 int hash1 = System.identityHashCode(obj1); 067 068 System.gc(); 069 System.gc(); 070 System.gc(); 071 072 Thread.sleep(10); 073 // Sleep a while because references newly becoming stale 074 // may still remain when calling the {@code purge} method. 075 pool.purge(); 076 Assert.assertEquals(1, pool.size()); 077 078 Object obj2 = pool.get("a"); 079 Assert.assertSame(obj1, obj2); 080 081 obj1 = null; 082 obj2 = null; 083 084 System.gc(); 085 System.gc(); 086 System.gc(); 087 088 Thread.sleep(10); 089 pool.purge(); 090 Assert.assertEquals(0, pool.size()); 091 092 Object obj3 = pool.get("a"); 093 Assert.assertNotEquals(hash1, System.identityHashCode(obj3)); 094 } 095 096 @Test 097 public void testCongestion() throws Exception { 098 final int THREAD_COUNT = 100; 099 100 final AtomicBoolean assertionFailed = new AtomicBoolean(); 101 final AtomicReference<Object> expectedObjRef = new AtomicReference<>(); 102 final CountDownLatch prepareLatch = new CountDownLatch(THREAD_COUNT); 103 final CountDownLatch startLatch = new CountDownLatch(1); 104 final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); 105 106 for (int i = 0; i < THREAD_COUNT; i++) { 107 new Thread() { 108 @Override 109 public void run() { 110 prepareLatch.countDown(); 111 try { 112 startLatch.await(); 113 114 Object obj = pool.get("a"); 115 if (!expectedObjRef.compareAndSet(null, obj)) { 116 if (expectedObjRef.get() != obj) { 117 assertionFailed.set(true); 118 } 119 } 120 } catch (Exception e) { 121 assertionFailed.set(true); 122 123 } finally { 124 endLatch.countDown(); 125 } 126 } 127 }.start(); 128 } 129 130 prepareLatch.await(); 131 startLatch.countDown(); 132 endLatch.await(); 133 134 if (assertionFailed.get()) { 135 Assert.fail(); 136 } 137 } 138}