2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.util
;
20 import static org
.junit
.Assert
.assertEquals
;
21 import static org
.junit
.Assert
.assertTrue
;
23 import java
.util
.Arrays
;
25 import java
.util
.Random
;
26 import java
.util
.concurrent
.Callable
;
27 import java
.util
.concurrent
.ConcurrentHashMap
;
28 import java
.util
.concurrent
.ExecutorCompletionService
;
29 import java
.util
.concurrent
.ExecutorService
;
30 import java
.util
.concurrent
.Executors
;
31 import java
.util
.concurrent
.Future
;
32 import java
.util
.concurrent
.TimeUnit
;
33 import java
.util
.concurrent
.locks
.Lock
;
34 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
35 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
36 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
37 import org
.apache
.hadoop
.hbase
.testclassification
.MiscTests
;
38 import org
.apache
.hadoop
.hbase
.util
.IdReadWriteLockWithObjectPool
.ReferenceType
;
39 import org
.junit
.ClassRule
;
40 import org
.junit
.Test
;
41 import org
.junit
.experimental
.categories
.Category
;
42 import org
.junit
.runner
.RunWith
;
43 import org
.junit
.runners
.Parameterized
;
44 import org
.slf4j
.Logger
;
45 import org
.slf4j
.LoggerFactory
;
47 @RunWith(Parameterized
.class)
48 @Category({MiscTests
.class, MediumTests
.class})
49 // Medium as it creates 100 threads; seems better to run it isolated
50 public class TestIdReadWriteLockWithObjectPool
{
53 public static final HBaseClassTestRule CLASS_RULE
=
54 HBaseClassTestRule
.forClass(TestIdReadWriteLockWithObjectPool
.class);
56 private static final Logger LOG
=
57 LoggerFactory
.getLogger(TestIdReadWriteLockWithObjectPool
.class);
59 private static final int NUM_IDS
= 16;
60 private static final int NUM_THREADS
= 128;
61 private static final int NUM_SECONDS
= 15;
63 @Parameterized.Parameter
64 public IdReadWriteLockWithObjectPool
<Long
> idLock
;
66 @Parameterized.Parameters
67 public static Iterable
<Object
[]> data() {
68 return Arrays
.asList(new Object
[][] {
69 { new IdReadWriteLockWithObjectPool
<Long
>(ReferenceType
.WEAK
) },
70 { new IdReadWriteLockWithObjectPool
<Long
>(ReferenceType
.SOFT
) } });
73 private Map
<Long
, String
> idOwner
= new ConcurrentHashMap
<>();
75 private class IdLockTestThread
implements Callable
<Boolean
> {
77 private String clientId
;
79 public IdLockTestThread(String clientId
) {
80 this.clientId
= clientId
;
84 public Boolean
call() throws Exception
{
85 Thread
.currentThread().setName(clientId
);
86 Random rand
= new Random();
87 long endTime
= EnvironmentEdgeManager
.currentTime() + NUM_SECONDS
* 1000;
88 while (EnvironmentEdgeManager
.currentTime() < endTime
) {
89 long id
= rand
.nextInt(NUM_IDS
);
90 boolean readLock
= rand
.nextBoolean();
92 ReentrantReadWriteLock readWriteLock
= idLock
.getLock(id
);
93 Lock lock
= readLock ? readWriteLock
.readLock() : readWriteLock
.writeLock();
96 int sleepMs
= 1 + rand
.nextInt(4);
97 String owner
= idOwner
.get(id
);
98 if (owner
!= null && LOG
.isDebugEnabled()) {
99 LOG
.debug((readLock ?
"Read" : "Write") + "lock of Id " + id
+ " already taken by "
100 + owner
+ ", we are " + clientId
);
103 idOwner
.put(id
, clientId
);
104 Thread
.sleep(sleepMs
);
109 if (LOG
.isDebugEnabled()) {
110 LOG
.debug("Release " + (readLock ?
"Read" : "Write") + " lock of Id" + id
+ ", we are "
121 public void testMultipleClients() throws Exception
{
122 ExecutorService exec
= Executors
.newFixedThreadPool(NUM_THREADS
);
124 ExecutorCompletionService
<Boolean
> ecs
= new ExecutorCompletionService
<>(exec
);
125 for (int i
= 0; i
< NUM_THREADS
; ++i
)
126 ecs
.submit(new IdLockTestThread("client_" + i
));
127 for (int i
= 0; i
< NUM_THREADS
; ++i
) {
128 Future
<Boolean
> result
= ecs
.take();
129 assertTrue(result
.get());
131 int entryPoolSize
= idLock
.purgeAndGetEntryPoolSize();
132 LOG
.debug("Size of entry pool after gc and purge: " + entryPoolSize
);
133 ReferenceType refType
= idLock
.getReferenceType();
136 // make sure the entry pool will be cleared after GC and purge call
137 assertEquals(0, entryPoolSize
);
140 // make sure the entry pool won't be cleared when JVM memory is enough
141 // even after GC and purge call
142 assertEquals(NUM_IDS
, entryPoolSize
);
149 exec
.awaitTermination(5000, TimeUnit
.MILLISECONDS
);