/* HeliDB -- A simple database for Java, http://www.helidb.org
* Copyright (C) 2008, 2009 Karl Gustafsson
*
* This file is a part of HeliDB.
*
* HeliDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeliDB 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, see <http://www.gnu.org/licenses/>.
*/
package org.helidb.util.bplus;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import org.entityfs.ReadWritableFile;
import org.entityfs.support.log.LogAdapterHolder;
import org.entityfs.support.log.StdOutLogAdapter;
import org.entityfs.util.io.ReadWritableFileAdapter;
import org.helidb.lang.DatabaseException;
import org.helidb.lang.KeyExistsException;
import org.helidb.lang.KeyNotFoundException;
import org.helidb.lang.Record;
import org.helidb.lang.serializer.CharacterNullSerializer;
import org.helidb.lang.serializer.IntegerNullSerializer;
import org.helidb.lang.serializer.IntegerSerializer;
import org.helidb.lang.serializer.LongNullSerializer;
import org.helidb.lang.serializer.LongSerializer;
import org.helidb.lang.serializer.Serializer;
import org.helidb.lang.serializer.ShortNullSerializer;
import org.helidb.lang.serializer.ShortSerializer;
import org.helidb.search.SearchMode;
import org.helidb.test.support.FileSupport;
import org.junit.Test;
public class BPlusTreeTest extends AbstractBPlusTreeTest
{
private static final Random RANDOM = new Random(System.currentTimeMillis());
private static final boolean[] BOOLEANS = new boolean[] { true, false };
private static final int[] POINTER_SIZES = new int[] { 2, 3, 6, 8 };
private void assertLEquals(long l1, Long l2)
{
assertEquals(l1, l2.longValue());
}
private byte[] writeJunk(ReadWritableFile f)
{
byte[] barr = new byte[RANDOM.nextInt(16)];
RANDOM.nextBytes(barr);
try
{
OutputStream os = f.openForWrite();
try
{
os.write(barr);
}
finally
{
os.close();
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
return barr;
}
private void assertJunkUntouched(ReadWritableFile f, byte[] barr)
{
if (barr.length > 0)
{
byte[] barr2 = new byte[barr.length];
try
{
InputStream is = f.openForRead();
try
{
assertEquals(barr2.length, is.read(barr2));
}
finally
{
is.close();
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
assertTrue(Arrays.equals(barr, barr2));
}
}
@Test
public void testInsertRecord()
{
List<Integer> l = new ArrayList<Integer>();
BPlusTree.insertRecord(l, 50);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 50 }));
BPlusTree.insertRecord(l, 30);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 30, 50 }));
BPlusTree.insertRecord(l, 20);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 30, 50 }));
BPlusTree.insertRecord(l, 25);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 50 }));
BPlusTree.insertRecord(l, 40);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 40, 50 }));
BPlusTree.insertRecord(l, 60);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 40, 50, 60 }));
BPlusTree.insertRecord(l, 35);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 35, 40, 50, 60 }));
BPlusTree.insertRecord(l, 45);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 35, 40, 45, 50, 60 }));
BPlusTree.insertRecord(l, 55);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 20, 25, 30, 35, 40, 45, 50, 55, 60 }));
BPlusTree.insertRecord(l, 15);
assertTrue(Arrays.equals(l.toArray(), new Object[] { 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 }));
List<Integer> l2 = new ArrayList<Integer>();
BPlusTree.insertRecord(l2, 50);
BPlusTree.insertRecord(l2, 70);
assertTrue(Arrays.equals(l2.toArray(), new Object[] { 50, 70 }));
}
@Test
public void testFindAddressToNodeWhereKeyShouldGo()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah), lah);
try
{
// A list with an odd size
List<KeyAndValue<Long, Long>> records = new ArrayList<KeyAndValue<Long, Long>>(5);
records.add(new KeyAndValue<Long, Long>(Long.valueOf(1L), Long.valueOf(3L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(3L), Long.valueOf(5L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(5L), Long.valueOf(7L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(7L), Long.valueOf(9L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(9L), Long.valueOf(11L)));
assertLEquals(1L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(-111L), 1L, null, records).getValue());
assertLEquals(1L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(0L), 1L, null, records).getValue());
assertLEquals(3L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(2L), 1L, null, records).getValue());
assertLEquals(5L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(4L), 1L, null, records).getValue());
assertLEquals(7L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(6L), 1L, null, records).getValue());
assertLEquals(9L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(8L), 1L, null, records).getValue());
assertLEquals(11L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(10L), 1L, null, records).getValue());
assertLEquals(11L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(100000L), 1L, null, records).getValue());
// A list with an even size
records = new ArrayList<KeyAndValue<Long, Long>>(4);
records.add(new KeyAndValue<Long, Long>(Long.valueOf(1L), Long.valueOf(3L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(3L), Long.valueOf(5L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(5L), Long.valueOf(7L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(7L), Long.valueOf(9L)));
assertLEquals(1L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(-111L), 1L, null, records).getValue());
assertLEquals(1L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(0L), 1L, null, records).getValue());
assertLEquals(3L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(2L), 1L, null, records).getValue());
assertLEquals(5L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(4L), 1L, null, records).getValue());
assertLEquals(7L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(6L), 1L, null, records).getValue());
assertLEquals(9L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(8L), 1L, null, records).getValue());
assertLEquals(9L, btr.findLocationOfNodeWhereKeyShouldGo(Long.valueOf(100000L), 1L, null, records).getValue());
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testFindRecord()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah), lah);
try
{
// A list with an odd size
List<KeyAndValue<Long, Long>> records = new ArrayList<KeyAndValue<Long, Long>>(5);
records.add(new KeyAndValue<Long, Long>(Long.valueOf(1L), Long.valueOf(3L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(3L), Long.valueOf(5L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(5L), Long.valueOf(7L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(7L), Long.valueOf(9L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(9L), Long.valueOf(11L)));
assertEquals(0, btr.findRecord(Long.valueOf(1L), records));
assertEquals(1, btr.findRecord(Long.valueOf(3L), records));
assertEquals(2, btr.findRecord(Long.valueOf(5L), records));
assertEquals(3, btr.findRecord(Long.valueOf(7L), records));
assertEquals(4, btr.findRecord(Long.valueOf(9L), records));
assertTrue(btr.findRecord(Long.valueOf(-11L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(2L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(6L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(11L), records) < 0);
// A list with an even size
records = new ArrayList<KeyAndValue<Long, Long>>(5);
records.add(new KeyAndValue<Long, Long>(Long.valueOf(1L), Long.valueOf(3L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(3L), Long.valueOf(5L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(5L), Long.valueOf(7L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(7L), Long.valueOf(9L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(9L), Long.valueOf(11L)));
records.add(new KeyAndValue<Long, Long>(Long.valueOf(11L), Long.valueOf(11L)));
assertEquals(0, btr.findRecord(Long.valueOf(1L), records));
assertEquals(1, btr.findRecord(Long.valueOf(3L), records));
assertEquals(2, btr.findRecord(Long.valueOf(5L), records));
assertEquals(3, btr.findRecord(Long.valueOf(7L), records));
assertEquals(4, btr.findRecord(Long.valueOf(9L), records));
assertEquals(5, btr.findRecord(Long.valueOf(11L), records));
assertTrue(btr.findRecord(Long.valueOf(-11L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(2L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(6L), records) < 0);
assertTrue(btr.findRecord(Long.valueOf(110L), records) < 0);
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testGetFirstLastRecord()
{
LongConverter lconv = new LongConverter();
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah), lah);
try
{
assertNull(btr.getFirstRecord());
assertNull(btr.getLastRecord());
KeyAndValue<Long, Long> r1 = createLRecord(lconv, lconv, 2, 2);
btr.insert(r1.getKey(), r1.getValue());
assertEquals(r1, btr.getFirstRecord());
assertEquals(r1, btr.getLastRecord());
KeyAndValue<Long, Long> r2 = createLRecord(lconv, lconv, 1, 1);
btr.insert(r2.getKey(), r2.getValue());
assertEquals(r2, btr.getFirstRecord());
assertEquals(r1, btr.getLastRecord());
KeyAndValue<Long, Long> r3 = createLRecord(lconv, lconv, 3, 3);
btr.insert(r3.getKey(), r3.getValue());
assertEquals(r2, btr.getFirstRecord());
assertEquals(r3, btr.getLastRecord());
KeyAndValue<Long, Long> r4 = createLRecord(lconv, lconv, 4, 4);
btr.insert(r4.getKey(), r4.getValue());
KeyAndValue<Long, Long> r5 = createLRecord(lconv, lconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
KeyAndValue<Long, Long> r6 = createLRecord(lconv, lconv, 6, 6);
btr.insert(r6.getKey(), r6.getValue());
assertEquals(r2, btr.getFirstRecord());
assertEquals(r6, btr.getLastRecord());
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testGetNextAndPreviousRecordsOnTreeThatDoesNotSupportThem()
{
LongConverter lconv = new LongConverter();
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah), lah);
try
{
KeyAndValue<Long, Long> r1 = createLRecord(lconv, lconv, 2, 2);
btr.insert(r1.getKey(), r1.getValue());
try
{
btr.getNextRecord(2L);
fail();
}
catch (UnsupportedOperationException e)
{
// ok
}
try
{
btr.getPreviousRecord(2L);
fail();
}
catch (UnsupportedOperationException e)
{
// ok
}
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testGetNextAndPreviousRecords()
{
LongConverter lconv = new LongConverter();
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah), lah);
try
{
assertNull(btr.getNextRecord(1L));
assertNull(btr.getPreviousRecord(1L));
KeyAndValue<Long, Long> r1 = createLRecord(lconv, lconv, 2, 2);
btr.insert(r1.getKey(), r1.getValue());
assertNull(btr.getPreviousRecord(1L));
assertEquals(r1, btr.getNextRecord(1L));
assertNull(btr.getPreviousRecord(2L));
assertNull(btr.getNextRecord(2L));
assertEquals(r1, btr.getPreviousRecord(3L));
assertNull(btr.getNextRecord(3L));
KeyAndValue<Long, Long> r2 = createLRecord(lconv, lconv, 5, 5);
btr.insert(r2.getKey(), r2.getValue());
assertNull(btr.getPreviousRecord(1L));
assertEquals(r1, btr.getNextRecord(1L));
assertNull(btr.getPreviousRecord(2L));
assertEquals(r2, btr.getNextRecord(2L));
assertEquals(r1, btr.getPreviousRecord(3L));
assertEquals(r2, btr.getNextRecord(3L));
assertEquals(r1, btr.getPreviousRecord(5L));
assertNull(btr.getNextRecord(5L));
assertEquals(r2, btr.getPreviousRecord(7L));
assertNull(btr.getNextRecord(7L));
KeyAndValue<Long, Long> r3 = createLRecord(lconv, lconv, 8, 8);
btr.insert(r3.getKey(), r3.getValue());
KeyAndValue<Long, Long> r4 = createLRecord(lconv, lconv, 11, 11);
btr.insert(r4.getKey(), r4.getValue());
KeyAndValue<Long, Long> r5 = createLRecord(lconv, lconv, 14, 14);
btr.insert(r5.getKey(), r5.getValue());
assertNull(btr.getPreviousRecord(1L));
assertEquals(r1, btr.getNextRecord(1L));
assertNull(btr.getPreviousRecord(2L));
assertEquals(r2, btr.getNextRecord(2L));
assertEquals(r1, btr.getPreviousRecord(3L));
assertEquals(r2, btr.getNextRecord(3L));
assertEquals(r1, btr.getPreviousRecord(5L));
assertEquals(r3, btr.getNextRecord(5L));
assertEquals(r2, btr.getPreviousRecord(7L));
assertEquals(r3, btr.getNextRecord(7L));
assertEquals(r2, btr.getPreviousRecord(8L));
assertEquals(r4, btr.getNextRecord(8L));
assertEquals(r3, btr.getPreviousRecord(9L));
assertEquals(r4, btr.getNextRecord(9L));
assertEquals(r3, btr.getPreviousRecord(11L));
assertEquals(r5, btr.getNextRecord(11L));
assertEquals(r4, btr.getPreviousRecord(12L));
assertEquals(r5, btr.getNextRecord(12L));
assertEquals(r4, btr.getPreviousRecord(14L));
assertNull(btr.getNextRecord(14L));
assertEquals(r5, btr.getPreviousRecord(15L));
assertNull(btr.getNextRecord(15L));
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private <K extends Comparable<K>> void assertNodeDeleted(NodeRepository<K> nr, long pos)
{
try
{
// Either this returns null if pos is beyond the end of the file,
// or it throws an exception if the node cannot be read.
assertNull(nr.readNode(pos, null));
}
catch (DatabaseException e)
{
assertTrue(e.getMessage().contains("deleted") || e.getMessage().contains("Wanted to read"));
}
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testInsertFromOneToNineWithTwoRecordsPerNodeInternal(NodeRepository<K> nr, ValueConverter<K> kconv, ValueConverter<V> vconv, long nonLeafNodeSize, long leafNodeSize)
{
NodePositions np = new NodePositions(nonLeafNodeSize, leafNodeSize, nr.getPositionOfRootNode());
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// *0[1, ]
KeyAndValue<K, V> r1 = createLRecord(kconv, vconv, 1, 1);
btr.insert(r1.getKey(), r1.getValue());
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r1), true, false, null, null), rn);
// 0[1,2]
KeyAndValue<K, V> r2 = createLRecord(kconv, vconv, 2, 2);
btr.insert(r2.getKey(), r2.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r1, r2), true, true, null, null), rn);
// 0[(1),2(2), ]
// *1[1, ] *2[2,3]
KeyAndValue<K, V> r3 = createLRecord(kconv, vconv, 3, 3);
btr.insert(r3.getKey(), r3.getValue());
np.addLeaf();
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(2, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2, r3), false, true, np.get(1), null), rn);
// 0[(1),2(2),3(3)]
// 1[1, ] 2[2, ] *3[3,4]
KeyAndValue<K, V> r4 = createLRecord(kconv, vconv, 4, 4);
btr.insert(r4.getKey(), r4.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(2, np.get(2), kconv), createLRecord(3, np.get(3), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r3, r4), false, true, np.get(2), null), rn);
// 0[(5),3(6), ]
// *5[(1),2(2), ] *6[(3),4(4), ]
// 1[1, ] 2[2, ] 3[3, ] *4[4, 5]
KeyAndValue<K, V> r5 = createLRecord(kconv, vconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(3, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r3), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r4, r5), false, true, np.get(3), null), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(2, Long.valueOf(np.get(2)), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(3));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(3), np.get(3), createLRecordList(createLRecord(4, Long.valueOf(np.get(4)), kconv)), false, false), rn);
// 0[(5),3(6), ]
// 5[(1),2(2), ] 6[(3),4(4),5(7)]
// 1[1, ] 2[2, ] 3[3, ] 4[4, ] *7[5,6]
KeyAndValue<K, V> r6 = createLRecord(kconv, vconv, 6, 6);
btr.insert(r6.getKey(), r6.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(3, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r4), false, false, np.get(3), np.get(7)), rn);
rn = nr.readNode(np.get(6), kconv.convert(3));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(3), np.get(3), createLRecordList(createLRecord(4, Long.valueOf(np.get(4)), kconv), createLRecord(5, Long.valueOf(np.get(7)), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5, r6), false, true, np.get(4), null), rn);
// 0[(5),3(6),5(9)]
// 5[(1),2(2), ] 6[(3),4(4), ] *9[(7),6(8),]
// 1[1, ] 2[2, ] 3[3, ] 4[4, ] 7[5, ] *8[6,7]
KeyAndValue<K, V> r7 = createLRecord(kconv, vconv, 7, 7);
btr.insert(r7.getKey(), r7.getValue());
np.addLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(3, np.get(6), kconv), createLRecord(5, np.get(9), kconv)), true, true), rn);
rn = nr.readNode(np.get(6), kconv.convert(3));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(3), np.get(3), createLRecordList(createLRecord(4, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(4), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6, r7), false, true, np.get(7), null), rn);
rn = nr.readNode(np.get(9), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(5), np.get(7), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
// 0[(5),3(6),5(9)]
// 5[(1),2(2), ] 6[(3),4(4), ] 9[(7),6(8),7(10)]
// 1[1, ] 2[2, ] 3[3, ] 4[4, ] 7[5, ] 8[6, ] *10[7,8]
KeyAndValue<K, V> r8 = createLRecord(kconv, vconv, 8, 8);
btr.insert(r8.getKey(), r8.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(3, np.get(6), kconv), createLRecord(5, np.get(9), kconv)), true, true), rn);
rn = nr.readNode(np.get(6), kconv.convert(3));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(3), np.get(3), createLRecordList(createLRecord(4, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(4), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6), false, false, np.get(7), np.get(10)), rn);
rn = nr.readNode(np.get(9), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(5), np.get(7), createLRecordList(createLRecord(6, np.get(8), kconv), createLRecord(7, np.get(10), kconv)), false, true), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r7, r8), false, true, np.get(8), null), rn);
// 0[(13),5(14), ]
// *13[(5),3(6), ] *14[(9),7(12), ]
// 5[(1),2(2), ] 6[(3),4(4), ] 9[(7),6(8), ] *12[(10),8(11), ]
// 1[1, ] 2[2, ] 3[3, ] 4[4, ] 7[5, ] 8[6, ] 10[7, ] *11[8,9]
KeyAndValue<K, V> r9 = createLRecord(kconv, vconv, 9, 9);
btr.insert(r9.getKey(), r9.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(13), createLRecordList(createLRecord(5, np.get(14), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r3), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r4), false, false, np.get(3), np.get(7)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(2, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(3));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(3), np.get(3), createLRecordList(createLRecord(4, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(4), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6), false, false, np.get(7), np.get(10)), rn);
rn = nr.readNode(np.get(9), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(5), np.get(7), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r7), false, false, np.get(8), np.get(11)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r8, r9), false, true, np.get(10), null), rn);
rn = nr.readNode(np.get(12), kconv.convert(7));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(7), np.get(10), createLRecordList(createLRecord(8, np.get(11), kconv)), false, false), rn);
rn = nr.readNode(np.get(13), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(13), null, np.get(5), createLRecordList(createLRecord(3, np.get(6), kconv)), false, false), rn);
rn = nr.readNode(np.get(14), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(14), kconv.convert(5), np.get(9), createLRecordList(createLRecord(7, np.get(12), kconv)), false, false), rn);
assertEquals(9, btr.size());
// Delete 1
// 0[(5),5(9),7(12)]
// 5[(1),3(3),4(4)] 9[(7),6(8), ] 12[(10),8(11), ]
// 1[2, ] 3[3, ] 4[4, ] 7[5, ] 8[6, ] 10[7, ] 11[8,9]
assertEquals(r1.getValue(), btr.delete(r1.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(5, np.get(9), kconv), createLRecord(7, np.get(12), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r2), false, false, null, np.get(3)), rn);
assertNodeDeleted(nr, np.get(2));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r3), false, false, np.get(1), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r4), false, false, np.get(3), np.get(7)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(3, np.get(3), kconv), createLRecord(4, np.get(4), kconv)), false, true), rn);
assertNodeDeleted(nr, np.get(6));
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(4), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6), false, false, np.get(7), np.get(10)), rn);
rn = nr.readNode(np.get(9), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(5), np.get(7), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r7), false, false, np.get(8), np.get(11)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r8, r9), false, true, np.get(10), null), rn);
rn = nr.readNode(np.get(12), kconv.convert(7));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(7), np.get(10), createLRecordList(createLRecord(8, np.get(11), kconv)), false, false), rn);
assertNodeDeleted(nr, np.get(13));
assertNodeDeleted(nr, np.get(14));
// Delete 2
// 0[(5),5(9),7(12)]
// 5[(3),4(4), ] 9[(7),6(8), ] 12[(10),8(11), ]
// 1[3, ] 4[4, ] 7[5, ] 8[6, ] 10[7, ] 11[8,9]
assertEquals(r2.getValue(), btr.delete(r2.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r3), false, false, null, np.get(4)), rn);
assertNodeDeleted(nr, np.get(3));
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r4), false, false, np.get(1), np.get(7)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(4, np.get(4), kconv)), false, false), rn);
// Delete 3
// 0[(5),7(12)]
// 5[(1),5(7),6(8)] 12[(10),8(11), ]
// 1[4, ] 7[5, ] 8[6, ] 10[7, ] 11[8,9]
assertEquals(r3.getValue(), btr.delete(r3.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(7, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r4), false, false, null, np.get(7)), rn);
assertNodeDeleted(nr, np.get(4));
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(5, np.get(7), kconv), createLRecord(6, np.get(8), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(1), np.get(8)), rn);
// Delete 4
// 0[(5),7(12)]
// 5[(1),6(8), ] 12[(10),8(11), ]
// 1[5, ] 8[6, ] 10[7, ] 11[8,9]
assertEquals(r4.getValue(), btr.delete(r4.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5), false, false, null, np.get(8)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
assertNodeDeleted(nr, np.get(7));
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6), false, false, np.get(1), np.get(10)), rn);
// Delete 5
// 0[(1),7(10),8(11)]
// 1[6, ] 10[7, ] 11[8,9]
assertEquals(r5.getValue(), btr.delete(r5.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(7, np.get(10), kconv), createLRecord(8, np.get(11), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r6), false, false, null, np.get(10)), rn);
assertNodeDeleted(nr, np.get(5));
assertNodeDeleted(nr, np.get(8));
assertNodeDeleted(nr, np.get(12));
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r7), false, false, np.get(1), np.get(11)), rn);
assertEquals(4, btr.size());
// Delete 6
// 0[(1),8(11)]
// 1[7, ] 11[8,9]
assertEquals(r6.getValue(), btr.delete(r6.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(8, np.get(11), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r7), false, false, null, np.get(11)), rn);
assertNodeDeleted(nr, np.get(10));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r8, r9), false, true, np.get(1), null), rn);
// Delete 7
// 0[8,9]
assertEquals(r7.getValue(), btr.delete(r7.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r8, r9), true, true, null, null), rn);
assertNodeDeleted(nr, np.get(1));
assertNodeDeleted(nr, np.get(11));
// Delete 8
// 0[9]
assertEquals(r8.getValue(), btr.delete(r8.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r9), true, false, null, null), rn);
// Delete 9
// 0[,]
assertEquals(r9.getValue(), btr.delete(r9.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), Collections.EMPTY_LIST, true, false, null, null), rn);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, lah);
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testInsertFromOneToNineWithTwoRecordsPerNodeInternal(nr, kconv, vconv, getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 2), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 2, leafNodePointers));
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testInsertFromOneToNineWithTwoRecordsPerNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToNineWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testInsertFromOneToNineWithTwoRecordsPerNode()
{
testInsertFromOneToNineWithTwoRecordsPerNodeInternal(0);
}
@Test
public void testInsertFromOneToNineWithTwoRecordsPerNodeAndSmallLruCache()
{
testInsertFromOneToNineWithTwoRecordsPerNodeInternal(2);
}
@Test
public void testInsertFromOneToNineWithTwoRecordsPerNodeAndLargeLruCache()
{
testInsertFromOneToNineWithTwoRecordsPerNodeInternal(20);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(NodeRepository<K> nr, ValueConverter<K> kconv, ValueConverter<V> vconv, long nonLeafNodeSize, long leafNodeSize)
{
NodePositions np = new NodePositions(nonLeafNodeSize, leafNodeSize, nr.getPositionOfRootNode());
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// *0[15, ]
KeyAndValue<K, V> r15 = createLRecord(kconv, vconv, 15, 15);
btr.insert(r15.getKey(), r15.getValue());
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r15), true, false, null, null), rn);
// 0[14,15]
KeyAndValue<K, V> r14 = createLRecord(kconv, vconv, 14, 14);
btr.insert(r14.getKey(), r14.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r14, r15), true, true, null, null), rn);
// 0[(1),14(2), ]
// *1[13, ] *2[14, 15]
KeyAndValue<K, V> r13 = createLRecord(kconv, vconv, 13, 13);
btr.insert(r13.getKey(), r13.getValue());
np.addLeaf();
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(14, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r13), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r14, r15), false, true, np.get(1), null), rn);
// 0[(1),14(2), ]
// 1[12,13] 2[14, 15]
KeyAndValue<K, V> r12 = createLRecord(kconv, vconv, 12, 12);
btr.insert(r12.getKey(), r12.getValue());
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r12, r13), false, true, null, np.get(2)), rn);
// 0[(1),12(3),14(2)]
// 1[11, ] *3[12,13] 2[14, 15]
KeyAndValue<K, V> r11 = createLRecord(kconv, vconv, 11, 11);
btr.insert(r11.getKey(), r11.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(12, np.get(3), kconv), createLRecord(14, np.get(2), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r11), false, false, null, np.get(3)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r14, r15), false, true, np.get(3), null), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r12, r13), false, true, np.get(1), np.get(2)), rn);
// 0[(1),12(3),14(2)]
// 1[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r10 = createLRecord(kconv, vconv, 10, 10);
btr.insert(r10.getKey(), r10.getValue());
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r10, r11), false, true, null, np.get(3)), rn);
// 0[(5),12(6), ]
// *5[(1),10(4), ] *6[(3),14(2), ]
// 1[9, ] *4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r9 = createLRecord(kconv, vconv, 9, 9);
btr.insert(r9.getKey(), r9.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(12, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r9), false, false, null, np.get(4)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r12, r13), false, true, np.get(4), np.get(2)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r10, r11), false, true, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(10, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(12));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(12), np.get(3), createLRecordList(createLRecord(14, np.get(2), kconv)), false, false), rn);
// 0[(5),12(6), ]
// 5[(1),10(4), ] 6[(3),14(2), ]
// 1[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r8 = createLRecord(kconv, vconv, 8, 8);
btr.insert(r8.getKey(), r8.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(12, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r8, r9), false, true, null, np.get(4)), rn);
// 0[(5),12(6), ]
// 5[(1),8(7),10(4)] 6[(3),14(2), ]
// 1[7, ] *7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r7 = createLRecord(kconv, vconv, 7, 7);
btr.insert(r7.getKey(), r7.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(12, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r7), false, false, null, np.get(7)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r10, r11), false, true, np.get(7), np.get(3)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(8, np.get(7), kconv), createLRecord(10, np.get(4), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r8, r9), false, true, np.get(1), np.get(4)), rn);
// 0[(5),12(6), ]
// 5[(1),8(7),10(4)] 6[(3),14(2), ]
// 1[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r6 = createLRecord(kconv, vconv, 6, 6);
btr.insert(r6.getKey(), r6.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(12, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r6, r7), false, true, null, np.get(7)), rn);
// 0[(5),8(9),12(6)]
// 5[(1),6(8), ] *9[(7),10(4), ] 6[(3),14(2), ]
// 1[5, ] *8[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r5 = createLRecord(kconv, vconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
np.addLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(8, np.get(9), kconv), createLRecord(12, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5), false, false, null, np.get(8)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r8, r9), false, true, np.get(8), np.get(4)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6, r7), false, true, np.get(1), np.get(7)), rn);
rn = nr.readNode(np.get(9), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(8), np.get(7), createLRecordList(createLRecord(10, np.get(4), kconv)), false, false), rn);
// 0[(5),8(9),12(6)]
// 5[(1),6(8), ] 9[(7),10(4), ] 6[(3),14(2), ]
// 1[4,5] 8[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r4 = createLRecord(kconv, vconv, 4, 4);
btr.insert(r4.getKey(), r4.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(8, np.get(9), kconv), createLRecord(12, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r4, r5), false, true, null, np.get(8)), rn);
// 0[(5),8(9),12(6)]
// 5[(1),4(10),6(8)] 9[(7),10(4), ] 6[(3),14(2), ]
// 1[3, ] *10[4,5] 8[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r3 = createLRecord(kconv, vconv, 3, 3);
btr.insert(r3.getKey(), r3.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(8, np.get(9), kconv), createLRecord(12, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r3), false, false, null, np.get(10)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(4, np.get(10), kconv), createLRecord(6, np.get(8), kconv)), false, true), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6, r7), false, true, np.get(10), np.get(7)), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r4, r5), false, true, np.get(1), np.get(8)), rn);
// 0[(5),8(9),12(6)]
// 5[(1),4(10),6(8)] 9[(7),10(4), ] 6[(3),14(2), ]
// 1[2, 3] 10[4,5] 8[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,15]
KeyAndValue<K, V> r2 = createLRecord(kconv, vconv, 2, 2);
btr.insert(r2.getKey(), r2.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(8, np.get(9), kconv), createLRecord(12, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r2, r3), false, true, null, np.get(10)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(4, np.get(10), kconv), createLRecord(6, np.get(8), kconv)), false, true), rn);
// 0[(13),8(14), ]
// *13[(5),4(12), ] *14[(9),12(6), ]
// 5[(1),2(11), ] *12[(10),6(8), ] 9[(7),10(4), ] 6[(3),14(2), ]
// 1[1,] *11[2,3] 10[4,5] 8[6,7] 7[8,9] 4[10,11] 3[12,13]
// 2[14,15]
KeyAndValue<K, V> r1 = createLRecord(kconv, vconv, 1, 1);
btr.insert(r1.getKey(), r1.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(13), createLRecordList(createLRecord(8, np.get(14), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(11)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r14, r15), false, true, np.get(3), null), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r12, r13), false, true, np.get(4), np.get(2)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r10, r11), false, true, np.get(7), np.get(3)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(2, np.get(11), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(12));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(12), np.get(3), createLRecordList(createLRecord(14, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r8, r9), false, true, np.get(8), np.get(4)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6, r7), false, true, np.get(10), np.get(7)), rn);
rn = nr.readNode(np.get(9), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(8), np.get(7), createLRecordList(createLRecord(10, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r4, r5), false, true, np.get(11), np.get(8)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r2, r3), false, true, np.get(1), np.get(10)), rn);
rn = nr.readNode(np.get(12), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(4), np.get(10), createLRecordList(createLRecord(6, np.get(8), kconv)), false, false), rn);
rn = nr.readNode(np.get(13), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(13), null, np.get(5), createLRecordList(createLRecord(4, np.get(12), kconv)), false, false), rn);
rn = nr.readNode(np.get(14), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(14), kconv.convert(8), np.get(9), createLRecordList(createLRecord(12, np.get(6), kconv)), false, false), rn);
// Delete 15
// 0[(13),8(14),]
// 13[(5),4(12),] 14[(9),12(6),]
// 5[(1),2(11),] 12[(10),6(8),] 9[(7),10(4),] 6[(3),14(2),]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 7[8,9] 4[10,11] 3[12,13] 2[14,]
assertEquals(r15.getValue(), btr.delete(r15.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r14), false, false, np.get(3), null), rn);
// Delete 14
// 0[(5),4(12),8(6)]
// 5[(1),2(11),] 12[(10),6(8),] 6[(7),10(4),12(2)]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 7[8,9] 4[10,11] 2[12,13]
assertEquals(r14.getValue(), btr.delete(r14.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(4, np.get(12), kconv), createLRecord(8, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r12, r13), false, true, np.get(4), null), rn);
assertNodeDeleted(nr, np.get(3));
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r10, r11), false, true, np.get(7), np.get(2)), rn);
rn = nr.readNode(np.get(6), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(8), np.get(7), createLRecordList(createLRecord(10, np.get(4), kconv), createLRecord(12, np.get(2), kconv)), false, true), rn);
assertNodeDeleted(nr, np.get(9));
assertNodeDeleted(nr, np.get(13));
assertNodeDeleted(nr, np.get(14));
// Delete 13
// 0[(5),4(12),8(6)]
// 5[(1),2(11),] 12[(10),6(8),] 6[(7),10(4),12(2)]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 7[8,9] 4[10,11] 2[12]
assertEquals(r13.getValue(), btr.delete(r13.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r12), false, false, np.get(4), null), rn);
// Delete 12
// 0[(5),4(12),8(6)]
// 5[(1),2(11),] 12[(10),6(8),] 6[(7),10(2),]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 7[8,9] 2[10,11]
assertEquals(r12.getValue(), btr.delete(r12.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r10, r11), false, true, np.get(7), null), rn);
assertNodeDeleted(nr, np.get(4));
rn = nr.readNode(np.get(6), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(8), np.get(7), createLRecordList(createLRecord(10, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r8, r9), false, true, np.get(8), np.get(2)), rn);
// Delete 11
// 0[(5),4(12),8(6)]
// 5[(1),2(11),] 12[(10),6(8),] 6[(7),10(2),]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 7[8,9] 2[10,]
assertEquals(r11.getValue(), btr.delete(r11.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r10), false, false, np.get(7), null), rn);
// Delete 10
// 0[(5),4(6),)]
// 5[(1),2(11),] 6[(10),6(8),8(2)]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 2[8,9]
assertEquals(r10.getValue(), btr.delete(r10.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(4, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r8, r9), false, true, np.get(8), null), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(10), createLRecordList(createLRecord(6, np.get(8), kconv), createLRecord(8, np.get(2), kconv)), false, true), rn);
assertNodeDeleted(nr, np.get(7));
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r6, r7), false, true, np.get(10), np.get(2)), rn);
assertNodeDeleted(nr, np.get(12));
// Delete 9
// 0[(5),4(6),)]
// 5[(1),2(11),] 6[(10),6(8),8(2)]
// 1[1,] 11[2,3] 10[4,5] 8[6,7] 2[8,]
assertEquals(r9.getValue(), btr.delete(r9.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r8), false, false, np.get(8), null), rn);
// Delete 8
// 0[(5),4(6),)]
// 5[(1),2(11),] 6[(10),6(2),]
// 1[1,] 11[2,3] 10[4,5] 2[6,7]
assertEquals(r8.getValue(), btr.delete(r8.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r6, r7), false, true, np.get(10), null), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(10), createLRecordList(createLRecord(6, np.get(2), kconv)), false, false), rn);
assertNodeDeleted(nr, np.get(8));
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r4, r5), false, true, np.get(11), np.get(2)), rn);
// Delete 7
// 0[(5),4(6),)]
// 5[(1),2(11),] 6[(10),6(2),]
// 1[1,] 11[2,3] 10[4,5] 2[6,]
assertEquals(r7.getValue(), btr.delete(r7.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r6), false, false, np.get(10), null), rn);
// Delete 6
// 0[(1),2(11),4(2)]
// 1[1,] 11[2,3] 2[4,5]
assertEquals(r6.getValue(), btr.delete(r6.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(2, np.get(11), kconv), createLRecord(4, np.get(2), kconv)), true, true), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r4, r5), false, true, np.get(11), null), rn);
assertNodeDeleted(nr, np.get(5));
assertNodeDeleted(nr, np.get(6));
assertNodeDeleted(nr, np.get(10));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r2, r3), false, true, np.get(1), np.get(2)), rn);
// Delete 5
// 0[(1),2(11),4(2)]
// 1[1,] 11[2,3] 2[4,]
assertEquals(r5.getValue(), btr.delete(r5.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r4), false, false, np.get(11), null), rn);
// Delete 4
// 0[(1),2(2),]
// 1[1,] 2[2,3]
assertEquals(r4.getValue(), btr.delete(r4.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(2, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2, r3), false, true, np.get(1), null), rn);
assertNodeDeleted(nr, np.get(11));
// Delete 3
// 0[(1),2(2),]
// 1[1,] 2[2,]
assertEquals(r3.getValue(), btr.delete(r3.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r2), false, false, np.get(1), null), rn);
// Delete 2
// 0[1,]
assertEquals(r2.getValue(), btr.delete(r2.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r1), true, false, null, null), rn);
assertNodeDeleted(nr, np.get(1));
assertNodeDeleted(nr, np.get(2));
// Delete 1
// 0[,]
assertEquals(r1.getValue(), btr.delete(r1.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), Collections.EMPTY_LIST, true, false, null, null), rn);
assertEquals(0, btr.size());
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(nr, kconv, vconv, getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 2), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 2, leafNodePointers));
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFrom15ToOneWithTwoRecordsPerNodeAndLruCacheInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testInsertFrom15ToOneWithTwoRecordsPerNode()
{
testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(0);
}
@Test
public void testInsertFrom15ToOneWithTwoRecordsPerNodeAndSmallLruCache()
{
testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(2);
}
@Test
public void testInsertFrom15ToOneWithTwoRecordsPerNodeAndLargeLruCache()
{
testInsertFrom15ToOneWithTwoRecordsPerNodeInternal(20);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(NodeRepository<K> nr, ValueConverter<K> kconv, ValueConverter<V> vconv, long nonLeafNodeSize, long leafNodeSize)
{
NodePositions np = new NodePositions(nonLeafNodeSize, leafNodeSize, nr.getPositionOfRootNode());
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// Insert 4, 2, 3, 9, 8, 6, 5, 1, 10, 7
// *0[4, ]
KeyAndValue<K, V> r4 = createLRecord(kconv, vconv, 4, 4);
btr.insert(r4.getKey(), r4.getValue());
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r4), true, false, null, null), rn);
// 0[2,4]
KeyAndValue<K, V> r2 = createLRecord(kconv, vconv, 2, 2);
btr.insert(r2.getKey(), r2.getValue());
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r2, r4), true, true, null, null), rn);
// 0[(1),3(2), ]
// *1[2, ] *2[3,4]
KeyAndValue<K, V> r3 = createLRecord(kconv, vconv, 3, 3);
btr.insert(r3.getKey(), r3.getValue());
np.addLeaf();
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r2), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r3, r4), false, true, np.get(1), null), rn);
// 0[(1),3(2),4(3)]
// 1[2, ] 2[3, ] *3[4,9]
KeyAndValue<K, V> r9 = createLRecord(kconv, vconv, 9, 9);
btr.insert(r9.getKey(), r9.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv), createLRecord(4, np.get(3), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r2), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r3), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r4, r9), false, true, np.get(2), null), rn);
assertEquals(4, btr.size());
// 0[(5),4(6), ]
// *5[(1),3(2), ] *6[(3),8(4), ]
// 1[2, ] 2[3, ] 3[4, ] *4[8,9]
KeyAndValue<K, V> r8 = createLRecord(kconv, vconv, 8, 8);
btr.insert(r8.getKey(), r8.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(4, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r2), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r3), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r4), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r8, r9), false, true, np.get(3), null), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(3), createLRecordList(createLRecord(8, np.get(4), kconv)), false, false), rn);
// 0[(5),4(6), ]
// 5[(1),3(2), ] 6[(3),8(4), ]
// 1[2, ] 2[3, ] 3[4,6] 4[8,9]
KeyAndValue<K, V> r6 = createLRecord(kconv, vconv, 6, 6);
btr.insert(r6.getKey(), r6.getValue());
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r4, r6), false, true, np.get(2), np.get(4)), rn);
// 0[(5),4(6), ]
// 5[(1),3(2), ] 6[(3),5(7),8(4)]
// 1[2, ] 2[3, ] 3[4, ] *7[5,6] 4[8,9]
KeyAndValue<K, V> r5 = createLRecord(kconv, vconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
np.addLeaf();
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r4), false, false, np.get(2), np.get(7)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r8, r9), false, true, np.get(7), null), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(3), createLRecordList(createLRecord(5, np.get(7), kconv), createLRecord(8, np.get(4), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5, r6), false, true, np.get(3), np.get(4)), rn);
// 0[(5),4(6), ]
// 5[(1),3(2), ] 6[(3),5(7),8(4)]
// 1[1,2] 2[3, ] 3[4, ] 7[5,6] 4[8,9]
KeyAndValue<K, V> r1 = createLRecord(kconv, vconv, 1, 1);
btr.insert(r1.getKey(), r1.getValue());
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1, r2), false, true, null, np.get(2)), rn);
// 0[(5),4(6),8(9)]
// 5[(1),3(2), ] 6[(3),5(7), ] *9[(4),9(8), ]
// 1[1,2] 2[3, ] 3[4, ] 7[5,6] 4[8, ] *8[9,10]
KeyAndValue<K, V> r10 = createLRecord(kconv, vconv, 10, 10);
btr.insert(r10.getKey(), r10.getValue());
np.addLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(4, np.get(6), kconv), createLRecord(8, np.get(9), kconv)), true, true), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r8), false, false, np.get(7), np.get(8)), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(3), createLRecordList(createLRecord(5, np.get(7), kconv)), false, false), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r9, r10), false, true, np.get(4), null), rn);
rn = nr.readNode(np.get(9), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(8), np.get(4), createLRecordList(createLRecord(9, np.get(8), kconv)), false, false), rn);
// 0[(5),4(6),8(9)]
// 5[(1),3(2), ] 6[(3),5(7),6(10)] 9[(4),9(8), ]
// 1[1,2] 2[3, ] 3[4, ] 7[5, ] *10[6,7] 4[8, ] 8[9,10]
KeyAndValue<K, V> r7 = createLRecord(kconv, vconv, 7, 7);
btr.insert(r7.getKey(), r7.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(4, np.get(6), kconv), createLRecord(8, np.get(9), kconv)), true, true), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1, r2), false, true, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r3), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r4), false, false, np.get(2), np.get(7)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r8), false, false, np.get(10), np.get(8)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(5), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(6), kconv.convert(4));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(4), np.get(3), createLRecordList(createLRecord(5, np.get(7), kconv), createLRecord(6, np.get(10), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createLRecordList(r5), false, false, np.get(3), np.get(10)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r9, r10), false, true, np.get(4), null), rn);
rn = nr.readNode(np.get(9), kconv.convert(8));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(9), kconv.convert(8), np.get(4), createLRecordList(createLRecord(9, np.get(8), kconv)), false, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r6, r7), false, true, np.get(7), np.get(4)), rn);
assertEquals(10, btr.size());
// Delete 4, 5, 6, 7, 2, 3, 9, 1, 8, 10
// Delete 4
// 0[(5),5(6),8(9)]
// 5[(1),3(2),] 6[(3),6(10),] 9[(4),9(8),]
// 1[1,2] 2[3,] 3[5,] 10[6,7] 4[8,] 8[9,10]
assertEquals(r4.getValue(), btr.delete(r4.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(5, np.get(6), kconv), createLRecord(8, np.get(9), kconv)), true, true), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r5), false, false, np.get(2), np.get(10)), rn);
rn = nr.readNode(np.get(6), kconv.convert(5));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), kconv.convert(5), np.get(3), createLRecordList(createLRecord(6, np.get(10), kconv)), false, false), rn);
assertNodeDeleted(nr, np.get(7));
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r6, r7), false, true, np.get(3), np.get(4)), rn);
// Delete 5
// 0[(6),8(9),]
// 6[(1),3(2),6(3)] 9[(4),9(8),]
// 1[1,2] 2[3,] 3[6,7] 4[8,] 8[9,10]
assertEquals(r5.getValue(), btr.delete(r5.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(6), createLRecordList(createLRecord(8, np.get(9), kconv)), true, false), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r6, r7), false, true, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r8), false, false, np.get(3), np.get(8)), rn);
assertNodeDeleted(nr, np.get(5));
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv), createLRecord(6, np.get(3), kconv)), false, true), rn);
assertNodeDeleted(nr, np.get(10));
// Delete 6
// 0[(6),8(9),]
// 6[(1),3(2),7(3)] 9[(4),9(8),]
// 1[1,2] 2[3,] 3[7,] 4[8,] 8[9,10]
assertEquals(r6.getValue(), btr.delete(r6.getKey()));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r7), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(3, np.get(2), kconv), createLRecord(7, np.get(3), kconv)), false, true), rn);
// Delete 7
// 0[(6),8(9),]
// 6[(1),3(3),] 9[(4),9(8),]
// 1[1,2] 3[3,] 4[8,] 8[9,10]
assertEquals(r7.getValue(), btr.delete(r7.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1, r2), false, true, null, np.get(3)), rn);
assertNodeDeleted(nr, np.get(2));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r3), false, false, np.get(1), np.get(4)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(3, np.get(3), kconv)), false, false), rn);
// Delete 2
// 0[(6),8(9),]
// 6[(1),3(3),] 9[(4),9(8),]
// 1[1,] 3[3,] 4[8,] 8[9,10]
assertEquals(r2.getValue(), btr.delete(r2.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r1), false, false, null, np.get(3)), rn);
// Delete 3
// 0[(3),8(4),9(8)]
// 3[1,] 4[8,] 8[9,10]
assertEquals(r3.getValue(), btr.delete(r3.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(3), createLRecordList(createLRecord(8, np.get(4), kconv), createLRecord(9, np.get(8), kconv)), true, true), rn);
assertNodeDeleted(nr, np.get(1));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r1), false, false, null, np.get(4)), rn);
assertNodeDeleted(nr, np.get(6));
assertNodeDeleted(nr, np.get(9));
// Delete 9
// 0[(3),8(4),10(8)]
// 3[1,] 4[8,] 8[10]
assertEquals(r9.getValue(), btr.delete(r9.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(3), createLRecordList(createLRecord(8, np.get(4), kconv), createLRecord(10, np.get(8), kconv)), true, true), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r10), false, false, np.get(4), null), rn);
// Delete 1
// 0[(3),10(8)]
// 3[8,] 8[10]
assertEquals(r1.getValue(), btr.delete(r1.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(3), createLRecordList(createLRecord(10, np.get(8), kconv)), true, false), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r8), false, false, null, np.get(8)), rn);
assertNodeDeleted(nr, np.get(4));
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r10), false, false, np.get(3), null), rn);
// Delete 8
// 0[10,]
assertEquals(r8.getValue(), btr.delete(r8.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r10), true, false, null, null), rn);
assertNodeDeleted(nr, np.get(3));
assertNodeDeleted(nr, np.get(8));
assertEquals(1, btr.size());
// Delete 10
// 0[,]
assertEquals(r10.getValue(), btr.delete(r10.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), Collections.EMPTY_LIST, true, false, null, null), rn);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(nr, kconv, vconv, getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 2), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 2, leafNodePointers));
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNode()
{
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(0);
}
@Test
public void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeAndSmallLruCache()
{
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(2);
}
@Test
public void testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeLargeLruCache()
{
testInsertFromOneToTenInRandomOrderWithTwoRecordsPerNodeInternal(20);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testInsertWithTreeRecordsPerNodeInternal(NodeRepository<K> nr, ValueConverter<K> kconv, ValueConverter<V> vconv, long nonLeafNodeSize, long leafNodeSize)
{
NodePositions np = new NodePositions(nonLeafNodeSize, leafNodeSize, nr.getPositionOfRootNode());
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// Insert 5, 10, 30, 50, 25, 15, 20, 55, 75, 80, 85, 60, 65, 90,
// 28, 70, 95, 72
// 5, 10, 30
// 0[5,10,30]
KeyAndValue<K, V> r5 = createLRecord(kconv, vconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
KeyAndValue<K, V> r10 = createLRecord(kconv, vconv, 10, 10);
btr.insert(r10.getKey(), r10.getValue());
KeyAndValue<K, V> r30 = createLRecord(kconv, vconv, 30, 30);
btr.insert(r30.getKey(), r30.getValue());
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r5, r10, r30), true, true, null, null), rn);
// 50
// 0[(1),30(2),,]
// *1[5,10,] *2[30,50,]
KeyAndValue<K, V> r50 = createLRecord(kconv, vconv, 50, 50);
btr.insert(r50.getKey(), r50.getValue());
np.addLeaf();
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(30, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50), false, false, np.get(1), null), rn);
// 25
// 0[(1),30(2),,]
// 1[5,10,25] 2[30,50,]
KeyAndValue<K, V> r25 = createLRecord(kconv, vconv, 25, 25);
btr.insert(r25.getKey(), r25.getValue());
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10, r25), false, true, null, np.get(2)), rn);
// 15
// 0[(1),15(3),30(2),]
// 1[5,10,] *3[15,25,] 2[30,50,]
KeyAndValue<K, V> r15 = createLRecord(kconv, vconv, 15, 15);
btr.insert(r15.getKey(), r15.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(30, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10), false, false, null, np.get(3)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50), false, false, np.get(3), null), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r15, r25), false, false, np.get(1), np.get(2)), rn);
// 20
// 0[(1),15(3),30(2),]
// 1[5,10,] 3[15,20,25] 2[30,50,]
KeyAndValue<K, V> r20 = createLRecord(kconv, vconv, 20, 20);
btr.insert(r20.getKey(), r20.getValue());
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r15, r20, r25), false, true, np.get(1), np.get(2)), rn);
// 55
// 0[(1),15(3),30(2),]
// 1[5,10,] 3[15,20,25] 2[30,50,55]
KeyAndValue<K, V> r55 = createLRecord(kconv, vconv, 55, 55);
btr.insert(r55.getKey(), r55.getValue());
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50, r55), false, true, np.get(3), null), rn);
// 75
// 0[(1),15(3),30(2),55(4)]
// 1[5,10,] 3[15,20,25] 2[30,50,] *4[55,75,]
KeyAndValue<K, V> r75 = createLRecord(kconv, vconv, 75, 75);
btr.insert(r75.getKey(), r75.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(30, np.get(2), kconv), createLRecord(55, np.get(4), kconv)), true, true), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50), false, false, np.get(3), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r75), false, false, np.get(2), null), rn);
// 80
// 0[(1),15(3),30(2),55(4)]
// 1[5,10,] 3[15,20,25] 2[30,50,] 4[55,75,80]
KeyAndValue<K, V> r80 = createLRecord(kconv, vconv, 80, 80);
btr.insert(r80.getKey(), r80.getValue());
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r75, r80), false, true, np.get(2), null), rn);
// 85
// 0[(6),55(7),,]
// *6[(1),15(3),30(2),] *7[(4),80(5),,]
// 1[5,10,] 3[15,20,25] 2[30,50,] 4[55,75,] *5[80,85,]
KeyAndValue<K, V> r85 = createLRecord(kconv, vconv, 85, 85);
btr.insert(r85.getKey(), r85.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(6), createLRecordList(createLRecord(55, np.get(7), kconv)), true, false), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r75), false, false, np.get(2), np.get(5)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r80, r85), false, false, np.get(4), null), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(30, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(7), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), kconv.convert(55), np.get(4), createLRecordList(createLRecord(80, np.get(5), kconv)), false, false), rn);
// 60
// 0[(6),55(7),,]
// 6[(1),15(3),30(2),] 7[(4),80(5),,]
// 1[5,10,] 3[15,20,25] 2[30,50,] 4[55,60,75] 5[80,85,]
KeyAndValue<K, V> r60 = createLRecord(kconv, vconv, 60, 60);
btr.insert(r60.getKey(), r60.getValue());
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r60, r75), false, true, np.get(2), np.get(5)), rn);
// 65
// 0[(6),55(7),,]
// 6[(1),15(3),30(2),] 7[(4),65(8),80(5),]
// 1[5,10,] 3[15,20,25] 2[30,50,] 4[55,60,] *8[65,75,] 5[80,85,]
KeyAndValue<K, V> r65 = createLRecord(kconv, vconv, 65, 65);
btr.insert(r65.getKey(), r65.getValue());
np.addLeaf();
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r60), false, false, np.get(2), np.get(8)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r80, r85), false, false, np.get(8), null), rn);
rn = nr.readNode(np.get(7), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), kconv.convert(55), np.get(4), createLRecordList(createLRecord(65, np.get(8), kconv), createLRecord(80, np.get(5), kconv)), false, false), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r65, r75), false, false, np.get(4), np.get(5)), rn);
// 90
// 0[(6),55(7),,]
// 6[(1),15(3),30(2),] 7[(4),65(8),80(5),]
// 1[5,10,] 3[15,20,25] 2[30,50,] 4[55,60,] 8[65,75,]
// 5[80,85,90]
KeyAndValue<K, V> r90 = createLRecord(kconv, vconv, 90, 90);
btr.insert(r90.getKey(), r90.getValue());
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r80, r85, r90), false, true, np.get(8), null), rn);
// 28
// 0[(6),55(7),,]
// 6[(1),15(3),25(9),30(2)] 7[(4),65(8),80(5),]
// 1[5,10,] 3[15,20,] *9[25,28,] 2[30,50,] 4[55,60,] 8[65,75,]
// 5[80,85,90]
KeyAndValue<K, V> r28 = createLRecord(kconv, vconv, 28, 28);
btr.insert(r28.getKey(), r28.getValue());
np.addLeaf();
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50), false, false, np.get(9), np.get(4)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r15, r20), false, false, np.get(1), np.get(9)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(25, np.get(9), kconv), createLRecord(30, np.get(2), kconv)), false, true), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createLRecordList(r25, r28), false, false, np.get(3), np.get(2)), rn);
// 70
// 0[(6),55(7),,]
// 6[(1),15(3),25(9),30(2)] 7[(4),65(8),80(5),]
// 1[5,10,] 3[15,20,] 9[25,28,] 2[30,50,] 4[55,60,] 8[65,70,75]
// 5[80,85,90]
KeyAndValue<K, V> r70 = createLRecord(kconv, vconv, 70, 70);
btr.insert(r70.getKey(), r70.getValue());
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r65, r70, r75), false, true, np.get(4), np.get(5)), rn);
// 95
// 0[(6),55(7),,]
// 6[(1),15(3),25(9),30(2)] 7[(4),65(8),80(5),90(10)]
// 1[5,10,] 3[15,20,] 9[25,28,] 2[30,50,] 4[55,60,] 8[65,70,75]
// 5[80,85,] *10[90,95,]
KeyAndValue<K, V> r95 = createLRecord(kconv, vconv, 95, 95);
btr.insert(r95.getKey(), r95.getValue());
np.addLeaf();
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r80, r85), false, false, np.get(8), np.get(10)), rn);
rn = nr.readNode(np.get(7), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), kconv.convert(55), np.get(4), createLRecordList(createLRecord(65, np.get(8), kconv), createLRecord(80, np.get(5), kconv), createLRecord(90, np.get(10), kconv)), false, true), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r90, r95), false, false, np.get(5), null), rn);
// 72
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),30(2)] 7[(4),65(8),72(11),]
// *12[(5),90(10),,]
// 1[5,10,] 3[15,20,] 9[25,28,] 2[30,50,] 4[55,60,] 8[65,70,]
// *11[72,75,] 5[80,85,] 10[90,95,]
KeyAndValue<K, V> r72 = createLRecord(kconv, vconv, 72, 72);
btr.insert(r72.getKey(), r72.getValue());
np.addLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(6), createLRecordList(createLRecord(55, np.get(7), kconv), createLRecord(80, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10), false, false, null, np.get(3)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r30, r50), false, false, np.get(9), np.get(4)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r15, r20), false, false, np.get(1), np.get(9)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r60), false, false, np.get(2), np.get(8)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r80, r85), false, false, np.get(11), np.get(10)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(25, np.get(9), kconv), createLRecord(30, np.get(2), kconv)), false, true), rn);
rn = nr.readNode(np.get(7), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), kconv.convert(55), np.get(4), createLRecordList(createLRecord(65, np.get(8), kconv), createLRecord(72, np.get(11), kconv)), false, false), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createLRecordList(r65, r70), false, false, np.get(4), np.get(11)), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createLRecordList(r25, r28), false, false, np.get(3), np.get(2)), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r90, r95), false, false, np.get(5), null), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r72, r75), false, false, np.get(8), np.get(5)), rn);
rn = nr.readNode(np.get(12), kconv.convert(80));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(80), np.get(5), createLRecordList(createLRecord(90, np.get(10), kconv)), false, false), rn);
// Delete 75, 30, 20, 10, 72, 90, 5, 70, 65, 95, 25, 28, 50, 60,
// 80, 55, 15, 85
// Delete 75
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),30(2)] 7[(4),65(8),72(11),]
// 12[(5),90(10),,]
// 1[5,10,] 3[15,20,] 9[25,28,] 2[30,50,] 4[55,60,] 8[65,70,]
// 11[72,,] 5[80,85,] 10[90,95,]
assertEquals(r75.getValue(), btr.delete(r75.getKey()));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r72), false, false, np.get(8), np.get(5)), rn);
// Delete 30
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),50(2)] 7[(4),65(8),72(11),]
// 12[(5),90(10),,]
// 1[5,10,] 3[15,20,] 9[25,28,] 2[50,,] 4[55,60,] 8[65,70,]
// 11[72,,] 5[80,85,] 10[90,95,]
assertEquals(r30.getValue(), btr.delete(r30.getKey()));
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r50), false, false, np.get(9), np.get(4)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(15, np.get(3), kconv), createLRecord(25, np.get(9), kconv), createLRecord(50, np.get(2), kconv)), false, true), rn);
// Delete 20
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),50(2)] 7[(4),65(8),72(11),]
// 12[(5),90(10),,]
// 1[5,10,] 3[15,,] 9[25,28,] 2[50,,] 4[55,60,] 8[65,70,]
// 11[72,,] 5[80,85,] 10[90,95,]
assertEquals(r20.getValue(), btr.delete(r20.getKey()));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r15), false, false, np.get(1), np.get(9)), rn);
// Delete 10
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),50(2)] 7[(4),65(8),72(11),]
// 12[(5),90(10),,]
// 1[5,,] 3[15,,] 9[25,28,] 2[50,,] 4[55,60,] 8[65,70,] 11[72,,]
// 5[80,85,] 10[90,95,]
assertEquals(r10.getValue(), btr.delete(r10.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5), false, false, null, np.get(3)), rn);
// Delete 72
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),50(2)] 7[(4),65(11),,] 12[(5),90(10),,]
// 1[5,,] 3[15,,] 9[25,28,] 2[50,,] 4[55,60,] 11[65,70,]
// 5[80,85,] 10[90,95,]
assertEquals(r72.getValue(), btr.delete(r72.getKey()));
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r55, r60), false, false, np.get(2), np.get(11)), rn);
rn = nr.readNode(np.get(7), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), kconv.convert(55), np.get(4), createLRecordList(createLRecord(65, np.get(11), kconv)), false, false), rn);
assertNodeDeleted(nr, np.get(8));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r65, r70), false, false, np.get(4), np.get(5)), rn);
// Delete 90
// 0[(6),55(7),80(12),]
// 6[(1),15(3),25(9),50(2)] 7[(4),65(11),,] 12[(5),95(10),,]
// 1[5,,] 3[15,,] 9[25,28,] 2[50,,] 4[55,60,] 11[65,70,]
// 5[80,85,] 10[95,,]
assertEquals(r90.getValue(), btr.delete(r90.getKey()));
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r95), false, false, np.get(5), null), rn);
rn = nr.readNode(np.get(12), kconv.convert(80));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(80), np.get(5), createLRecordList(createLRecord(95, np.get(10), kconv)), false, false), rn);
// Delete 5
// 0[(6),55(7),80(12),]
// 6[(1),25(9),50(2),] 7[(4),65(11),,] 12[(5),95(10),,]
// 1[15,,] 9[25,28,] 2[50,,] 4[55,60,] 11[65,70,] 5[80,85,]
// 10[95,,]
assertEquals(r5.getValue(), btr.delete(r5.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r15), false, false, null, np.get(9)), rn);
assertNodeDeleted(nr, np.get(3));
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(6), null, np.get(1), createLRecordList(createLRecord(25, np.get(9), kconv), createLRecord(50, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createLRecordList(r25, r28), false, false, np.get(1), np.get(2)), rn);
// Delete 70
// 0[(6),55(7),80(12),]
// 6[(1),25(9),50(2),] 7[(4),65(11),,] 12[(5),95(10),,]
// 1[15,,] 9[25,28,] 2[50,,] 4[55,60,] 11[65,,] 5[80,85,]
// 10[95,,]
assertEquals(r70.getValue(), btr.delete(r70.getKey()));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r65), false, false, np.get(4), np.get(5)), rn);
// Delete 65
// 0[(7),80(12),,]
// 7[(1),25(9),50(2),55(11)] 12[(5),95(10),,]
// 1[15,,] 9[25,28,] 2[50,,] 11[55,60,] 5[80,85,] 10[95,,]
assertEquals(r65.getValue(), btr.delete(r65.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(7), createLRecordList(createLRecord(80, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r50), false, false, np.get(9), np.get(11)), rn);
assertNodeDeleted(nr, np.get(4));
assertNodeDeleted(nr, np.get(6));
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), null, np.get(1), createLRecordList(createLRecord(25, np.get(9), kconv), createLRecord(50, np.get(2), kconv), createLRecord(55, np.get(11), kconv)), false, true), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r55, r60), false, false, np.get(2), np.get(5)), rn);
// Delete 95
// 0[(7),55(12),,]
// 7[(1),25(9),50(2),] 12[(11),80(10),,]
// 1[15,,] 9[25,28,] 2[50,,] 11[55,60,] 10[80,85,]
assertEquals(r95.getValue(), btr.delete(r95.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(7), createLRecordList(createLRecord(55, np.get(12), kconv)), true, false), rn);
assertNodeDeleted(nr, np.get(5));
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), null, np.get(1), createLRecordList(createLRecord(25, np.get(9), kconv), createLRecord(50, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r80, r85), false, false, np.get(11), null), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r55, r60), false, false, np.get(2), np.get(10)), rn);
rn = nr.readNode(np.get(12), kconv.convert(55));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(55), np.get(11), createLRecordList(createLRecord(80, np.get(10), kconv)), false, false), rn);
// Delete 25
// 0[(7),55(12),,]
// 7[(1),25(9),50(2),] 12[(11),80(10),,]
// 1[15,,] 9[28,,] 2[50,,] 11[55,60,] 10[80,85,]
assertEquals(r25.getValue(), btr.delete(r25.getKey()));
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createLRecordList(r28), false, false, np.get(1), np.get(2)), rn);
// Delete 28
// 0[(7),55(12),,]
// 7[(9),50(2),,] 12[(11),80(10),,]
// 9[15,,] 2[50,,] 11[55,60,] 10[80,85,]
assertEquals(r28.getValue(), btr.delete(r28.getKey()));
assertNodeDeleted(nr, np.get(1));
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), null, np.get(9), createLRecordList(createLRecord(50, np.get(2), kconv)), false, false), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createLRecordList(r15), false, false, null, np.get(2)), rn);
// Delete 50
// 0[(2),55(11),80(10),]
// 2[15,,] 11[55,60,] 10[80,85,]
assertEquals(r50.getValue(), btr.delete(r50.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(2), createLRecordList(createLRecord(55, np.get(11), kconv), createLRecord(80, np.get(10), kconv)), true, false), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r15), false, false, null, np.get(11)), rn);
assertNodeDeleted(nr, np.get(7));
assertNodeDeleted(nr, np.get(9));
assertNodeDeleted(nr, np.get(12));
// Delete 60
// 0[(2),55(11),80(10),]
// 2[15,,] 11[55,,] 10[80,85,]
assertEquals(r60.getValue(), btr.delete(r60.getKey()));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r55), false, false, np.get(2), np.get(10)), rn);
// Delete 80
// 0[(2),55(11),85(10),]
// 2[15,,] 11[55,,] 10[85,,]
assertEquals(r80.getValue(), btr.delete(r80.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(2), createLRecordList(createLRecord(55, np.get(11), kconv), createLRecord(85, np.get(10), kconv)), true, false), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(r85), false, false, np.get(11), null), rn);
// Delete 55
// 0[(2),85(10),,]
// 11[15,,] 10[85,,]
assertEquals(r55.getValue(), btr.delete(r55.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(11), createLRecordList(createLRecord(85, np.get(10), kconv)), true, false), rn);
assertNodeDeleted(nr, np.get(2));
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(11), createLRecordList(r15), false, false, null, np.get(10)), rn);
// Delete 15
// 0[85,,]
assertEquals(r15.getValue(), btr.delete(r15.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r85), true, false, null, null), rn);
assertNodeDeleted(nr, np.get(10));
assertNodeDeleted(nr, np.get(11));
// Delete 85
// 0[,,]
assertEquals(r85.getValue(), btr.delete(r85.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), Collections.EMPTY_LIST, true, false, null, null), rn);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testInsertWithThreeRecordsPerNodeInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(3), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testInsertWithTreeRecordsPerNodeInternal(nr, kconv, vconv, getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 3), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 3, leafNodePointers));
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testInsertWithThreeRecordsPerNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testInsertWithThreeRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithThreeRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testInsertWithThreeRecordsPerNode()
{
testInsertWithThreeRecordsPerNodeInternal(0);
}
@Test
public void testInsertWithThreeRecordsPerNodeAndSmallLruCache()
{
testInsertWithThreeRecordsPerNodeInternal(2);
}
@Test
public void testInsertWithThreeRecordsPerNodeAndLargeLruCache()
{
testInsertWithThreeRecordsPerNodeInternal(20);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testInsertWithFourRecordsPerNodeInternal(NodeRepository<K> nr, NodePositions np, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// Insert 5, 10, 30, 50, 25, 15, 20, 55, 75, 80, 85, 60, 65, 90, 73,
// 100
// 0[(1),25(2),50(3),75(4), ]
// 1[5,10,15,20] 2[25,30,,] 3[50,55,60,65] 4[75,80,85,90]
KeyAndValue<K, V> r5 = createLRecord(kconv, vconv, 5, 5);
btr.insert(r5.getKey(), r5.getValue());
KeyAndValue<K, V> r10 = createLRecord(kconv, vconv, 10, 10);
btr.insert(r10.getKey(), r10.getValue());
KeyAndValue<K, V> r30 = createLRecord(kconv, vconv, 30, 30);
btr.insert(r30.getKey(), r30.getValue());
KeyAndValue<K, V> r50 = createLRecord(kconv, vconv, 50, 50);
btr.insert(r50.getKey(), r50.getValue());
KeyAndValue<K, V> r25 = createLRecord(kconv, vconv, 25, 25);
btr.insert(r25.getKey(), r25.getValue());
KeyAndValue<K, V> r15 = createLRecord(kconv, vconv, 15, 15);
btr.insert(r15.getKey(), r15.getValue());
KeyAndValue<K, V> r20 = createLRecord(kconv, vconv, 20, 20);
btr.insert(r20.getKey(), r20.getValue());
KeyAndValue<K, V> r55 = createLRecord(kconv, vconv, 55, 55);
btr.insert(r55.getKey(), r55.getValue());
KeyAndValue<K, V> r75 = createLRecord(kconv, vconv, 75, 75);
btr.insert(r75.getKey(), r75.getValue());
KeyAndValue<K, V> r80 = createLRecord(kconv, vconv, 80, 80);
btr.insert(r80.getKey(), r80.getValue());
KeyAndValue<K, V> r85 = createLRecord(kconv, vconv, 85, 85);
btr.insert(r85.getKey(), r85.getValue());
KeyAndValue<K, V> r60 = createLRecord(kconv, vconv, 60, 60);
btr.insert(r60.getKey(), r60.getValue());
KeyAndValue<K, V> r65 = createLRecord(kconv, vconv, 65, 65);
btr.insert(r65.getKey(), r65.getValue());
KeyAndValue<K, V> r90 = createLRecord(kconv, vconv, 90, 90);
btr.insert(r90.getKey(), r90.getValue());
np.addLeaf();
np.addLeaf();
np.addLeaf();
np.addLeaf();
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(25, np.get(2), kconv), createLRecord(50, np.get(3), kconv), createLRecord(75, np.get(4), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10, r15, r20), false, true, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r25, r30), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r50, r55, r60, r65), false, true, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r75, r80, r85, r90), false, true, np.get(3), null), rn);
// Insert 28
// 0[(1),25(2),50(3),75(4), ]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,60,65] 4[75,80,85,90]
KeyAndValue<K, V> r28 = createLRecord(kconv, vconv, 28, 28);
btr.insert(r28.getKey(), r28.getValue());
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r25, r28, r30), false, false, np.get(1), np.get(3)), rn);
// Insert 70
// 0[(1),25(2),50(3),60(5),75(4)]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,,] *5[60,65,70,]
// 4[75,80,85,90]
KeyAndValue<K, V> r70 = createLRecord(kconv, vconv, 70, 70);
btr.insert(r70.getKey(), r70.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(25, np.get(2), kconv), createLRecord(50, np.get(3), kconv), createLRecord(60, np.get(5), kconv), createLRecord(75, np.get(4), kconv)), true, true), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r50, r55), false, false, np.get(2), np.get(5)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r75, r80, r85, r90), false, true, np.get(5), null), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r60, r65, r70), false, false, np.get(3), np.get(4)), rn);
// Insert 95
// *0[(7),60(8),,,]
// *7[(1),25(2),50(3),,] *8[(5),75(4),85(6),,]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,,] 5[60,65,70,] 4[75,80,,]
// *6[85,90,95,]
KeyAndValue<K, V> r95 = createLRecord(kconv, vconv, 95, 95);
btr.insert(r95.getKey(), r95.getValue());
np.addLeaf();
np.addNonLeaf();
np.addNonLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(7), createLRecordList(createLRecord(60, np.get(8), kconv)), true, false), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r75, r80), false, false, np.get(5), np.get(6)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createLRecordList(r85, r90, r95), false, false, np.get(4), null), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), null, np.get(1), createLRecordList(createLRecord(25, np.get(2), kconv), createLRecord(50, np.get(3), kconv)), false, false), rn);
rn = nr.readNode(np.get(8), kconv.convert(60));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(8), kconv.convert(60), np.get(5), createLRecordList(createLRecord(75, np.get(4), kconv), createLRecord(85, np.get(6), kconv)), false, false), rn);
// Insert 73
// 0[(7),60(8),,,]
// 7[(1),25(2),50(3),,] 8[(5),75(4),85(6),,]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,,] *5[60,65,70,73] 4[75,80,,]
// 6[85,90,95,]
KeyAndValue<K, V> r73 = createLRecord(kconv, vconv, 73, 73);
btr.insert(r73.getKey(), r73.getValue());
np.addLeaf();
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r60, r65, r70, r73), false, true, np.get(3), np.get(4)), rn);
// Insert 100
// 0[(7),60(8),,,]
// 7[(1),25(2),50(3),,] 8[(5),75(4),85(6),,]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,,] 5[60,65,70,73] 4[75,80,,]
// *6[85,90,95,100]
KeyAndValue<K, V> r100 = createLRecord(kconv, vconv, 100, 100);
btr.insert(r100.getKey(), r100.getValue());
np.addLeaf();
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(7), createLRecordList(createLRecord(60, np.get(8), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r5, r10, r15, r20), false, true, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(r25, r28, r30), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r50, r55), false, false, np.get(2), np.get(5)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r75, r80), false, false, np.get(5), np.get(6)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r60, r65, r70, r73), false, true, np.get(3), np.get(4)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createLRecordList(r85, r90, r95, r100), false, true, np.get(4), null), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(7), null, np.get(1), createLRecordList(createLRecord(25, np.get(2), kconv), createLRecord(50, np.get(3), kconv)), false, false), rn);
rn = nr.readNode(np.get(8), kconv.convert(60));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(8), kconv.convert(60), np.get(5), createLRecordList(createLRecord(75, np.get(4), kconv), createLRecord(85, np.get(6), kconv)), false, false), rn);
// Delete 75, 55, 85, 60, 5, 15, 30, 10, 50, 65, 25, 80, 90, 20,
// 100,
// 73, 28, 95, 70
// Delete 75 (will steal leaf node 73)
// 0[(7),60(8),,,]
// 7[(1),25(2),50(3),,] 8[(5),73(4),85(6),,]
// 1[5,10,15,20] 2[25,28,30,] 3[50,55,,] 5[60,65,70,] 4[73,80,,]
// 6[85,90,95,100,]
assertEquals(r75.getValue(), btr.delete(r75.getKey()));
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r73, r80), false, false, np.get(5), np.get(6)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r60, r65, r70), false, false, np.get(3), np.get(4)), rn);
rn = nr.readNode(np.get(8), kconv.convert(60));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(8), kconv.convert(60), np.get(5), createLRecordList(createLRecord(73, np.get(4), kconv), createLRecord(85, np.get(6), kconv)), false, false), rn);
// Delete 55
// 0[(1),25(3),60(5),73(4),85(6)]
// 1[5,10,15,20] 3[25,28,30,50] 5[60,65,70,] 4[73,80,,]
// 6[85,90,95,100,]
assertEquals(r55.getValue(), btr.delete(r55.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(25, np.get(3), kconv), createLRecord(60, np.get(5), kconv), createLRecord(73, np.get(4), kconv), createLRecord(85, np.get(6), kconv)), true, true), rn);
assertNodeDeleted(nr, np.get(2));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r25, r28, r30, r50), false, true, np.get(1), np.get(5)), rn);
assertNodeDeleted(nr, np.get(7));
assertNodeDeleted(nr, np.get(8));
// Delete 85
// 0[(1),25(3),60(5),73(4),90(6)]
// 1[5,10,15,20] 3[25,28,30,50] 5[60,65,70,] 4[73,80,,]
// 6[90,95,100,,]
assertEquals(r85.getValue(), btr.delete(r85.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(25, np.get(3), kconv), createLRecord(60, np.get(5), kconv), createLRecord(73, np.get(4), kconv), createLRecord(90, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createLRecordList(r90, r95, r100), false, false, np.get(4), null), rn);
// Delete 60
// 0[(1),25(3),65(5),73(4),90(6)]
// 1[5,10,15,20] 3[25,28,30,50] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r60.getValue(), btr.delete(r60.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(25, np.get(3), kconv), createLRecord(65, np.get(5), kconv), createLRecord(73, np.get(4), kconv), createLRecord(90, np.get(6), kconv)), true, true), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r65, r70), false, false, np.get(3), np.get(4)), rn);
// Delete 5
// 0[(1),25(3),65(5),73(4),90(6)]
// 1[10,15,20,] 3[25,28,30,50] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r5.getValue(), btr.delete(r5.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r10, r15, r20), false, false, null, np.get(3)), rn);
// Delete 15
// 0[(1),25(3),65(5),73(4),90(6)]
// 1[10,20,,] 3[25,28,30,50] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r15.getValue(), btr.delete(r15.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r10, r20), false, false, null, np.get(3)), rn);
// Delete 30
// 0[(1),25(3),65(5),73(4),90(6)]
// 1[10,20,,] 3[25,28,50,] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r30.getValue(), btr.delete(r30.getKey()));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createLRecordList(r25, r28, r50), false, false, np.get(1), np.get(5)), rn);
// Delete 10
// 0[(1),65(5),73(4),90(6),]
// 1[20,25,28,50] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r10.getValue(), btr.delete(r10.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(65, np.get(5), kconv), createLRecord(73, np.get(4), kconv), createLRecord(90, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r20, r25, r28, r50), false, true, null, np.get(5)), rn);
assertNodeDeleted(nr, np.get(3));
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r65, r70), false, false, np.get(1), np.get(4)), rn);
// Delete 50
// 0[(1),65(5),73(4),90(6),]
// 1[20,25,28,] 5[65,70,,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r50.getValue(), btr.delete(r50.getKey()));
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(r20, r25, r28), false, false, null, np.get(5)), rn);
// Delete 65
// 0[(5),73(4),90(6),]
// 5[20,25,28,70] 4[73,80,,] 6[90,95,100,,]
assertEquals(r65.getValue(), btr.delete(r65.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(5), createLRecordList(createLRecord(73, np.get(4), kconv), createLRecord(90, np.get(6), kconv)), true, false), rn);
assertNodeDeleted(nr, np.get(1));
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r20, r25, r28, r70), false, true, null, np.get(4)), rn);
// Delete 25
// 0[(5),73(4),90(6),]
// 5[20,28,70,] 4[73,80,,] 6[90,95,100,,]
assertEquals(r25.getValue(), btr.delete(r25.getKey()));
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createLRecordList(r20, r28, r70), false, false, null, np.get(4)), rn);
// Delete 80
// 0[(4),90(6),,]
// 4[20,28,70,73] 6[90,95,100,,]
assertEquals(r80.getValue(), btr.delete(r80.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(4), createLRecordList(createLRecord(90, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r20, r28, r70, r73), false, true, null, np.get(6)), rn);
assertNodeDeleted(nr, np.get(5));
// Delete 90
// 0[(4),95(6),,]
// 4[20,28,70,73] 6[95,100,,]
assertEquals(r90.getValue(), btr.delete(r90.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(4), createLRecordList(createLRecord(95, np.get(6), kconv)), true, false), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createLRecordList(r95, r100), false, false, np.get(4), null), rn);
// Delete 20
// 0[(4),95(6),,]
// 4[28,70,73,] 6[95,100,,]
assertEquals(r20.getValue(), btr.delete(r20.getKey()));
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createLRecordList(r28, r70, r73), false, false, null, np.get(6)), rn);
// Delete 100
// 0[28,70,73,95]
assertEquals(r100.getValue(), btr.delete(r100.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r28, r70, r73, r95), true, true, null, null), rn);
assertNodeDeleted(nr, np.get(4));
assertNodeDeleted(nr, np.get(6));
// Delete 73
// 0[28,70,95,]
assertEquals(r73.getValue(), btr.delete(r73.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r28, r70, r95), true, false, null, null), rn);
// Delete 28
// 0[70,95,,]
assertEquals(r28.getValue(), btr.delete(r28.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r70, r95), true, false, null, null), rn);
// Delete 95
// 0[70,,,]
assertEquals(r95.getValue(), btr.delete(r95.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), createLRecordList(r70), true, false, null, null), rn);
// Delete 70
// 0[,,,]
assertEquals(r70.getValue(), btr.delete(r70.getKey()));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(0), Collections.EMPTY_LIST, true, false, null, null), rn);
}
finally
{
btr.close();
}
}
@Test
public void testInsertWithFourRecordsPerNodeAndASlightlyTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
int nodeSize = new NumberOfRecordsNodeSizeStrategy(4).getNodeSize(9, 2 * LongSerializer.DATA_SIZE, 0) + 3;
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(nodeSize), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testInsertWithFourRecordsPerNodeInternal(nr, new NodePositions(nodeSize, nodeSize, nr.getPositionOfRootNode()), LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private <K extends Comparable<K>, V> void testInsertWithFourRecordsPerNodeInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(4), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testInsertWithFourRecordsPerNodeInternal(nr, new NodePositions(getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 4), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 4, leafNodePointers), nr.getPositionOfRootNode()), kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testInsertWithFourRecordsPerNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testInsertWithFourRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testInsertWithFourRecordsPerNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testInsertWithFourRecordsPerNode()
{
testInsertWithFourRecordsPerNodeInternal(0);
}
@Test
public void testInsertWithFourRecordsPerNodeAndSmallLruCache()
{
testInsertWithFourRecordsPerNodeInternal(2);
}
@Test
public void testInsertWithFourRecordsPerNodeAndLargeLruCache()
{
testInsertWithFourRecordsPerNodeInternal(20);
}
@Test
public void testInsertDuplicateKey()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah);
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(nr, lah);
try
{
btr.insert(2L, 3L);
try
{
btr.insert(2L, 4L);
fail();
}
catch (KeyExistsException e)
{
// ok
}
assertEquals(3L, btr.find(2L).longValue());
assertEquals(2L, btr.findRecord(2L, SearchMode.EXACT_MATCH).getKey().longValue());
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testInsertOrReplace()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah);
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(nr, lah);
try
{
assertFalse(btr.insertOrReplace(2L, 3L));
assertTrue(btr.insertOrReplace(2L, 4L));
assertEquals(4L, btr.find(2L).longValue());
assertEquals(2L, btr.findRecord(2L, SearchMode.EXACT_MATCH).getKey().longValue());
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private <K extends Comparable<K>, V> void insertTestRecords(BPlusTree<K, V> btr, List<KeyAndValue<K, V>> records)
{
for (KeyAndValue<K, V> record : records)
{
btr.insert(record.getKey(), record.getValue());
}
}
private static final int[] TEST_KEYS = new int[] { 5, 10, 30, 50, 25, 15, 20, 55, 75, 80, 85, 60, 65, 90, 73, 100 };
private static final int[] TEST_KEYS_SORTED;
static
{
TEST_KEYS_SORTED = new int[TEST_KEYS.length];
System.arraycopy(TEST_KEYS, 0, TEST_KEYS_SORTED, 0, TEST_KEYS.length);
Arrays.sort(TEST_KEYS_SORTED);
}
/**
* Insert 5, 10, 30, 50, 25, 15, 20, 55, 75, 80, 85, 60, 65, 90, 73, 100
* @param btr
*/
private <K extends Comparable<K>, V> void insertTestRecords(BPlusTree<K, V> btr, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
btr.insert(kconv.convert(5), vconv.convert(5));
btr.insert(kconv.convert(10), vconv.convert(10));
btr.insert(kconv.convert(30), vconv.convert(30));
btr.insert(kconv.convert(50), vconv.convert(50));
btr.insert(kconv.convert(25), vconv.convert(25));
btr.insert(kconv.convert(15), vconv.convert(15));
btr.insert(kconv.convert(20), vconv.convert(20));
btr.insert(kconv.convert(55), vconv.convert(55));
btr.insert(kconv.convert(75), vconv.convert(75));
btr.insert(kconv.convert(80), vconv.convert(80));
btr.insert(kconv.convert(85), vconv.convert(85));
btr.insert(kconv.convert(60), vconv.convert(60));
btr.insert(kconv.convert(65), vconv.convert(65));
btr.insert(kconv.convert(90), vconv.convert(90));
btr.insert(kconv.convert(73), vconv.convert(73));
btr.insert(kconv.convert(100), vconv.convert(100));
}
/**
* @param expected Must be sorted.
*/
private <K extends Comparable<K>> void verifyNextAndPreviousRecords(BPlusTree<K, ?> btr, int[] expected)
{
if (btr.isIteratorSupported())
{
// Forward
KeyAndValue<K, ?> rec = btr.getFirstRecord();
KeyAndValue<K, ?> prevRec = null;
assertNull(btr.getPreviousRecord(rec.getKey()));
for (int i = 0; i < expected.length; i++)
{
assertEquals(expected[i], ((Number) rec.getKey()).intValue());
if (i > 0)
{
assertEquals(prevRec.getKey(), btr.getPreviousRecord(rec.getKey()).getKey());
assertTrue(((Number) prevRec.getKey()).intValue() < ((Number) rec.getKey()).intValue());
}
prevRec = rec;
rec = btr.getNextRecord(rec.getKey());
if (i < (expected.length - 1))
{
assertNotNull(rec);
}
}
assertNull(rec);
// Backwards
rec = prevRec;
prevRec = null;
for (int i = expected.length - 1; i >= 0; i--)
{
assertEquals(expected[i], ((Number) rec.getKey()).intValue());
if (i < (expected.length - 1))
{
assertEquals(prevRec.getKey(), btr.getNextRecord(rec.getKey()).getKey());
}
prevRec = rec;
rec = btr.getPreviousRecord(rec.getKey());
if (i > 0)
{
assertNotNull(rec);
}
}
assertNull(rec);
}
}
/**
* @param l (A copy) is sorted by this method.
*/
private <K extends Comparable<K>> void verifyNextAndPreviousRecords(BPlusTree<K, ?> btr, List<? extends KeyAndValue<K, ?>> l)
{
if (btr.isIteratorSupported())
{
int[] expected = new int[l.size()];
for (int i = 0; i < l.size(); i++)
{
expected[i] = ((Number) l.get(i).getKey()).intValue();
}
Arrays.sort(expected);
verifyNextAndPreviousRecords(btr, expected);
}
}
private <K extends Comparable<K>, V> List<KeyAndValue<K, V>> createInterval(int first, int last, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
List<KeyAndValue<K, V>> res = new ArrayList<KeyAndValue<K, V>>(last - first + 1);
for (int i = first; i <= last; i++)
{
res.add(createLRecord(kconv, vconv, i, i));
}
return res;
}
private <K extends Comparable<K>, V> List<KeyAndValue<K, V>> mergeIntervals(List<KeyAndValue<K, V>>... intervals)
{
List<KeyAndValue<K, V>> res = new ArrayList<KeyAndValue<K, V>>();
for (List<KeyAndValue<K, V>> l : intervals)
{
res.addAll(l);
}
return res;
}
private <V> void testFindKeyInternal(NodeRepository<Character> nr, ValueConverter<Character> kconv, ValueConverter<V> vconv)
{
BPlusTree<Character, V> btr = new BPlusTree<Character, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
insertTestRecords(btr, kconv, vconv);
assertNull(btr.findRecord(kconv.convert(4), SearchMode.EXACT_MATCH));
assertEquals(5, btr.findRecord(kconv.convert(4), SearchMode.CLOSEST_ABOVE).getKey().charValue());
assertNull(btr.findRecord(kconv.convert(4), SearchMode.CLOSEST_BELOW));
assertEquals(5, btr.findRecord(kconv.convert(4), SearchMode.CLOSEST_MATCH).getKey().charValue());
for (int i = 0; i < TEST_KEYS_SORTED.length - 1; i++)
{
int thisKeyValue = TEST_KEYS_SORTED[i];
int nextKeyValue = TEST_KEYS_SORTED[i + 1];
assertEquals(thisKeyValue, btr.findRecord(kconv.convert(TEST_KEYS_SORTED[i]), SearchMode.CLOSEST_BELOW).getKey().charValue());
assertEquals(thisKeyValue, btr.findRecord(kconv.convert(TEST_KEYS_SORTED[i]), SearchMode.CLOSEST_ABOVE).getKey().charValue());
assertEquals(thisKeyValue, btr.findRecord(kconv.convert(TEST_KEYS_SORTED[i]), SearchMode.CLOSEST_MATCH).getKey().charValue());
for (int j = TEST_KEYS_SORTED[i] + 1; j < TEST_KEYS_SORTED[i + 1]; j++)
{
assertEquals(thisKeyValue, btr.findRecord(kconv.convert(j), SearchMode.CLOSEST_BELOW).getKey().charValue());
assertEquals(nextKeyValue, btr.findRecord(kconv.convert(j), SearchMode.CLOSEST_ABOVE).getKey().charValue());
if ((j - thisKeyValue) < (nextKeyValue - j))
{
assertEquals(thisKeyValue, btr.findRecord(kconv.convert(j), SearchMode.CLOSEST_MATCH).getKey().charValue());
}
else if ((nextKeyValue - j) < (j - thisKeyValue))
{
assertEquals(nextKeyValue, btr.findRecord(kconv.convert(j), SearchMode.CLOSEST_MATCH).getKey().charValue());
}
else
{
int val = btr.findRecord(kconv.convert(j), SearchMode.CLOSEST_MATCH).getKey();
assertTrue(val == thisKeyValue || val == nextKeyValue);
}
}
}
assertNull(btr.findRecord(kconv.convert(101), SearchMode.EXACT_MATCH));
assertNull(btr.findRecord(kconv.convert(101), SearchMode.CLOSEST_ABOVE));
assertEquals(100, btr.findRecord(kconv.convert(101), SearchMode.CLOSEST_BELOW).getKey().charValue());
assertEquals(100, btr.findRecord(kconv.convert(101), SearchMode.CLOSEST_MATCH).getKey().charValue());
}
finally
{
btr.close();
}
}
private <V> void testFindKeyInternal(Serializer<Character> keySerializer, ValueConverter<Character> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<Character> nr = new FileBackedNodeRepository<Character, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(4), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<Character, V>(nr, cacheSize);
}
testFindKeyInternal(nr, kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testFindKeyInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
// Must use Character since the compareTo methods of the Number
// classes does not give distances as required.
testFindKeyInternal(CharacterNullSerializer.INSTANCE, CHARACTER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, true);
testFindKeyInternal(CharacterNullSerializer.INSTANCE, CHARACTER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, true);
testFindKeyInternal(CharacterNullSerializer.INSTANCE, CHARACTER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, true);
}
}
@Test
public void testFindKey()
{
testFindKeyInternal(0);
}
@Test
public void testFindKeyWithLruCache()
{
testFindKeyInternal(10);
}
private <K extends Comparable<K>, V> void testReplaceInNodeInternal(NodeRepository<K> nr, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
insertTestRecords(btr, kconv, vconv);
btr.replace(kconv.convert(85), vconv.convert(10));
assertEquals(vconv.convert(10), btr.find(kconv.convert(85)));
assertEquals(kconv.convert(85), btr.findRecord(kconv.convert(85), SearchMode.EXACT_MATCH).getKey());
verifyNextAndPreviousRecords(btr, TEST_KEYS_SORTED);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testReplaceInNodeInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(4), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testReplaceInNodeInternal(nr, kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testReplaceInNodeWithTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(new NumberOfRecordsNodeSizeStrategy(4).getNodeSize(9, 16, 0) + 3), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testReplaceInNodeInternal(nr, LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testReplaceInNodeInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testReplaceInNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testReplaceInNodeInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testReplaceInNode()
{
testReplaceInNodeInternal(0);
}
@Test
public void testReplaceInNodeWithLruCache()
{
testReplaceInNodeInternal(10);
}
@Test
public void testReplaceWhenKeyNotFound()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
LogAdapterHolder lah = new LogAdapterHolder(new StdOutLogAdapter());
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, lah);
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(nr, lah);
try
{
btr.replace(2L, 2L);
fail();
}
catch (KeyNotFoundException e)
{
// ok
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testStealThreeLeafRecordsFromNodeToTheRightInternal(NodeRepository<K> nr, NodePositions np, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// 0[(1), 13(2)]
// 1[1..6] 2[13..22]
List<KeyAndValue<K, V>> records = mergeIntervals(createInterval(1, 6, kconv, vconv), createInterval(13, 22, kconv, vconv));
insertTestRecords(btr, records);
np.addLeaf();
np.addLeaf();
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(13, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(1, 6, kconv, vconv), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createInterval(13, 22, kconv, vconv), false, false, np.get(1), null), rn);
verifyNextAndPreviousRecords(btr, records);
// Delete 1
// 0[(1), 16(2)]
// 1[2..6,13..15] 2[16..22]
assertEquals(vconv.convert(1), btr.delete(kconv.convert(1)));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(16, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createLRecordList(createLRecord(kconv, vconv, 2, 2), createLRecord(kconv, vconv, 3, 3), createLRecord(kconv, vconv, 4, 4), createLRecord(kconv, vconv, 5, 5), createLRecord(kconv, vconv, 6, 6), createLRecord(kconv, vconv, 13, 13), createLRecord(kconv, vconv, 14, 14), createLRecord(kconv, vconv, 15, 15)), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createInterval(16, 22, kconv, vconv), false, false, np.get(1), null), rn);
assertTrue(records.remove(new KeyAndValue<K, V>(kconv.convert(1), vconv.convert(1))));
verifyNextAndPreviousRecords(btr, records);
}
finally
{
btr.close();
}
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheRightWithTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// 12 records per node
int nodeSize = new NumberOfRecordsNodeSizeStrategy(12).getNodeSize(9, 2 * LongSerializer.DATA_SIZE, 0) + 3;
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(nodeSize), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testStealThreeLeafRecordsFromNodeToTheRightInternal(nr, new NodePositions(nodeSize, nodeSize, nr.getPositionOfRootNode()), LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private <K extends Comparable<K>, V> void testStealThreeLeafRecordsFromNodeToTheRightInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(12), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testStealThreeLeafRecordsFromNodeToTheRightInternal(nr, new NodePositions(getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 12), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 12, leafNodePointers), nr.getPositionOfRootNode()), kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testStealThreeLeafRecordsFromNodeToTheRightInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testStealThreeLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheRight()
{
testStealThreeLeafRecordsFromNodeToTheRightInternal(0);
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheRightWithLruCache()
{
testStealThreeLeafRecordsFromNodeToTheRightInternal(10);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testStealThreeLeafRecordsFromNodeToTheLeftInternal(NodeRepository<K> nr, NodePositions np, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// 0[(1),13(2)]
// 1[1..9] 2[13..19]
List<KeyAndValue<K, V>> records = mergeIntervals(createInterval(1, 6, kconv, vconv), createInterval(13, 19, kconv, vconv), createInterval(7, 9, kconv, vconv));
insertTestRecords(btr, records);
np.addLeaf();
np.addLeaf();
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(13, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(1, 9, kconv, vconv), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createInterval(13, 19, kconv, vconv), false, false, np.get(1), null), rn);
verifyNextAndPreviousRecords(btr, records);
// Delete 19, 18
// 0[(1),7(2)]
// 1[1..6] 2[7..9,13..17]
assertEquals(vconv.convert(19), btr.delete(kconv.convert(19)));
assertEquals(vconv.convert(18), btr.delete(kconv.convert(18)));
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(1), createLRecordList(createLRecord(7, np.get(2), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(1, 6, kconv, vconv), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createLRecordList(createLRecord(kconv, vconv, 7, 7), createLRecord(kconv, vconv, 8, 8), createLRecord(kconv, vconv, 9, 9), createLRecord(kconv, vconv, 13, 13), createLRecord(kconv, vconv, 14, 14), createLRecord(kconv, vconv, 15, 15), createLRecord(kconv, vconv, 16, 16), createLRecord(kconv, vconv, 17, 17)), false, false, np.get(1), null), rn);
records.remove(new KeyAndValue<K, V>(kconv.convert(18), vconv.convert(18)));
records.remove(new KeyAndValue<K, V>(kconv.convert(19), vconv.convert(19)));
verifyNextAndPreviousRecords(btr, records);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testStealThreeLeafRecordsFromNodeToTheLeftInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(12), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testStealThreeLeafRecordsFromNodeToTheLeftInternal(nr, new NodePositions(getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 12), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 12, leafNodePointers), nr.getPositionOfRootNode()), kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheLeftWithTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// 12 records per node + 4 extra bytes
int nodeSize = new NumberOfRecordsNodeSizeStrategy(12).getNodeSize(9, 2 * LongSerializer.DATA_SIZE, 0) + 4;
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(nodeSize), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testStealThreeLeafRecordsFromNodeToTheLeftInternal(nr, new NodePositions(nodeSize, nodeSize, nr.getPositionOfRootNode()), LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testStealThreeLeafRecordsFromNodeToTheLeftInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testStealThreeLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealThreeLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheLeft()
{
testStealThreeLeafRecordsFromNodeToTheLeftInternal(0);
}
@Test
public void testStealThreeLeafRecordsFromNodeToTheLeftWithLruCache()
{
testStealThreeLeafRecordsFromNodeToTheLeftInternal(10);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testStealTwoNonLeafRecordsFromNodeToTheRightInternal(NodeRepository<K> nr, NodePositions np, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// 0[(11), 21(12)]
// 11[(1),5(2),9(3),13(4),17(5),]
// 12[(6),25(7),29(8),33(9),37(10),41(13),]
// 1[1..4] 2[5..8] 3[9..12] 4[13..16] 5[17..20] 6[21..24]
// 7[25..28] 8[29..32] 9[33..36] 10[37..40] 13[41..45]
List<KeyAndValue<K, V>> records = createInterval(1, 45, kconv, vconv);
insertTestRecords(btr, records);
for (int i = 1; i <= 10; i++)
{
np.addLeaf();
}
np.addNonLeaf();
np.addNonLeaf();
np.addLeaf();
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(11), createLRecordList(createLRecord(21, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(1, 4, kconv, vconv), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createInterval(5, 8, kconv, vconv), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createInterval(9, 12, kconv, vconv), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createInterval(13, 16, kconv, vconv), false, false, np.get(3), np.get(5)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createInterval(17, 20, kconv, vconv), false, false, np.get(4), np.get(6)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createInterval(21, 24, kconv, vconv), false, false, np.get(5), np.get(7)), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createInterval(25, 28, kconv, vconv), false, false, np.get(6), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createInterval(29, 32, kconv, vconv), false, false, np.get(7), np.get(9)), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createInterval(33, 36, kconv, vconv), false, false, np.get(8), np.get(10)), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createInterval(37, 40, kconv, vconv), false, false, np.get(9), np.get(13)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(11), null, np.get(1), createLRecordList(createLRecord(5, np.get(2), kconv), createLRecord(9, np.get(3), kconv), createLRecord(13, np.get(4), kconv), createLRecord(17, np.get(5), kconv)), false, false), rn);
rn = nr.readNode(np.get(12), kconv.convert(21));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(21), np.get(6), createLRecordList(createLRecord(25, np.get(7), kconv), createLRecord(29, np.get(8), kconv), createLRecord(33, np.get(9), kconv), createLRecord(37, np.get(10), kconv), createLRecord(41, np.get(13), kconv)), false, false), rn);
rn = nr.readNode(np.get(13), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(13), createInterval(41, 45, kconv, vconv), false, false, np.get(10), null), rn);
verifyNextAndPreviousRecords(btr, records);
// Delete 1
assertEquals(vconv.convert(1), btr.delete(kconv.convert(1)));
// 0[(11), 29(12)]
// 11[(1),9(3),13(4),17(5),21(6),25(7)]
// 12[(8),33(9),37(10),41(13),]
// 1[2..8] 3[9..12] 4[13..16] 5[17..20] 6[21..24] 7[25..28]
// 8[29..32] 9[33..36] 10[37..40] 13[41..45]
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(11), createLRecordList(createLRecord(29, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(2, 8, kconv, vconv), false, false, null, np.get(3)), rn);
assertNodeDeleted(nr, np.get(2));
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createInterval(9, 12, kconv, vconv), false, false, np.get(1), np.get(4)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(11), null, np.get(1), createLRecordList(createLRecord(9, np.get(3), kconv), createLRecord(13, np.get(4), kconv), createLRecord(17, np.get(5), kconv), createLRecord(21, np.get(6), kconv), createLRecord(25, np.get(7), kconv)), false, false), rn);
rn = nr.readNode(np.get(12), kconv.convert(29));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(29), np.get(8), createLRecordList(createLRecord(33, np.get(9), kconv), createLRecord(37, np.get(10), kconv), createLRecord(41, np.get(13), kconv)), false, false), rn);
records.remove(new KeyAndValue<K, V>(kconv.convert(1), vconv.convert(1)));
verifyNextAndPreviousRecords(btr, records);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testStealTwoNonLeafRecordsFromNodeToTheRightInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(8), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(nr, new NodePositions(getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 8), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 8, leafNodePointers), nr.getPositionOfRootNode()), kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheRightAndTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// 8 records per node + 5 extra bytes
int nodeSize = new NumberOfRecordsNodeSizeStrategy(8).getNodeSize(9, 2 * LongSerializer.DATA_SIZE, 0) + 5;
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(nodeSize), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(nr, new NodePositions(nodeSize, nodeSize, nr.getPositionOfRootNode()), LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testStealTwoNonLeafRecordsFromNodeToTheRightInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheRight()
{
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(0);
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheRightWithLruCache()
{
testStealTwoNonLeafRecordsFromNodeToTheRightInternal(10);
}
@SuppressWarnings("unchecked")
private <K extends Comparable<K>, V> void testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(NodeRepository<K> nr, NodePositions np, ValueConverter<K> kconv, ValueConverter<V> vconv)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
// 0[(11), 29(12)]
// 11[(1),5(2),9(3),13(4),17(5),21(14),]
// 12[(6),33(7),37(8),41(9),45(10),49(13)]
// 1[1..4] 2[5..8] 3[9..12] 4[13..16] 5[17..20] 14[21..25]
// 6[29..32] 7[33..36] 8[37..40] 9[41..44] 10[45..48] 13[49..53]
List<KeyAndValue<K, V>> records = mergeIntervals(createInterval(1, 20, kconv, vconv), createInterval(29, 53, kconv, vconv), createInterval(21, 25, kconv, vconv));
insertTestRecords(btr, records);
for (int i = 1; i <= 10; i++)
{
np.addLeaf();
}
np.addNonLeaf();
np.addNonLeaf();
np.addLeaf();
BPlusTreeNode<K, ?> rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(11), createLRecordList(createLRecord(29, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(1), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(1), createInterval(1, 4, kconv, vconv), false, false, null, np.get(2)), rn);
rn = nr.readNode(np.get(2), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(2), createInterval(5, 8, kconv, vconv), false, false, np.get(1), np.get(3)), rn);
rn = nr.readNode(np.get(3), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(3), createInterval(9, 12, kconv, vconv), false, false, np.get(2), np.get(4)), rn);
rn = nr.readNode(np.get(4), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(4), createInterval(13, 16, kconv, vconv), false, false, np.get(3), np.get(5)), rn);
rn = nr.readNode(np.get(5), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(5), createInterval(17, 20, kconv, vconv), false, false, np.get(4), np.get(14)), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createInterval(29, 32, kconv, vconv), false, false, np.get(14), np.get(7)), rn);
rn = nr.readNode(np.get(7), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(7), createInterval(33, 36, kconv, vconv), false, false, np.get(6), np.get(8)), rn);
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createInterval(37, 40, kconv, vconv), false, false, np.get(7), np.get(9)), rn);
rn = nr.readNode(np.get(9), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(9), createInterval(41, 44, kconv, vconv), false, false, np.get(8), np.get(10)), rn);
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createInterval(45, 48, kconv, vconv), false, false, np.get(9), np.get(13)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(11), null, np.get(1), createLRecordList(createLRecord(5, np.get(2), kconv), createLRecord(9, np.get(3), kconv), createLRecord(13, np.get(4), kconv), createLRecord(17, np.get(5), kconv), createLRecord(21, np.get(14), kconv)), false, false), rn);
rn = nr.readNode(np.get(12), kconv.convert(29));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(29), np.get(6), createLRecordList(createLRecord(33, np.get(7), kconv), createLRecord(37, np.get(8), kconv), createLRecord(41, np.get(9), kconv), createLRecord(45, np.get(10), kconv), createLRecord(49, np.get(13), kconv)), false, false), rn);
rn = nr.readNode(np.get(13), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(13), createInterval(49, 53, kconv, vconv), false, false, np.get(10), null), rn);
rn = nr.readNode(np.get(14), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(14), createInterval(21, 25, kconv, vconv), false, false, np.get(5), np.get(6)), rn);
verifyNextAndPreviousRecords(btr, records);
// Delete 45, 29
assertEquals(vconv.convert(45), btr.delete(kconv.convert(45)));
assertEquals(vconv.convert(29), btr.delete(kconv.convert(29)));
// 0[(11), 17(12)]
// 11[(1),5(2),9(3),13(4),]
// 12[(5),21(14),30(6),37(8),41(10),49(13),]
// 1[1..4] 2[5..8] 3[9..12] 4[13..16] 5[17..20] 14[21..25]
// 6[30..36] 8[37..40] 10[41..44,46..48] 13[49..53]
rn = nr.readNode(np.get(0), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(0), null, np.get(11), createLRecordList(createLRecord(17, np.get(12), kconv)), true, false), rn);
rn = nr.readNode(np.get(6), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(6), createInterval(30, 36, kconv, vconv), false, false, np.get(14), np.get(8)), rn);
assertNodeDeleted(nr, np.get(7));
rn = nr.readNode(np.get(8), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(8), createInterval(37, 40, kconv, vconv), false, false, np.get(6), np.get(10)), rn);
assertNodeDeleted(nr, np.get(9));
rn = nr.readNode(np.get(10), null);
assertNodesEqual(new BPlusTreeLeafNode<K, V>(np.get(10), createLRecordList(createLRecord(kconv, vconv, 41, 41), createLRecord(kconv, vconv, 42, 42), createLRecord(kconv, vconv, 43, 43), createLRecord(kconv, vconv, 44, 44), createLRecord(kconv, vconv, 46, 46), createLRecord(kconv, vconv, 47, 47), createLRecord(kconv, vconv, 48, 48)), false, false, np.get(8), np.get(13)), rn);
rn = nr.readNode(np.get(11), null);
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(11), null, np.get(1), createLRecordList(createLRecord(5, np.get(2), kconv), createLRecord(9, np.get(3), kconv), createLRecord(13, np.get(4), kconv)), false, false), rn);
rn = nr.readNode(np.get(12), kconv.convert(17));
assertNodesEqual(new BPlusTreeNonLeafNode<K>(np.get(12), kconv.convert(17), np.get(5), createLRecordList(createLRecord(21, np.get(14), kconv), createLRecord(30, np.get(6), kconv), createLRecord(37, np.get(8), kconv), createLRecord(41, np.get(10), kconv), createLRecord(49, np.get(13), kconv)), false, false), rn);
records.remove(new KeyAndValue<K, V>(kconv.convert(45), vconv.convert(45)));
records.remove(new KeyAndValue<K, V>(kconv.convert(29), vconv.convert(29)));
verifyNextAndPreviousRecords(btr, records);
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean leafNodePointers)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(8), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(nr, new NodePositions(getNonLeafNodeSize(keySerializer.getSerializedSize(), pointerSize, 8), getLeafNodeSize(keySerializer.getSerializedSize(), valueSerializer.getSerializedSize(), pointerSize, 8, leafNodePointers), nr.getPositionOfRootNode()), kconv, vconv);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheLeftWithTooBigNodeSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// 8 records per node + 5 extra bytes
int nodeSize = new NumberOfRecordsNodeSizeStrategy(8).getNodeSize(9, 16, 0) + 5;
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(nodeSize), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(nr, new NodePositions(nodeSize, nodeSize, nr.getPositionOfRootNode()), LONG_CONVERTER, LONG_CONVERTER);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(int cacheSize)
{
for (int pointerSize : POINTER_SIZES)
{
for (boolean lnp : BOOLEANS)
{
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, lnp);
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(ShortNullSerializer.INSTANCE, SHORT_CONVERTER, ShortSerializer.INSTANCE, SHORT_CONVERTER, cacheSize, pointerSize, lnp);
}
}
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheLeft()
{
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(0);
}
@Test
public void testStealTwoNonLeafRecordsFromNodeToTheLeftWithLruCache()
{
testStealTwoNonLeafRecordsFromNodeToTheLeftInternal(10);
}
@Test
public void testIteratorsWhenNotSupported()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
assertFalse(btr.isIteratorSupported());
try
{
btr.keyIterator();
fail();
}
catch (UnsupportedOperationException e)
{
// ok
}
try
{
btr.valueIterator();
fail();
}
catch (UnsupportedOperationException e)
{
// ok
}
try
{
btr.iterator();
fail();
}
catch (UnsupportedOperationException e)
{
// ok
}
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void assertGivesConcurrentModificationException(Iterator<?> itr)
{
try
{
itr.hasNext();
fail();
}
catch (ConcurrentModificationException e)
{
// ok
}
try
{
itr.next();
fail();
}
catch (ConcurrentModificationException e)
{
// ok
}
}
@Test
public void testKeyIterator()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Long> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.keyIterator();
assertFalse(itr.hasNext());
btr.insert(Long.valueOf(1L), Integer.valueOf(1));
btr.insert(Long.valueOf(8L), Integer.valueOf(8));
btr.insert(Long.valueOf(6L), Integer.valueOf(6));
btr.insert(Long.valueOf(2L), Integer.valueOf(2));
btr.insert(Long.valueOf(5L), Integer.valueOf(5));
itr = btr.keyIterator();
assertTrue(itr.hasNext());
assertEquals(1L, itr.next().longValue());
assertTrue(itr.hasNext());
assertEquals(2L, itr.next().longValue());
assertTrue(itr.hasNext());
assertEquals(5L, itr.next().longValue());
assertEquals(6L, itr.next().longValue());
assertTrue(itr.hasNext());
assertEquals(8L, itr.next().longValue());
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
// Test concurrent modifications
itr = btr.keyIterator();
assertTrue(itr.hasNext());
btr.insert(Long.valueOf(10L), Integer.valueOf(10));
assertGivesConcurrentModificationException(itr);
itr = btr.keyIterator();
assertTrue(itr.hasNext());
btr.delete(10L);
assertGivesConcurrentModificationException(itr);
itr = btr.keyIterator();
assertTrue(itr.hasNext());
if (btr.compact())
{
assertGivesConcurrentModificationException(itr);
}
// Replacing values does not affect key iteration
itr = btr.keyIterator();
assertTrue(itr.hasNext());
btr.replace(2L, 20);
assertTrue(itr.hasNext());
itr = btr.keyIterator();
assertTrue(itr.hasNext());
btr.clear();
assertGivesConcurrentModificationException(itr);
}
finally
{
btr.close();
try
{
itr.hasNext();
fail();
}
catch (IllegalStateException e)
{
// ok
}
try
{
itr = btr.keyIterator();
fail();
}
catch (IllegalStateException e)
{
// ok
}
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testKeyIteratorForEmptyTree()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Long> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new LruCacheNodeRepository<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), 10), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.keyIterator();
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testValueIterator()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Integer> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.valueIterator();
assertFalse(itr.hasNext());
btr.insert(Long.valueOf(1L), Integer.valueOf(1));
btr.insert(Long.valueOf(8L), Integer.valueOf(8));
btr.insert(Long.valueOf(6L), Integer.valueOf(6));
btr.insert(Long.valueOf(2L), Integer.valueOf(2));
btr.insert(Long.valueOf(5L), Integer.valueOf(5));
itr = btr.valueIterator();
assertTrue(itr.hasNext());
assertEquals(1, itr.next().intValue());
assertTrue(itr.hasNext());
assertEquals(2, itr.next().intValue());
assertTrue(itr.hasNext());
assertEquals(5, itr.next().intValue());
assertEquals(6, itr.next().intValue());
assertTrue(itr.hasNext());
assertEquals(8, itr.next().intValue());
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
// Test concurrent modifications
itr = btr.valueIterator();
assertTrue(itr.hasNext());
btr.insert(Long.valueOf(10L), Integer.valueOf(10));
assertGivesConcurrentModificationException(itr);
itr = btr.valueIterator();
assertTrue(itr.hasNext());
btr.delete(10L);
assertGivesConcurrentModificationException(itr);
itr = btr.valueIterator();
assertTrue(itr.hasNext());
if (btr.compact())
{
assertGivesConcurrentModificationException(itr);
}
itr = btr.valueIterator();
assertTrue(itr.hasNext());
btr.replace(2L, 20);
assertGivesConcurrentModificationException(itr);
itr = btr.valueIterator();
assertTrue(itr.hasNext());
btr.clear();
assertGivesConcurrentModificationException(itr);
itr = btr.valueIterator();
}
finally
{
btr.close();
try
{
itr.hasNext();
fail();
}
catch (IllegalStateException e)
{
// ok
}
try
{
itr = btr.valueIterator();
fail();
}
catch (IllegalStateException e)
{
// ok
}
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testValueIteratorForEmptyTree()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Integer> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.valueIterator();
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testIterator()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Record<Long, Integer>> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.iterator();
assertFalse(itr.hasNext());
btr.insert(Long.valueOf(1L), Integer.valueOf(1));
btr.insert(Long.valueOf(8L), Integer.valueOf(8));
btr.insert(Long.valueOf(6L), Integer.valueOf(6));
btr.insert(Long.valueOf(2L), Integer.valueOf(2));
btr.insert(Long.valueOf(5L), Integer.valueOf(5));
itr = btr.iterator();
assertTrue(itr.hasNext());
assertEquals(new Record<Long, Integer>(1L, 1), itr.next());
assertTrue(itr.hasNext());
assertEquals(new Record<Long, Integer>(2L, 2), itr.next());
assertTrue(itr.hasNext());
assertEquals(new Record<Long, Integer>(5L, 5), itr.next());
assertEquals(new Record<Long, Integer>(6L, 6), itr.next());
assertTrue(itr.hasNext());
assertEquals(new Record<Long, Integer>(8L, 8), itr.next());
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
// Test concurrent modifications
itr = btr.iterator();
assertTrue(itr.hasNext());
btr.insert(Long.valueOf(10L), Integer.valueOf(10));
assertGivesConcurrentModificationException(itr);
itr = btr.iterator();
assertTrue(itr.hasNext());
btr.delete(10L);
assertGivesConcurrentModificationException(itr);
itr = btr.iterator();
assertTrue(itr.hasNext());
if (btr.compact())
{
assertGivesConcurrentModificationException(itr);
}
itr = btr.iterator();
assertTrue(itr.hasNext());
btr.replace(2L, 20);
assertGivesConcurrentModificationException(itr);
itr = btr.iterator();
assertTrue(itr.hasNext());
btr.clear();
assertGivesConcurrentModificationException(itr);
itr = btr.iterator();
}
finally
{
btr.close();
try
{
itr.hasNext();
fail();
}
catch (IllegalStateException e)
{
// ok
}
try
{
itr = btr.iterator();
fail();
}
catch (IllegalStateException e)
{
// ok
}
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testIteratorForEmptyTree()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
Iterator<Record<Long, Integer>> itr = null;
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
itr = btr.iterator();
assertFalse(itr.hasNext());
try
{
itr.next();
fail();
}
catch (NoSuchElementException e)
{
// ok
}
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testClear()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
btr.insert(12L, 24);
btr.insert(24L, 12);
assertEquals(2, btr.size());
btr.clear();
assertEquals(0, btr.size());
assertFalse(btr.iterator().hasNext());
btr.insert(13L, 23);
assertEquals(1, btr.size());
}
finally
{
btr.close();
try
{
btr.clear();
fail();
}
catch (IllegalStateException e)
{
// ok
}
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testSize()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
BPlusTree<Long, Integer> btr = new BPlusTree<Long, Integer>(new FileBackedNodeRepository<Long, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), true, LongNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 3, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
assertEquals(0, btr.size());
btr.insert(12L, 24);
btr.insert(24L, 12);
assertEquals(2, btr.size());
// There are other size-tests spread out among the other test
// methods.
}
finally
{
btr.close();
try
{
btr.size();
fail();
}
catch (IllegalStateException e)
{
// ok
}
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testDeleteMissingKey()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
assertNull(btr.delete(Long.valueOf(1)));
btr.insert(Long.valueOf(1), Long.valueOf(2));
assertEquals(Long.valueOf(2), btr.delete(Long.valueOf(1)));
assertNull(btr.delete(Long.valueOf(1)));
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testInsertNullValue()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// A tree that should support null values.
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongNullSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
btr.insert(12L, null);
assertNull(btr.find(12L));
assertTrue(btr.containsKey(12L));
assertEquals(12L, btr.findRecord(12L, SearchMode.EXACT_MATCH).getKey().longValue());
btr.delete(12L);
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// A tree that does not support null values
BPlusTree<Long, Long> btr = new BPlusTree<Long, Long>(new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(2), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 8, 8192, null, new LogAdapterHolder(new StdOutLogAdapter())), new LogAdapterHolder(new StdOutLogAdapter()));
try
{
btr.insert(Long.valueOf(12L), null);
fail();
}
catch (NullPointerException e)
{
// ok
}
finally
{
btr.close();
}
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private <K extends Comparable<K>, V> void testLargeBTreeInternal(NodeRepository<K> nr, boolean compact, ValueConverter<K> kconv, ValueConverter<V> vconv, int noRecords)
{
BPlusTree<K, V> btr = new BPlusTree<K, V>(nr, new LogAdapterHolder(new StdOutLogAdapter()));
try
{
List<KeyAndValue<K, V>> records = createInterval(1, noRecords, kconv, vconv);
insertTestRecords(btr, records);
assertEquals(noRecords, btr.size());
btr.verifyTreeIntegrity();
verifyNextAndPreviousRecords(btr, records);
int previ1 = 2;
int previ2 = 1;
for (int i = 2; i < noRecords / 10; i = previ1 + previ2)
{
// Remove every i:th record
for (int j = 1; j <= noRecords; j += i)
{
try
{
assertNotNull(btr.delete(kconv.convert(j)));
}
catch (RuntimeException e)
{
System.out.println("delete " + i + ":" + j);
throw e;
}
assertTrue(records.remove(new KeyAndValue<K, V>(kconv.convert(j), vconv.convert(j))));
if ((j - 1) % (i * 1000) == 0)
{
try
{
if (compact)
{
btr.verifyTreeIntegrity();
// System.out.println(btr.printTree());
btr.compact();
// System.out.println(btr.printTree());
}
btr.verifyTreeIntegrity();
}
catch (RuntimeException e)
{
System.out.println("delete* " + i + ":" + j);
throw e;
}
}
}
if (compact)
{
btr.compact();
btr.verifyTreeIntegrity();
}
verifyNextAndPreviousRecords(btr, records);
// Insert them again
for (int j = 1; j <= noRecords; j += i)
{
try
{
btr.insert(kconv.convert(j), vconv.convert(j));
}
catch (RuntimeException e)
{
System.out.println("insert " + i + ":" + j);
throw e;
}
records.add(new KeyAndValue<K, V>(kconv.convert(j), vconv.convert(j)));
if ((j - 1) % (i * 1000) == 0)
{
try
{
btr.verifyTreeIntegrity();
}
catch (RuntimeException e)
{
System.out.println("insert* " + i + ":" + j);
throw e;
}
}
}
btr.verifyTreeIntegrity();
verifyNextAndPreviousRecords(btr, records);
previ2 = previ1;
previ1 = i;
}
}
finally
{
btr.close();
}
}
private <K extends Comparable<K>, V> void testLargeBTreeInternal(Serializer<K> keySerializer, ValueConverter<K> kconv, Serializer<V> valueSerializer, ValueConverter<V> vconv, int cacheSize, int pointerSize, boolean compact, boolean leafNodePointers)
{
final int noRecords = 10000;
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<K> nr = new FileBackedNodeRepository<K, V>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(8), leafNodePointers, keySerializer, valueSerializer, pointerSize, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
if (cacheSize > 0)
{
nr = new LruCacheNodeRepository<K, V>(nr, cacheSize);
}
testLargeBTreeInternal(nr, compact, kconv, vconv, noRecords);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
private void testLargeBTreeInternal(int cacheSize, boolean compact)
{
int[] pointerSizes = new int[] { 4, 7 };
for (int pointerSize : pointerSizes)
{
for (boolean lnp : BOOLEANS)
{
testLargeBTreeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, compact, lnp);
testLargeBTreeInternal(LongNullSerializer.INSTANCE, LONG_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, compact, lnp);
testLargeBTreeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, LongSerializer.INSTANCE, LONG_CONVERTER, cacheSize, pointerSize, compact, lnp);
testLargeBTreeInternal(IntegerNullSerializer.INSTANCE, INTEGER_CONVERTER, IntegerSerializer.INSTANCE, INTEGER_CONVERTER, cacheSize, pointerSize, compact, lnp);
}
}
}
private void testLargeBTreeWithTooBigNodesInternal(boolean compact)
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
// 8 records per node + 1 extra byte
NodeRepository<Long> nr = new FileBackedNodeRepository<Long, Long>(f, false, f.getSize(), new FixedSizeNodeSizeStrategy(new NumberOfRecordsNodeSizeStrategy(8).getNodeSize(FileBackedNodeRepository.NODE_HEADER_SIZE, 16, 0) + 1), false, LongNullSerializer.INSTANCE, LongSerializer.INSTANCE, 7, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testLargeBTreeInternal(nr, compact, LONG_CONVERTER, LONG_CONVERTER, 10000);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
@Test
public void testLargeBTreeWithTooBigNodes()
{
testLargeBTreeWithTooBigNodesInternal(false);
}
@Test
public void testLargeBTreeWithTooBigNodesAndCompact()
{
testLargeBTreeWithTooBigNodesInternal(true);
}
@Test
public void testLargeBTree()
{
testLargeBTreeInternal(0, false);
}
@Test
public void testLargeBTreeWithCompact()
{
testLargeBTreeInternal(0, true);
}
@Test
public void testLargeBTreeWithSmallLruCache()
{
testLargeBTreeInternal(4, false);
}
@Test
public void testLargeBTreeWithLargeLruCache()
{
testLargeBTreeInternal(30, false);
}
@Test
public void testLargeBTreeWithCompactAndSmallLruCache()
{
testLargeBTreeInternal(4, true);
}
@Test
public void testLargeBTreeWithCompactAndLargeLruCache()
{
testLargeBTreeInternal(30, true);
}
@Test
public void testHugeBTreeWithCompactAndLargeLruCache()
{
File tmpFile = FileSupport.createTempFile();
try
{
ReadWritableFile f = new ReadWritableFileAdapter(tmpFile);
byte[] barr = writeJunk(f);
NodeRepository<Integer> nr = new FileBackedNodeRepository<Integer, Integer>(f, false, f.getSize(), new NumberOfRecordsNodeSizeStrategy(8), true, IntegerNullSerializer.INSTANCE, IntegerSerializer.INSTANCE, 6, 8192, null, new LogAdapterHolder(new StdOutLogAdapter()));
testLargeBTreeInternal(nr, true, INTEGER_CONVERTER, INTEGER_CONVERTER, 200000);
assertJunkUntouched(f, barr);
}
finally
{
assertTrue(tmpFile.delete());
}
}
}