/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Nov 27, 2006
*/
package com.bigdata.btree;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import org.apache.log4j.Level;
import com.bigdata.btree.keys.TestKeyBuilder;
import com.bigdata.io.SerializerUtil;
import com.bigdata.util.BytesUtil;
import cutthecrap.utils.striterators.Resolver;
import cutthecrap.utils.striterators.Striterator;
/**
* Test insert, lookup, and value scan for leaves.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestInsertLookupRemoveKeysInRootLeaf extends AbstractBTreeTestCase {
/**
*
*/
public TestInsertLookupRemoveKeysInRootLeaf() {
}
/**
* @param name
*/
public TestInsertLookupRemoveKeysInRootLeaf(String name) {
super(name);
}
/**
* Test ability to insert entries into a leaf. Random (legal) external keys
* are inserted into a leaf until the leaf would overflow. The random keys
* are then sorted and compared with the actual keys in the leaf. If the
* keys were inserted correctly into the leaf then the two arrays of keys
* will have the same values in the same order.
*/
public void test_insertKeyIntoLeaf01() {
final int branchingFactor = 20;
BTree btree = getBTree(branchingFactor);
Leaf root = (Leaf) btree.root;
// array of inserted keys.
byte[][] expectedKeys = new byte[branchingFactor][];
int nkeys = 0;
while( nkeys < branchingFactor ) {
// Valid random key.
byte[] key = new byte[3];
r.nextBytes(key);
int index = root.getKeys().search(key);
if( index >= 0 ) {
/*
* The key is already present in the leaf.
*/
continue;
}
// Convert the position to obtain the insertion point.
index = -index - 1;
// save the key.
expectedKeys[ nkeys ] = key;
if(log.isInfoEnabled())
log.info("Will insert: key=" + BytesUtil.toString(key)
+ " at index=" + index + " : nkeys=" + nkeys);
// insert an entry under that key.
btree.insert(key, new SimpleEntry() );
nkeys++;
assertEquals( nkeys, root.getKeyCount() );
}
// sort the keys that we inserted.
Arrays.sort(expectedKeys,
BytesUtil.UnsignedByteArrayComparator.INSTANCE);
assertTrue(root.dump(Level.DEBUG,System.err));
// verify that the leaf has the same keys in the same order.
assertKeys( expectedKeys, root);
}
/**
* Test ability to insert entries into a leaf. Random (legal) external keys
* are inserted into a leaf until the leaf would overflow. The random keys
* are then sorted and compared with the actual keys in the leaf. If the
* keys were inserted correctly into the leaf then the two arrays of keys
* will have the same values in the same order. (This is a variation on the
* previous test that inserts keys into the leaf using a slightly higher
* level API).
*/
public void test_insertKeyIntoLeaf02() {
final int branchingFactor = 20;
final BTree btree = getBTree(branchingFactor);
final Leaf root = (Leaf) btree.root;
// array of inserted keys.
final byte[][] expectedKeys = new byte[branchingFactor][];
int nkeys = 0;
while( nkeys < branchingFactor ) {
// Valid random key.
final byte[] key = new byte[3];
r.nextBytes(key);
final int nkeysBefore = root.getKeyCount();
final boolean exists = btree.lookup(key) != null;
btree.insert(key, new SimpleEntry() );
if (nkeysBefore == root.getKeyCount()) {
// key already exists.
assertTrue(exists);
continue;
}
assertFalse(exists);
// save the key.
expectedKeys[ nkeys ] = key;
nkeys++;
assertEquals(nkeys, root.getKeyCount());
}
// sort the keys that we inserted.
Arrays.sort(expectedKeys,
BytesUtil.UnsignedByteArrayComparator.INSTANCE);
assertTrue(root.dump(Level.DEBUG,System.err));
// verify that the leaf has the same keys in the same order.
assertKeys( expectedKeys, root );
}
/**
* Test ability to insert entries into a leaf. Known keys and values are
* generated and inserted into the leaf in a random order. The sequence of
* keys and values in the leaf is then compared with the pre-generated
* sequences known to the unit test. The correct behavior of the
* {@link Leaf#entryIterator()} is also tested.
*
* @see Leaf#insert(byte[], byte[], boolean, long, Tuple)
* @see Leaf#lookup(byte[], Tuple)
* @see Leaf#entryIterator()
*/
public void test_insertKeyIntoLeaf03() {
final int branchingFactor = 20;
final BTree btree = getBTree(branchingFactor);
final Leaf root = (Leaf) btree.getRoot();
// array of keys to insert.
final byte[][] expectedKeys = new byte[branchingFactor][];
// the value to insert for each key.
final SimpleEntry[] expectedValues = new SimpleEntry[branchingFactor];
/*
* Generate keys and values. The keys are a monotonic progression with
* random non-zero intervals.
*/
int lastKey = 1;
for (int i = 0; i < branchingFactor; i++) {
final int key = lastKey + r.nextInt(100) + 1;
expectedKeys[ i ] = keyBuilder.reset().append(key).getKey();
expectedValues[ i ] = new SimpleEntry();
lastKey = key;
}
for( int i=0; i<branchingFactor; i++ ) {
final byte[] key = expectedKeys[i];
final SimpleEntry value = expectedValues[i];
assertEquals(i, root.getKeyCount() );
assertNull("Not expecting to find key=" + BytesUtil.toString(key),
btree.lookup(key));
// root.dump(System.err);
btree.insert(key, value );
// root.dump(System.err);
assertEquals("nkeys(i=" + i + " of " + branchingFactor + ")", i + 1,
root.getKeyCount());
assertEquals("value(i=" + i + " of " + branchingFactor + ")",
value, btree.lookup(key));
// verify the values iterator
final byte[][] tmp = new byte[root.getKeyCount()][];
for (int j = 0; j < root.getKeyCount(); j++) {
tmp[j] = root.getValue(j);
}
assertSameIterator("values", tmp, new Striterator(root
.entryIterator()).addFilter(new Resolver() {
@Override
protected Object resolve(Object arg0) {
return ((ITuple)arg0).getValue();
}
}) );
}
assertTrue(root.dump(Level.DEBUG,System.err));
// verify that the leaf has the same keys in the same order.
assertKeys(expectedKeys, root);
// verify that the leaf has the same values in the same order.
assertValues(expectedValues, root);
// verify the expected behavior of the iterator.
assertSameIterator("values", expectedValues, root.entryIterator());
}
/**
* Test insert, lookup and remove of keys in the root leaf.
*/
public void test_insertLookupRemoveFromLeaf01() {
final int m = 4;
final BTree btree = getBTree(m);
final Leaf root = (Leaf) btree.root;
Object e1 = new SimpleEntry();
Object e2 = new SimpleEntry();
Object e3 = new SimpleEntry();
Object e4 = new SimpleEntry();
/*
* fill the root leaf.
*/
assertNull(btree.insert(TestKeyBuilder.asSortKey(4), e4));
assertNull(btree.insert(TestKeyBuilder.asSortKey(2), e2));
assertNull(btree.insert(TestKeyBuilder.asSortKey(1), e1));
assertNull(btree.insert(TestKeyBuilder.asSortKey(3), e3));
/*
* verify that re-inserting does not split the leaf and returns the old
* value.
*/
assertEquals(e4,btree.insert(TestKeyBuilder.asSortKey(4),e4));
assertEquals(e2,btree.insert(TestKeyBuilder.asSortKey(2),e2));
assertEquals(e1,btree.insert(TestKeyBuilder.asSortKey(1),e1));
assertEquals(e3,btree.insert(TestKeyBuilder.asSortKey(3),e3));
assertEquals(root,btree.root);
// validate
assertKeys(new int[]{1,2,3,4},root);
assertSameIterator(new Object[]{e1,e2,e3,e4}, root.entryIterator());
// remove (2).
assertEquals(e2,btree.remove(TestKeyBuilder.asSortKey(2)));
assertKeys(new int[]{1,3,4},root);
assertSameIterator(new Object[]{e1,e3,e4}, root.entryIterator());
// remove (1).
assertEquals(e1,btree.remove(TestKeyBuilder.asSortKey(1)));
assertKeys(new int[]{3,4},root);
assertSameIterator(new Object[]{e3,e4}, root.entryIterator());
// remove (4).
assertEquals(e4,btree.remove(TestKeyBuilder.asSortKey(4)));
assertKeys(new int[]{3},root);
assertSameIterator(new Object[]{e3}, root.entryIterator());
// remove (3).
assertEquals(e3,btree.remove(TestKeyBuilder.asSortKey(3)));
assertKeys(new int[]{},root);
assertSameIterator(new Object[]{}, root.entryIterator());
assertNull(btree.remove(TestKeyBuilder.asSortKey(1)));
assertNull(btree.remove(TestKeyBuilder.asSortKey(2)));
assertNull(btree.remove(TestKeyBuilder.asSortKey(3)));
assertNull(btree.remove(TestKeyBuilder.asSortKey(4)));
}
/**
* Test insert and removal of keys in the root leaf.
*/
public void test_insertLookupRemoveFromLeaf02() {
final int m = 4;
final BTree btree = getBTree(m);
Map<Integer,SimpleEntry> expected = new TreeMap<Integer,SimpleEntry>();
Integer k1 = 1;
Integer k2 = 2;
Integer k3 = 3;
Integer k4 = 4;
SimpleEntry e1 = new SimpleEntry();
SimpleEntry e2 = new SimpleEntry();
SimpleEntry e3 = new SimpleEntry();
SimpleEntry e4 = new SimpleEntry();
Integer[] keys = new Integer[] {k1,k2,k3,k4};
SimpleEntry[] vals = new SimpleEntry[]{e1,e2,e3,e4};
for( int i=0; i<1000; i++ ) {
boolean insert = r.nextBoolean();
int index = r.nextInt(m);
final Integer ikey = keys[index];
final byte[] key = TestKeyBuilder.asSortKey(ikey);
SimpleEntry val = vals[index];
if( insert ) {
// System.err.println("insert("+key+", "+val+")");
SimpleEntry old = expected.put(ikey, val);
SimpleEntry old2 = (SimpleEntry) btree.insert(key, val);
// btree.dump(Level.DEBUG,System.err);
assertEquals(old, old2);
// verify that the root leaf was not split.
assertEquals("height",0,btree.height);
assertTrue(btree.root instanceof Leaf);
} else {
// System.err.println("remove("+key+")");
SimpleEntry old = expected.remove(ikey);
SimpleEntry old2 = (SimpleEntry) SerializerUtil.deserialize(btree.remove(key));
// btree.dump(Level.DEBUG,System.err);
assertEquals(old, old2);
}
if( i % 100 == 0 ) {
/*
* Validate the keys and entries.
*/
assertEquals("#entries", expected.size(), btree.getEntryCount());
Iterator<Map.Entry<Integer,SimpleEntry>> itr = expected.entrySet().iterator();
while( itr.hasNext()) {
Map.Entry<Integer,SimpleEntry> entry = itr.next();
final byte[] tmp = TestKeyBuilder.asSortKey(entry.getKey());
assertEquals("lookup(" + entry.getKey() + ")", entry
.getValue(), btree
.lookup(tmp));
}
}
}
}
}