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<>( 044 new ObjectPool.ObjectFactory<String, Object>() { 045 @Override 046 public Object createObject(String key) { 047 return new Object(); 048 } 049 }); 050 } 051 052 @Test 053 public void testKeys() { 054 Object obj1 = pool.get("a"); 055 Object obj2 = pool.get(new String("a")); 056 057 Assert.assertSame(obj1, obj2); 058 059 Object obj3 = pool.get("b"); 060 061 Assert.assertNotSame(obj1, obj3); 062 } 063 064 @Test 065 public void testWeakReference() throws Exception { 066 Object obj1 = pool.get("a"); 067 int hash1 = System.identityHashCode(obj1); 068 069 System.gc(); 070 System.gc(); 071 System.gc(); 072 073 Thread.sleep(10); 074 // Sleep a while because references newly becoming stale 075 // may still remain when calling the {@code purge} method. 076 pool.purge(); 077 Assert.assertEquals(1, pool.size()); 078 079 Object obj2 = pool.get("a"); 080 Assert.assertSame(obj1, obj2); 081 082 obj1 = null; 083 obj2 = null; 084 085 System.gc(); 086 System.gc(); 087 System.gc(); 088 089 Thread.sleep(10); 090 pool.purge(); 091 Assert.assertEquals(0, pool.size()); 092 093 Object obj3 = pool.get("a"); 094 Assert.assertNotEquals(hash1, System.identityHashCode(obj3)); 095 } 096 097 @Test 098 public void testCongestion() throws Exception { 099 final int THREAD_COUNT = 100; 100 101 final AtomicBoolean assertionFailed = new AtomicBoolean(); 102 final AtomicReference<Object> expectedObjRef = new AtomicReference<>(); 103 final CountDownLatch prepareLatch = new CountDownLatch(THREAD_COUNT); 104 final CountDownLatch startLatch = new CountDownLatch(1); 105 final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); 106 107 for (int i=0; i<THREAD_COUNT; i++) { 108 new Thread() { 109 @Override 110 public void run() { 111 prepareLatch.countDown(); 112 try { 113 startLatch.await(); 114 115 Object obj = pool.get("a"); 116 if (! expectedObjRef.compareAndSet(null, obj)) { 117 if (expectedObjRef.get() != obj) { 118 assertionFailed.set(true); 119 } 120 } 121 } catch (Exception e) { 122 assertionFailed.set(true); 123 124 } finally { 125 endLatch.countDown(); 126 } 127 } 128 }.start(); 129 } 130 131 prepareLatch.await(); 132 startLatch.countDown(); 133 endLatch.await(); 134 135 if (assertionFailed.get()) { 136 Assert.fail(); 137 } 138 } 139}