/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.apache.hadoop.hbase.util; import java.util.Random; import java.util.TreeMap; import org.apache.hadoop.hbase.testclassification.SmallTests; import org.apache.hadoop.hbase.testclassification.MiscTests; import org.apache.hadoop.hbase.util.AvlUtil.AvlKeyComparator; import org.apache.hadoop.hbase.util.AvlUtil.AvlIterableList; import org.apache.hadoop.hbase.util.AvlUtil.AvlLinkedNode; import org.apache.hadoop.hbase.util.AvlUtil.AvlNode; import org.apache.hadoop.hbase.util.AvlUtil.AvlNodeVisitor; import org.apache.hadoop.hbase.util.AvlUtil.AvlTree; import org.apache.hadoop.hbase.util.AvlUtil.AvlTreeIterator; import org.junit.Test; import org.junit.experimental.categories.Category; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @Category({MiscTests.class, SmallTests.class}) public class TestAvlUtil { private static final TestAvlKeyComparator KEY_COMPARATOR = new TestAvlKeyComparator(); @Test public void testAvlTreeCrud() { final int MAX_KEY = 99999999; final int NELEM = 10000; final TreeMap<Integer, Object> treeMap = new TreeMap<>(); TestAvlNode root = null; final Random rand = new Random(); for (int i = 0; i < NELEM; ++i) { int key = rand.nextInt(MAX_KEY); if (AvlTree.get(root, key, KEY_COMPARATOR) != null) { i--; continue; } root = AvlTree.insert(root, new TestAvlNode(key)); treeMap.put(key, null); for (Integer keyX: treeMap.keySet()) { TestAvlNode node = AvlTree.get(root, keyX, KEY_COMPARATOR); assertNotNull(node); assertEquals(keyX.intValue(), node.getKey()); } } for (int i = 0; i < NELEM; ++i) { int key = rand.nextInt(MAX_KEY); TestAvlNode node = AvlTree.get(root, key, KEY_COMPARATOR); if (!treeMap.containsKey(key)) { assert node == null; continue; } treeMap.remove(key); assertEquals(key, node.getKey()); root = AvlTree.remove(root, key, KEY_COMPARATOR); for (Integer keyX: treeMap.keySet()) { node = AvlTree.get(root, keyX, KEY_COMPARATOR); assertNotNull(node); assertEquals(keyX.intValue(), node.getKey()); } } } @Test public void testAvlTreeVisitor() { final int MIN_KEY = 0; final int MAX_KEY = 50; TestAvlNode root = null; for (int i = MAX_KEY; i >= MIN_KEY; --i) { root = AvlTree.insert(root, new TestAvlNode(i)); } AvlTree.visit(root, new AvlNodeVisitor<TestAvlNode>() { private int prevKey = -1; public boolean visitNode(TestAvlNode node) { assertEquals(prevKey, node.getKey() - 1); assertTrue(node.getKey() >= MIN_KEY); assertTrue(node.getKey() <= MAX_KEY); prevKey = node.getKey(); return node.getKey() <= MAX_KEY; } }); } @Test public void testAvlTreeIterSeekFirst() { final int MIN_KEY = 1; final int MAX_KEY = 50; TestAvlNode root = null; for (int i = MIN_KEY; i < MAX_KEY; ++i) { root = AvlTree.insert(root, new TestAvlNode(i)); } AvlTreeIterator<TestAvlNode> iter = new AvlTreeIterator<>(root); assertTrue(iter.hasNext()); long prevKey = 0; while (iter.hasNext()) { TestAvlNode node = iter.next(); assertEquals(prevKey + 1, node.getKey()); prevKey = node.getKey(); } assertEquals(MAX_KEY - 1, prevKey); } @Test public void testAvlTreeIterSeekTo() { final int MIN_KEY = 1; final int MAX_KEY = 50; TestAvlNode root = null; for (int i = MIN_KEY; i < MAX_KEY; i += 2) { root = AvlTree.insert(root, new TestAvlNode(i)); } for (int i = MIN_KEY - 1; i < MAX_KEY + 1; ++i) { AvlTreeIterator<TestAvlNode> iter = new AvlTreeIterator<>(root, i, KEY_COMPARATOR); if (i < MAX_KEY) { assertTrue(iter.hasNext()); } else { // searching for something greater than the last node assertFalse(iter.hasNext()); break; } TestAvlNode node = iter.next(); assertEquals((i % 2 == 0) ? i + 1 : i, node.getKey()); long prevKey = node.getKey(); while (iter.hasNext()) { node = iter.next(); assertTrue(node.getKey() > prevKey); prevKey = node.getKey(); } } } @Test public void testAvlIterableListCrud() { final int NITEMS = 10; TestLinkedAvlNode prependHead = null; TestLinkedAvlNode appendHead = null; // prepend()/append() for (int i = 0; i <= NITEMS; ++i) { TestLinkedAvlNode pNode = new TestLinkedAvlNode(i); assertFalse(AvlIterableList.isLinked(pNode)); prependHead = AvlIterableList.prepend(prependHead, pNode); assertTrue(AvlIterableList.isLinked(pNode)); TestLinkedAvlNode aNode = new TestLinkedAvlNode(i); assertFalse(AvlIterableList.isLinked(aNode)); appendHead = AvlIterableList.append(appendHead, aNode); assertTrue(AvlIterableList.isLinked(aNode)); } // readNext() TestLinkedAvlNode pNode = prependHead; TestLinkedAvlNode aNode = appendHead; for (int i = 0; i <= NITEMS; ++i) { assertEquals(NITEMS - i, pNode.getKey()); pNode = AvlIterableList.readNext(pNode); assertEquals(i, aNode.getKey()); aNode = AvlIterableList.readNext(aNode); } // readPrev() pNode = AvlIterableList.readPrev(prependHead); aNode = AvlIterableList.readPrev(appendHead); for (int i = 0; i <= NITEMS; ++i) { assertEquals(i, pNode.getKey()); pNode = AvlIterableList.readPrev(pNode); assertEquals(NITEMS - i, aNode.getKey()); aNode = AvlIterableList.readPrev(aNode); } // appendList() TestLinkedAvlNode node = AvlIterableList.appendList(prependHead, appendHead); for (int i = NITEMS; i >= 0; --i) { assertEquals(i, node.getKey()); node = AvlIterableList.readNext(node); } for (int i = 0; i <= NITEMS; ++i) { assertEquals(i, node.getKey()); node = AvlIterableList.readNext(node); } } private static class TestAvlNode extends AvlNode<TestAvlNode> { private final int key; public TestAvlNode(int key) { this.key = key; } public int getKey() { return key; } @Override public int compareTo(TestAvlNode other) { return this.key - other.key; } @Override public String toString() { return String.format("TestAvlNode(%d)", key); } } private static class TestLinkedAvlNode extends AvlLinkedNode<TestLinkedAvlNode> { private final int key; public TestLinkedAvlNode(int key) { this.key = key; } public int getKey() { return key; } @Override public int compareTo(TestLinkedAvlNode other) { return this.key - other.key; } @Override public String toString() { return String.format("TestLinkedAvlNode(%d)", key); } } private static class TestAvlKeyComparator implements AvlKeyComparator<TestAvlNode> { public int compareKey(TestAvlNode node, Object key) { return node.getKey() - (int)key; } } }