View Javadoc

1   /**
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
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
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.
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 }