/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Dec 3, 2008
*/
package com.bigdata.btree;
import java.io.File;
import java.util.UUID;
import com.bigdata.btree.keys.TestKeyBuilder;
import com.bigdata.rawstore.SimpleMemoryRawStore;
/**
* A test of the {@link IndexSegmentBuilder} in which there are some deleted
* tuples in the source {@link BTree} and a compacting merge is performed.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestIndexSegmentBuilderWithCompactingMerge extends
AbstractIndexSegmentTestCase {
/**
*
*/
public TestIndexSegmentBuilderWithCompactingMerge() {
}
/**
* @param name
*/
public TestIndexSegmentBuilderWithCompactingMerge(String name) {
super(name);
}
File outFile;
File tmpDir;
public void setUp() throws Exception {
super.setUp();
outFile = new File(getName() + ".seg");
if (outFile.exists() && !outFile.delete()) {
throw new RuntimeException("Could not delete file: " + outFile);
}
tmpDir = outFile.getAbsoluteFile().getParentFile();
}
public void tearDown() throws Exception {
if (outFile != null && outFile.exists() && !outFile.delete()) {
log.warn("Could not delete file: " + outFile);
}
super.tearDown();
}
/**
* Unit test explores the correct propagation of deleted index entries to
* the generated index segment.
*
* @throws Exception
*
* @todo modify test to verify correct propagation of the version timestamps
* (or create an entire test suite for that purpose). Note that
* version timestamps are only used for full transactions.
*/
public void test_deletedEntries() throws Exception {
final long createTime = System.currentTimeMillis();
final String name = "testIndex";
final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID());
// enable delete markers.
metadata.setDeleteMarkers(true);
// use the same branching factor on the BTree and the IndexSegment for
// ease of comparison.
metadata.setBranchingFactor(3);
metadata.setIndexSegmentBranchingFactor(3);
final BTree expected = BTree.create(new SimpleMemoryRawStore(), metadata);
for (int i = 1; i <= 10; i++) {
expected.insert(TestKeyBuilder.asSortKey(i), new SimpleEntry(i));
}
/*
* First, build an index segment from the original BTree.
*/
{
final byte[] fromKey = null;
final byte[] toKey = null;
// should cover all keys.
assertEquals(10, expected.getEntryCount());
assertEquals(10, expected.rangeCount(fromKey, toKey));
assertEquals(10, expected.rangeCountExact(fromKey, toKey));
final IndexSegmentBuilder builder = IndexSegmentBuilder
.newInstance(/*name,*/ expected, outFile, tmpDir,
true/* compactingMerge */, createTime, fromKey,
toKey);
IndexSegmentStore segmentStore = null;
try {
@SuppressWarnings("unused")
final IndexSegmentCheckpoint checkpoint = builder.call();
// @see BLZG-1501 (remove LRUNexus)
// if (LRUNexus.INSTANCE != null) {
//
// /*
// * Clear the records for the index segment from the cache so we will
// * read directly from the file. This is necessary to ensure that the
// * data on the file is good rather than just the data in the cache.
// */
//
// LRUNexus.INSTANCE.deleteCache(checkpoint.segmentUUID);
//
// }
segmentStore = new IndexSegmentStore(outFile);
final IndexSegment actual = segmentStore.loadIndexSegment();
assertSameEntryIterator(expected.rangeIterator(fromKey, toKey),
actual.rangeIterator(fromKey, toKey));
/*
* The index segment's iterator WITH the DELETED tuples should
* visit the same tuples in the same order as the ground truth
* BTree's iterator WITHOUT the DELETED tuples (because the
* deleted tuples SHOULD NOT have been copied into the generated
* index segment).
*/
assertSameEntryIterator(
expected
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT,
null/* filter */),
actual
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT
| IRangeQuery.DELETED, null/* filter */));
} finally {
if (segmentStore != null)
segmentStore.destroy();
outFile.delete();
}
}
/*
* Now delete a few tuples.
*/
{
final byte[] fromKey = null;
final byte[] toKey = null;
expected.remove(TestKeyBuilder.asSortKey(3));
expected.remove(TestKeyBuilder.asSortKey(5));
// should cover all keys (since deleted tuples are still present).
assertEquals(10, expected.getEntryCount());
// should cover all keys (since deleted tuples are still present).
assertEquals(10, expected.rangeCount(fromKey, toKey));
// should exclude the deleted tuples.
assertEquals(8, expected.rangeCountExact(fromKey, toKey));
final IndexSegmentBuilder builder = IndexSegmentBuilder
.newInstance(/*name,*/ expected, outFile, tmpDir,
true/* compactingMerge */, createTime, fromKey,
toKey);
IndexSegmentStore segmentStore = null;
try {
@SuppressWarnings("unused")
final IndexSegmentCheckpoint checkpoint = builder.call();
// @see BLZG-1501 (remove LRUNexus)
// if (LRUNexus.INSTANCE != null) {
//
// /*
// * Clear the records for the index segment from the cache so we will
// * read directly from the file. This is necessary to ensure that the
// * data on the file is good rather than just the data in the cache.
// */
//
// LRUNexus.INSTANCE.deleteCache(checkpoint.segmentUUID);
//
// }
segmentStore = new IndexSegmentStore(outFile);
final IndexSegment actual = segmentStore.loadIndexSegment();
assertSameEntryIterator(expected.rangeIterator(fromKey, toKey),
actual.rangeIterator(fromKey, toKey));
/*
* The index segment's iterator WITH the DELETED tuples should
* visit the same tuples in the same order as the ground truth
* BTree's iterator WITHOUT the DELETED tuples (because the
* deleted tuples SHOULD NOT have been copied into the generated
* index segment).
*/
assertSameEntryIterator(
expected
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT,
null/* filter */),
actual
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT
| IRangeQuery.DELETED, null/* filter */));
} finally {
if (segmentStore != null)
segmentStore.destroy();
outFile.delete();
}
}
/*
* Now delete all the tuples.
*/
{
final byte[] fromKey = null;
final byte[] toKey = null;
/*
* Note: removeAll() MUST write delete markers when the index
* supports them rather than just replacing the root with a new root
* leaf.
*/
expected.removeAll();
// should cover all keys (since deleted tuples are still present).
assertEquals(10, expected.getEntryCount());
// should cover all keys (since deleted tuples are still present).
assertEquals(10, expected.rangeCount(fromKey, toKey));
// should exclude the deleted tuples.
assertEquals(0, expected.rangeCountExact(fromKey, toKey));
final IndexSegmentBuilder builder = IndexSegmentBuilder
.newInstance(/*name, */ expected, outFile, tmpDir,
true/* compactingMerge */, createTime, fromKey,
toKey);
IndexSegmentStore segmentStore = null;
try {
@SuppressWarnings("unused")
final IndexSegmentCheckpoint checkpoint = builder.call();
// @see BLZG-1501 (remove LRUNexus)
// if (LRUNexus.INSTANCE != null) {
//
// /*
// * Clear the records for the index segment from the cache so we will
// * read directly from the file. This is necessary to ensure that the
// * data on the file is good rather than just the data in the cache.
// */
//
// LRUNexus.INSTANCE.deleteCache(checkpoint.segmentUUID);
//
// }
segmentStore = new IndexSegmentStore(outFile);
final IndexSegment actual = segmentStore.loadIndexSegment();
assertSameEntryIterator(expected.rangeIterator(fromKey, toKey),
actual.rangeIterator(fromKey, toKey));
/*
* The index segment's iterator WITH the DELETED tuples should
* visit the same tuples in the same order as the ground truth
* BTree's iterator WITHOUT the DELETED tuples (because the
* deleted tuples SHOULD NOT have been copied into the generated
* index segment).
*/
assertSameEntryIterator(
expected
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT,
null/* filter */),
actual
.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.DEFAULT
| IRangeQuery.DELETED, null/* filter */));
} finally {
if (segmentStore != null)
segmentStore.destroy();
outFile.delete();
}
}
}
}