1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.types;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25
26 import java.util.Map;
27 import java.util.concurrent.ConcurrentNavigableMap;
28 import java.util.concurrent.ConcurrentSkipListMap;
29 import java.util.concurrent.ThreadLocalRandom;
30
31 import org.apache.hadoop.hbase.testclassification.SmallTests;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.experimental.categories.Category;
35
36 @Category(SmallTests.class)
37 public class TestCopyOnWriteMaps {
38 private static final int MAX_RAND = 10 * 1000 * 1000;
39 private ConcurrentNavigableMap<Long, Long> m;
40 private ConcurrentSkipListMap<Long, Long> csm;
41
42 @Before
43 public void setUp() {
44 m = new CopyOnWriteArrayMap<>();
45 csm = new ConcurrentSkipListMap<>();
46
47 for (long i = 0 ; i < 10000; i++) {
48 long o = ThreadLocalRandom.current().nextLong(MAX_RAND);
49 m.put(i, o);
50 csm.put(i,o);
51 }
52 long o = ThreadLocalRandom.current().nextLong(MAX_RAND);
53 m.put(0L, o);
54 csm.put(0L,o);
55 }
56
57 @Test
58 public void testSize() {
59 assertEquals("Size should always be equal", m.size(), csm.size());
60 }
61
62 @Test
63 public void testIsEmpty() {
64 m.clear();
65 assertTrue(m.isEmpty());
66 m.put(100L, 100L);
67 assertFalse(m.isEmpty());
68 m.remove(100L);
69 assertTrue(m.isEmpty());
70 }
71
72 @Test
73 public void testFindOnEmpty() {
74 m.clear();
75 assertTrue(m.isEmpty());
76 assertNull(m.get(100L));
77 assertFalse(m.containsKey(100L));
78 assertEquals(0, m.tailMap(100L).entrySet().size());
79 }
80
81 @Test
82 public void testLowerKey() {
83 assertEquals(csm.lowerKey(400L), m.lowerKey(400L));
84 assertEquals(csm.lowerKey(-1L), m.lowerKey(-1L));
85
86 for (int i = 0 ; i < 100; i++) {
87 Long key = ThreadLocalRandom.current().nextLong();
88 assertEquals(csm.lowerKey(key), m.lowerKey(key));
89 }
90 }
91
92 @Test
93 public void testFloorEntry() {
94 for (int i = 0 ; i < 100; i++) {
95 Long key = ThreadLocalRandom.current().nextLong();
96 assertEquals(csm.floorEntry(key), m.floorEntry(key));
97 }
98 }
99
100 @Test
101 public void testFloorKey() {
102 for (int i = 0 ; i < 100; i++) {
103 Long key = ThreadLocalRandom.current().nextLong();
104 assertEquals(csm.floorKey(key), m.floorKey(key));
105 }
106 }
107
108 @Test
109 public void testCeilingKey() {
110 assertEquals(csm.ceilingKey(4000L), m.ceilingKey(4000L));
111 assertEquals(csm.ceilingKey(400L), m.ceilingKey(400L));
112 assertEquals(csm.ceilingKey(-1L), m.ceilingKey(-1L));
113
114 for (int i = 0 ; i < 100; i++) {
115 Long key = ThreadLocalRandom.current().nextLong();
116 assertEquals(csm.ceilingKey(key), m.ceilingKey(key));
117 }
118 }
119
120 @Test
121 public void testHigherKey() {
122 assertEquals(csm.higherKey(4000L), m.higherKey(4000L));
123 assertEquals(csm.higherKey(400L), m.higherKey(400L));
124 assertEquals(csm.higherKey(-1L), m.higherKey(-1L));
125
126 for (int i = 0 ; i < 100; i++) {
127 Long key = ThreadLocalRandom.current().nextLong();
128 assertEquals(csm.higherKey(key), m.higherKey(key));
129 }
130 }
131
132 @Test
133 public void testRemove() {
134 for (Map.Entry<Long, Long> e : csm.entrySet()) {
135 assertEquals(csm.remove(e.getKey()), m.remove(e.getKey()));
136 assertNull(m.remove(e.getKey()));
137 }
138 }
139
140 @Test
141 public void testReplace() {
142 for (Map.Entry<Long, Long> e : csm.entrySet()) {
143 Long newValue = ThreadLocalRandom.current().nextLong();
144 assertEquals(csm.replace(e.getKey(), newValue), m.replace(e.getKey(), newValue));
145 }
146 assertNull(m.replace(MAX_RAND + 100L, ThreadLocalRandom.current().nextLong()));
147 }
148
149 @Test
150 public void testReplace1() {
151 for (Map.Entry<Long, Long> e : csm.entrySet()) {
152 Long newValue = ThreadLocalRandom.current().nextLong();
153 assertEquals(csm.replace(e.getKey(), e.getValue() + 1, newValue),
154 m.replace(e.getKey(), e.getValue() + 1, newValue));
155 assertEquals(csm.replace(e.getKey(), e.getValue(), newValue),
156 m.replace(e.getKey(), e.getValue(), newValue));
157 assertEquals(newValue, m.get(e.getKey()));
158 assertEquals(csm.get(e.getKey()), m.get(e.getKey()));
159 }
160 assertNull(m.replace(MAX_RAND + 100L, ThreadLocalRandom.current().nextLong()));
161 }
162
163 @Test
164 public void testMultiAdd() throws InterruptedException {
165 Thread[] threads = new Thread[10];
166 for (int i = 0 ; i < threads.length; i++) {
167 threads[i] = new Thread(new Runnable() {
168 @Override
169 public void run() {
170 for (int j = 0; j < 5000; j++) {
171 m.put(ThreadLocalRandom.current().nextLong(),
172 ThreadLocalRandom.current().nextLong());
173 }
174 }
175 });
176 }
177
178 for (Thread thread1 : threads) {
179 thread1.start();
180 }
181
182 for (Thread thread2 : threads) {
183 thread2.join();
184 }
185 }
186
187 @Test
188 public void testFirstKey() {
189 assertEquals(csm.firstKey(), m.firstKey());
190 }
191
192 @Test
193 public void testLastKey() {
194 assertEquals(csm.lastKey(), m.lastKey());
195 }
196
197 @Test
198 public void testFirstEntry() {
199 assertEquals(csm.firstEntry().getKey(), m.firstEntry().getKey());
200 assertEquals(csm.firstEntry().getValue(), m.firstEntry().getValue());
201 assertEquals(csm.firstEntry(), m.firstEntry());
202 }
203
204 @Test
205 public void testLastEntry() {
206 assertEquals(csm.lastEntry().getKey(), m.lastEntry().getKey());
207 assertEquals(csm.lastEntry().getValue(), m.lastEntry().getValue());
208 assertEquals(csm.lastEntry(), m.lastEntry());
209 }
210
211 @Test
212 public void testKeys() {
213 for (Long key : csm.keySet()) {
214 assertNotNull(m.get(key));
215 assertNotNull(m.remove(key));
216 assertNull(m.get(key));
217 }
218 }
219
220 @Test
221 public void testValues() {
222 for (Long value : m.values()) {
223 assertTrue(csm.containsValue(value));
224 assertTrue(m.containsValue(value));
225 }
226 }
227
228 @Test
229 public void testTailMap() {
230 Map<Long, Long> fromCsm = csm.tailMap(50L);
231 Map<Long, Long> fromM = m.tailMap(50L);
232 assertEquals(fromCsm, fromM);
233 for (Long value : m.keySet()) {
234 assertEquals(csm.tailMap(value), m.tailMap(value));
235 }
236
237 for (long i = 0; i < 100; i++) {
238 long o = ThreadLocalRandom.current().nextLong(MAX_RAND);
239 assertEquals(csm.tailMap(o), m.tailMap(o));
240 }
241 }
242
243 @Test
244 public void testTailMapExclusive() {
245 m.clear();
246 m.put(100L, 100L);
247 m.put(101L, 101L);
248 m.put(101L, 101L);
249 m.put(103L, 103L);
250 m.put(99L, 99L);
251 m.put(102L, 102L);
252
253 long n = 100L;
254 CopyOnWriteArrayMap<Long,Long> tm99 = (CopyOnWriteArrayMap<Long, Long>) m.tailMap(99L, false);
255 for (Map.Entry<Long,Long> e : tm99.entrySet()) {
256 assertEquals(new Long(n), e.getKey());
257 assertEquals(new Long(n), e.getValue());
258 n++;
259 }
260 }
261
262 @Test
263 public void testTailMapInclusive() {
264 m.clear();
265 m.put(100L, 100L);
266 m.put(101L, 101L);
267 m.put(101L, 101L);
268 m.put(103L, 103L);
269 m.put(99L, 99L);
270 m.put(102L, 102L);
271
272 long n = 102;
273 CopyOnWriteArrayMap<Long,Long> tm102 = (CopyOnWriteArrayMap<Long, Long>) m.tailMap(102L, true);
274 for (Map.Entry<Long,Long> e : tm102.entrySet()) {
275 assertEquals(new Long(n), e.getKey());
276 assertEquals(new Long(n), e.getValue());
277 n++;
278 }
279 n = 99;
280 CopyOnWriteArrayMap<Long,Long> tm98 = (CopyOnWriteArrayMap<Long, Long>) m.tailMap(98L, true);
281 for (Map.Entry<Long,Long> e : tm98.entrySet()) {
282 assertEquals(new Long(n), e.getKey());
283 assertEquals(new Long(n), e.getValue());
284 n++;
285 }
286 }
287
288 @Test
289 public void testPut() {
290 m.clear();
291 m.put(100L, 100L);
292 m.put(101L, 101L);
293 m.put(101L, 101L);
294 m.put(103L, 103L);
295 m.put(99L, 99L);
296 m.put(102L, 102L);
297 long n = 99;
298
299 for (Map.Entry<Long, Long> e : m.entrySet()) {
300 assertEquals(new Long(n), e.getKey());
301 assertEquals(new Long(n), e.getValue());
302 n++;
303 }
304 assertEquals(5, m.size());
305 assertFalse(m.isEmpty());
306 }
307 }