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