blob: e0b9dbf33d20d0a7514137be7891db9e76d3edd2 [file] [log] [blame]
/*
* 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.directory.mavibot.btree;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import org.apache.directory.mavibot.btree.BulkLoader.LevelEnum;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.Ignore;
import org.junit.Test;
/**
* Test the BulkLoader class.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BulkLoaderTest
{
private void checkBtree( BTree<Long, String> oldBtree, BTree<Long, String> newBtree )
throws EndOfFileExceededException, IOException, KeyNotFoundException
{
assertEquals( oldBtree.getNbElems(), newBtree.getNbElems() );
TupleCursor<Long, String> cursorOld = oldBtree.browse();
TupleCursor<Long, String> cursorNew = newBtree.browse();
while ( cursorOld.hasNext() && cursorNew.hasNext() )
{
Tuple<Long, String> tupleOld = cursorOld.next();
Tuple<Long, String> tupleNew = cursorNew.next();
assertEquals( tupleOld.getKey(), tupleNew.getKey() );
assertEquals( tupleOld.getValue(), tupleNew.getValue() );
}
assertEquals( cursorOld.hasNext(), cursorNew.hasNext() );
}
/**
* Test that we can compact a btree which has no element
*/
@Test
public void testInMemoryBulkLoadNoElement() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
TupleCursor<Long, String> cursorOld = btree.browse();
TupleCursor<Long, String> cursorNew = btree.browse();
assertFalse( cursorOld.hasNext() );
assertFalse( cursorNew.hasNext() );
}
/**
* Test that we can compact a btree which has a partially full leaf only
*/
@Ignore
@Test
public void testInMemoryBulkLoad3Elements() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 3L; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
}
/**
* Test that we can compact a btree which has a 2 full leaves
*/
@Ignore
@Test
public void testInMemoryBulkLoad8Elements() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 8L; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
}
/**
* Test that we can compact a btree which has a few leaves, one being partially full
* @throws BTreeAlreadyManagedException
*/
@Test
public void testPersistedBulkLoad10Elements() throws IOException, KeyNotFoundException,
BTreeAlreadyManagedException
{
for ( int i = 0; i < 1001; i++ )
{
Random random = new Random( System.currentTimeMillis() );
File file = File.createTempFile( "managedbtreebuilder", ".data" );
file.deleteOnExit();
try
{
RecordManager rm = new RecordManager( file.getAbsolutePath() );
PersistedBTree<Long, String> btree = ( PersistedBTree<Long, String> ) rm.addBTree( "test",
LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
BulkLoader<Long, String> bulkLoader = new BulkLoader<Long, String>();
int nbElems = i;
int addedElems = 0;
final Tuple<Long, String>[] elems = new Tuple[nbElems];
Map<Long, Tuple<Long, Set<String>>> expected = new HashMap<Long, Tuple<Long, Set<String>>>();
long t00 = System.currentTimeMillis();
while ( addedElems < nbElems )
{
long key = random.nextLong() % 3333333L;
if ( expected.containsKey( key ) )
{
continue;
}
long w = random.nextLong() % 3333333L;
String value = "V" + w;
elems[addedElems] = new Tuple<Long, String>( key, value );
Tuple<Long, Set<String>> expectedTuple = expected.get( key );
if ( expectedTuple == null )
{
expectedTuple = new Tuple<Long, Set<String>>( key, new TreeSet<String>() );
}
expectedTuple.value.add( value );
expected.put( key, expectedTuple );
addedElems++;
if ( addedElems % 100 == 0 )
{
//System.out.println( "Nb added elements = " + addedElems );
}
}
long t01 = System.currentTimeMillis();
// System.out.println( "Time to create the " + nbElems + " elements " + ( ( t01 - t00 ) / 1 ) );
Iterator<Tuple<Long, String>> tupleIterator = new Iterator<Tuple<Long, String>>()
{
private int pos = 0;
@Override
public Tuple<Long, String> next()
{
return elems[pos++];
}
@Override
public boolean hasNext()
{
return pos < elems.length;
}
@Override
public void remove()
{
}
};
long t0 = System.currentTimeMillis();
BTree<Long, String> result = bulkLoader.load( btree, tupleIterator, 128 );
long t1 = System.currentTimeMillis();
System.out.println( "== Btree #" + i + ", Time to bulkoad the " + nbElems + " elements "
+ ( t1 - t0 ) + "ms" );
TupleCursor<Long, String> cursor = result.browse();
int nbFetched = 0;
long t2 = System.currentTimeMillis();
while ( cursor.hasNext() )
{
Tuple<Long, String> elem = cursor.next();
assertTrue( expected.containsKey( elem.key ) );
Tuple<Long, Set<String>> tuple = expected.get( elem.key );
assertNotNull( tuple );
nbFetched++;
}
long t3 = System.currentTimeMillis();
//System.out.println( "Time to read the " + nbElems + " elements " + ( t3 - t2 ) );
assertEquals( nbElems, nbFetched );
checkBtree( btree, result );
}
finally
{
file.delete();
}
}
}
/**
* Test that we can compact a btree which has a full parent node, with all the leaves full.
*/
@Test
public void testInMemoryBulkLoad20Elements() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 20L; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
}
/**
* Test that we can compact a btree which has two full parent nodes, with all the leaves full.
* That means we have an upper node with one element.
*/
@Ignore
@Test
public void testInMemoryBulkLoad40Elements() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 40L; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
}
/**
* Test that we can compact a btree which has two full parent nodes, with all the leaves full.
* That means we have an upper node with one element.
*/
@Test
public void testInMemoryBulkLoad100Elements() throws IOException, KeyNotFoundException
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 100L; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
checkBtree( btree, newBtree );
}
@Ignore
@Test
public void testInMemoryBulkLoadN() throws IOException, KeyNotFoundException
{
Random random = new Random( System.nanoTime() );
long t0 = System.currentTimeMillis();
for ( long n = 0L; n < 2500L; n++ )
{
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < n; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
//long t1 = System.currentTimeMillis();
//System.out.println( "Delta initial load = " + ( t1 - t0 ) );
//long t2 = System.currentTimeMillis();
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
//long t3 = System.currentTimeMillis();
//System.out.println( "Delta initial load = " + ( t3 - t2 ) );
System.out.println( "Checking for N = " + n );
checkBtree( btree, newBtree );
}
}
@Ignore
@Test
public void testInMemoryBulkLoad21() throws IOException, KeyNotFoundException
{
Random random = new Random( System.nanoTime() );
long t0 = System.currentTimeMillis();
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( Long i = 0L; i < 21; i++ )
{
String value = "V" + i;
btree.insert( i, value );
}
//long t1 = System.currentTimeMillis();
//System.out.println( "Delta initial load = " + ( t1 - t0 ) );
//long t2 = System.currentTimeMillis();
BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
//long t3 = System.currentTimeMillis();
//System.out.println( "Delta initial load = " + ( t3 - t2 ) );
System.out.println( "Checking for N = " + 21 );
checkBtree( btree, newBtree );
}
/**
* test the computeLeafLevel method
*/
@Test
public void testPersistedBulkLoadComputeLeafLevel() throws IOException, KeyNotFoundException,
BTreeAlreadyManagedException
{
Random random = new Random( System.currentTimeMillis() );
File file = File.createTempFile( "managedbtreebuilder", ".data" );
file.deleteOnExit();
try
{
RecordManager rm = new RecordManager( file.getAbsolutePath() );
PersistedBTree<Long, String> btree = ( PersistedBTree<Long, String> ) rm.addBTree( "test",
LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
BulkLoader<Long, String> bulkLoader = new BulkLoader<Long, String>();
int[] expectedNbPages = new int[]
{
0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
int[] expectedLimit = new int[]
{
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 32,
16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 48
};
int[] expectedKeys = new int[]
{
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};
for ( int i = 0; i < 49; i++ )
{
System.out.println( "=======================================" );
System.out.println( "== Iteration n#" + i );
System.out.println( "=======================================" );
BulkLoader<Long, String>.LevelInfo leafInfo = bulkLoader.computeLevel( btree, i, LevelEnum.LEAF );
assertEquals( expectedNbPages[i], leafInfo.nbPages );
assertEquals( expectedLimit[i], leafInfo.nbElemsLimit );
assertEquals( expectedKeys[i], leafInfo.currentPage.getNbElems() );
}
}
finally
{
file.delete();
}
}
/**
* test the computeNodeLevel method
*/
@Test
public void testPersistedBulkLoadComputeNodeLevel() throws IOException, KeyNotFoundException,
BTreeAlreadyManagedException
{
Random random = new Random( System.currentTimeMillis() );
File file = File.createTempFile( "managedbtreebuilder", ".data" );
file.deleteOnExit();
try
{
RecordManager rm = new RecordManager( file.getAbsolutePath() );
PersistedBTree<Long, String> btree = ( PersistedBTree<Long, String> ) rm.addBTree( "test",
LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
BulkLoader<Long, String> bulkLoader = new BulkLoader<Long, String>();
int[] expectedNbPages = new int[]
{
-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
int[] expectedLimit = new int[]
{
-1,
-1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 34,
17, 17, 17, 17, 17, 17, 17, 17, 34, 34, 34, 34, 34, 34, 34, 34, 51
};
int[] expectedKeys = new int[]
{
-1, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};
for ( int i = 2; i < 52; i++ )
{
System.out.println( "=======================================" );
System.out.println( "== Iteration n#" + i );
System.out.println( "=======================================" );
BulkLoader<Long, String>.LevelInfo nodeInfo = bulkLoader.computeLevel( btree, i, LevelEnum.NODE );
assertEquals( expectedNbPages[i], nodeInfo.nbPages );
assertEquals( expectedLimit[i], nodeInfo.nbElemsLimit );
assertEquals( expectedKeys[i], nodeInfo.currentPage.getNbElems() );
}
}
finally
{
file.delete();
}
}
/**
* test the computeNodeLevel method
*/
@Test
public void testPersistedBulkLoadComputeLevels() throws IOException, KeyNotFoundException,
BTreeAlreadyManagedException
{
Random random = new Random( System.currentTimeMillis() );
File file = File.createTempFile( "managedbtreebuilder", ".data" );
file.deleteOnExit();
try
{
RecordManager rm = new RecordManager( file.getAbsolutePath() );
PersistedBTree<Long, String> btree = ( PersistedBTree<Long, String> ) rm.addBTree( "test",
LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
BulkLoader<Long, String> bulkLoader = new BulkLoader<Long, String>();
int[] expectedNbPages = new int[]
{
-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
int[] expectedLimit = new int[]
{
-1,
-1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 34,
17, 17, 17, 17, 17, 17, 17, 17, 34, 34, 34, 34, 34, 34, 34, 34, 51
};
int[] expectedKeys = new int[]
{
-1, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};
for ( int i = 2599; i <= 2599; i++ )
{
System.out.println( "=======================================" );
System.out.println( "== Iteration #" + i );
System.out.println( "=======================================" );
List<BulkLoader<Long, String>.LevelInfo> levels = bulkLoader.computeLevels( btree, i );
for ( BulkLoader<Long, String>.LevelInfo level : levels )
{
System.out.println( level );
}
}
}
finally
{
file.delete();
}
}
}