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 static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertTrue; 024import java.util.Random; 025import java.util.TreeMap; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.testclassification.MediumTests; 028import org.apache.hadoop.hbase.testclassification.MiscTests; 029import org.apache.hadoop.hbase.util.AvlUtil.AvlIterableList; 030import org.apache.hadoop.hbase.util.AvlUtil.AvlKeyComparator; 031import org.apache.hadoop.hbase.util.AvlUtil.AvlLinkedNode; 032import org.apache.hadoop.hbase.util.AvlUtil.AvlNode; 033import org.apache.hadoop.hbase.util.AvlUtil.AvlNodeVisitor; 034import org.apache.hadoop.hbase.util.AvlUtil.AvlTree; 035import org.apache.hadoop.hbase.util.AvlUtil.AvlTreeIterator; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039 040@Category({MiscTests.class, MediumTests.class}) 041public class TestAvlUtil { 042 043 @ClassRule 044 public static final HBaseClassTestRule CLASS_RULE = 045 HBaseClassTestRule.forClass(TestAvlUtil.class); 046 047 private static final TestAvlKeyComparator KEY_COMPARATOR = new TestAvlKeyComparator(); 048 049 @Test 050 public void testAvlTreeCrud() { 051 final int MAX_KEY = 99999999; 052 final int NELEM = 10000; 053 054 final TreeMap<Integer, Object> treeMap = new TreeMap<>(); 055 TestAvlNode root = null; 056 057 final Random rand = new Random(); 058 for (int i = 0; i < NELEM; ++i) { 059 int key = rand.nextInt(MAX_KEY); 060 if (AvlTree.get(root, key, KEY_COMPARATOR) != null) { 061 i--; 062 continue; 063 } 064 root = AvlTree.insert(root, new TestAvlNode(key)); 065 treeMap.put(key, null); 066 for (Integer keyX: treeMap.keySet()) { 067 TestAvlNode node = AvlTree.get(root, keyX, KEY_COMPARATOR); 068 assertNotNull(node); 069 assertEquals(keyX.intValue(), node.getKey()); 070 } 071 } 072 073 for (int i = 0; i < NELEM; ++i) { 074 int key = rand.nextInt(MAX_KEY); 075 TestAvlNode node = AvlTree.get(root, key, KEY_COMPARATOR); 076 if (!treeMap.containsKey(key)) { 077 assert node == null; 078 continue; 079 } 080 treeMap.remove(key); 081 assertEquals(key, node.getKey()); 082 root = AvlTree.remove(root, key, KEY_COMPARATOR); 083 for (Integer keyX: treeMap.keySet()) { 084 node = AvlTree.get(root, keyX, KEY_COMPARATOR); 085 assertNotNull(node); 086 assertEquals(keyX.intValue(), node.getKey()); 087 } 088 } 089 } 090 091 @Test 092 public void testAvlTreeVisitor() { 093 final int MIN_KEY = 0; 094 final int MAX_KEY = 50; 095 096 TestAvlNode root = null; 097 for (int i = MAX_KEY; i >= MIN_KEY; --i) { 098 root = AvlTree.insert(root, new TestAvlNode(i)); 099 } 100 101 AvlTree.visit(root, new AvlNodeVisitor<TestAvlNode>() { 102 private int prevKey = -1; 103 @Override 104 public boolean visitNode(TestAvlNode node) { 105 assertEquals(prevKey, node.getKey() - 1); 106 assertTrue(node.getKey() >= MIN_KEY); 107 assertTrue(node.getKey() <= MAX_KEY); 108 prevKey = node.getKey(); 109 return node.getKey() <= MAX_KEY; 110 } 111 }); 112 } 113 114 @Test 115 public void testAvlTreeIterSeekFirst() { 116 final int MIN_KEY = 1; 117 final int MAX_KEY = 50; 118 119 TestAvlNode root = null; 120 for (int i = MIN_KEY; i < MAX_KEY; ++i) { 121 root = AvlTree.insert(root, new TestAvlNode(i)); 122 } 123 124 AvlTreeIterator<TestAvlNode> iter = new AvlTreeIterator<>(root); 125 assertTrue(iter.hasNext()); 126 long prevKey = 0; 127 while (iter.hasNext()) { 128 TestAvlNode node = iter.next(); 129 assertEquals(prevKey + 1, node.getKey()); 130 prevKey = node.getKey(); 131 } 132 assertEquals(MAX_KEY - 1, prevKey); 133 } 134 135 @Test 136 public void testAvlTreeIterSeekTo() { 137 final int MIN_KEY = 1; 138 final int MAX_KEY = 50; 139 140 TestAvlNode root = null; 141 for (int i = MIN_KEY; i < MAX_KEY; i += 2) { 142 root = AvlTree.insert(root, new TestAvlNode(i)); 143 } 144 145 for (int i = MIN_KEY - 1; i < MAX_KEY + 1; ++i) { 146 AvlTreeIterator<TestAvlNode> iter = new AvlTreeIterator<>(root, i, KEY_COMPARATOR); 147 if (i < MAX_KEY) { 148 assertTrue(iter.hasNext()); 149 } else { 150 // searching for something greater than the last node 151 assertFalse(iter.hasNext()); 152 break; 153 } 154 155 TestAvlNode node = iter.next(); 156 assertEquals((i % 2 == 0) ? i + 1 : i, node.getKey()); 157 158 long prevKey = node.getKey(); 159 while (iter.hasNext()) { 160 node = iter.next(); 161 assertTrue(node.getKey() > prevKey); 162 prevKey = node.getKey(); 163 } 164 } 165 } 166 167 @Test 168 public void testAvlIterableListCrud() { 169 final int NITEMS = 10; 170 TestLinkedAvlNode prependHead = null; 171 TestLinkedAvlNode appendHead = null; 172 // prepend()/append() 173 for (int i = 0; i <= NITEMS; ++i) { 174 TestLinkedAvlNode pNode = new TestLinkedAvlNode(i); 175 assertFalse(AvlIterableList.isLinked(pNode)); 176 prependHead = AvlIterableList.prepend(prependHead, pNode); 177 assertTrue(AvlIterableList.isLinked(pNode)); 178 179 TestLinkedAvlNode aNode = new TestLinkedAvlNode(i); 180 assertFalse(AvlIterableList.isLinked(aNode)); 181 appendHead = AvlIterableList.append(appendHead, aNode); 182 assertTrue(AvlIterableList.isLinked(aNode)); 183 } 184 // readNext() 185 TestLinkedAvlNode pNode = prependHead; 186 TestLinkedAvlNode aNode = appendHead; 187 for (int i = 0; i <= NITEMS; ++i) { 188 assertEquals(NITEMS - i, pNode.getKey()); 189 pNode = AvlIterableList.readNext(pNode); 190 191 assertEquals(i, aNode.getKey()); 192 aNode = AvlIterableList.readNext(aNode); 193 } 194 // readPrev() 195 pNode = AvlIterableList.readPrev(prependHead); 196 aNode = AvlIterableList.readPrev(appendHead); 197 for (int i = 0; i <= NITEMS; ++i) { 198 assertEquals(i, pNode.getKey()); 199 pNode = AvlIterableList.readPrev(pNode); 200 201 assertEquals(NITEMS - i, aNode.getKey()); 202 aNode = AvlIterableList.readPrev(aNode); 203 } 204 // appendList() 205 TestLinkedAvlNode node = AvlIterableList.appendList(prependHead, appendHead); 206 for (int i = NITEMS; i >= 0; --i) { 207 assertEquals(i, node.getKey()); 208 node = AvlIterableList.readNext(node); 209 } 210 for (int i = 0; i <= NITEMS; ++i) { 211 assertEquals(i, node.getKey()); 212 node = AvlIterableList.readNext(node); 213 } 214 } 215 216 private static class TestAvlNode extends AvlNode<TestAvlNode> { 217 private final int key; 218 219 public TestAvlNode(int key) { 220 this.key = key; 221 } 222 223 public int getKey() { 224 return key; 225 } 226 227 @Override 228 public int compareTo(TestAvlNode other) { 229 return this.key - other.key; 230 } 231 232 @Override 233 public String toString() { 234 return String.format("TestAvlNode(%d)", key); 235 } 236 } 237 238 private static class TestLinkedAvlNode extends AvlLinkedNode<TestLinkedAvlNode> { 239 private final int key; 240 241 public TestLinkedAvlNode(int key) { 242 this.key = key; 243 } 244 245 public int getKey() { 246 return key; 247 } 248 249 @Override 250 public int compareTo(TestLinkedAvlNode other) { 251 return this.key - other.key; 252 } 253 254 @Override 255 public String toString() { 256 return String.format("TestLinkedAvlNode(%d)", key); 257 } 258 } 259 260 private static class TestAvlKeyComparator implements AvlKeyComparator<TestAvlNode> { 261 @Override 262 public int compareKey(TestAvlNode node, Object key) { 263 return node.getKey() - (int)key; 264 } 265 } 266}