/**
* 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.regionserver.wal;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Random;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Tests LRUDictionary
*/
@Category(SmallTests.class)
public class TestLRUDictionary {
LRUDictionary testee;
@Before
public void setUp() throws Exception {
testee = new LRUDictionary();
}
@Test
public void TestContainsNothing() {
assertTrue(isDictionaryEmpty(testee));
}
/**
* Assert can't add empty array.
*/
@Test
public void testPassingEmptyArrayToFindEntry() {
assertEquals(Dictionary.NOT_IN_DICTIONARY,
testee.findEntry(HConstants.EMPTY_BYTE_ARRAY, 0, 0));
assertEquals(Dictionary.NOT_IN_DICTIONARY,
testee.addEntry(HConstants.EMPTY_BYTE_ARRAY, 0, 0));
}
@Test
public void testPassingSameArrayToAddEntry() {
// Add random predefined byte array, in this case a random byte array from
// HConstants. Assert that when we add, we get new index. Thats how it
// works.
int len = HConstants.CATALOG_FAMILY.length;
int index = testee.addEntry(HConstants.CATALOG_FAMILY, 0, len);
assertFalse(index == testee.addEntry(HConstants.CATALOG_FAMILY, 0, len));
assertFalse(index == testee.addEntry(HConstants.CATALOG_FAMILY, 0, len));
}
@Test
public void testBasic() {
Random rand = new Random();
byte[] testBytes = new byte[10];
rand.nextBytes(testBytes);
// Verify that our randomly generated array doesn't exist in the dictionary
assertEquals(testee.findEntry(testBytes, 0, testBytes.length), -1);
// now since we looked up an entry, we should have added it to the
// dictionary, so it isn't empty
assertFalse(isDictionaryEmpty(testee));
// Check if we can find it using findEntry
short t = testee.findEntry(testBytes, 0, testBytes.length);
// Making sure we do find what we're looking for
assertTrue(t != -1);
byte[] testBytesCopy = new byte[20];
Bytes.putBytes(testBytesCopy, 10, testBytes, 0, testBytes.length);
// copy byte arrays, make sure that we check that equal byte arrays are
// equal without just checking the reference
assertEquals(testee.findEntry(testBytesCopy, 10, testBytes.length), t);
// make sure the entry retrieved is the same as the one put in
assertTrue(Arrays.equals(testBytes, testee.getEntry(t)));
testee.clear();
// making sure clear clears the dictionary
assertTrue(isDictionaryEmpty(testee));
}
@Test
public void TestLRUPolicy(){
//start by filling the dictionary up with byte arrays
for (int i = 0; i < LRUDictionary.BidirectionalLRUMap.MAX_SIZE; i++) {
testee.findEntry((BigInteger.valueOf(i)).toByteArray(), 0,
(BigInteger.valueOf(i)).toByteArray().length);
}
// check we have the first element added
assertTrue(testee.findEntry(BigInteger.ZERO.toByteArray(), 0,
BigInteger.ZERO.toByteArray().length) != -1);
// check for an element we know isn't there
assertTrue(testee.findEntry(BigInteger.valueOf(Integer.MAX_VALUE).toByteArray(), 0,
BigInteger.valueOf(Integer.MAX_VALUE).toByteArray().length) == -1);
// since we just checked for this element, it should be there now.
assertTrue(testee.findEntry(BigInteger.valueOf(Integer.MAX_VALUE).toByteArray(), 0,
BigInteger.valueOf(Integer.MAX_VALUE).toByteArray().length) != -1);
// test eviction, that the least recently added or looked at element is
// evicted. We looked at ZERO so it should be in the dictionary still.
assertTrue(testee.findEntry(BigInteger.ZERO.toByteArray(), 0,
BigInteger.ZERO.toByteArray().length) != -1);
// Now go from beyond 1 to the end.
for(int i = 1; i < LRUDictionary.BidirectionalLRUMap.MAX_SIZE; i++) {
assertTrue(testee.findEntry(BigInteger.valueOf(i).toByteArray(), 0,
BigInteger.valueOf(i).toByteArray().length) == -1);
}
// check we can find all of these.
for (int i = 0; i < LRUDictionary.BidirectionalLRUMap.MAX_SIZE; i++) {
assertTrue(testee.findEntry(BigInteger.valueOf(i).toByteArray(), 0,
BigInteger.valueOf(i).toByteArray().length) != -1);
}
}
static private boolean isDictionaryEmpty(LRUDictionary dict) {
try {
dict.getEntry((short)0);
return false;
} catch (IndexOutOfBoundsException ioobe) {
return true;
}
}
}