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}