/*
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 20, 2009
*/
package com.bigdata.resources;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import junit.framework.TestCase2;
import com.bigdata.btree.BTree;
import com.bigdata.btree.ILocalBTreeView;
import com.bigdata.btree.ISimpleSplitHandler;
import com.bigdata.btree.IndexSegment;
import com.bigdata.btree.IndexSegmentBuilder;
import com.bigdata.journal.IJournal;
import com.bigdata.journal.Journal;
import com.bigdata.journal.Options;
import com.bigdata.util.BytesUtil;
/**
* Unit tests for splitting an index segment based on its size on the disk, the
* nominal size of an index partition, and an optional application level
* constraint on the choice of the separator keys. This approach presumes a
* compacting merge has been performed such that all history other than the
* buffered writes is on a single index segment. The buffered writes are not
* considered when choosing the #of splits to make and the separator keys for
* those splits. They are simply copied afterwards onto the new index partition
* which covers their key-range.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*
* @see src/architecture/SplitMath.xls
*/
public class AbstractTestSegSplitter extends TestCase2 {
/**
*
*/
public AbstractTestSegSplitter() {
}
/**
* @param name
*/
public AbstractTestSegSplitter(String name) {
super(name);
}
protected IJournal getStore() throws IOException {
Properties p = new Properties();
p.setProperty(Options.FILE, File.createTempFile(getName(), Options.JNL).toString());
return new Journal(p);
}
protected IPartitionIdFactory pidFactory = new MockPartitionIdFactory();
/**
* Always accepts the recommended separator key.
*/
protected static final ISimpleSplitHandler acceptAllSplits = new ISimpleSplitHandler() {
public byte[] getSeparatorKey(IndexSegment seg, int fromIndex, int toIndex,
int splitAt) {
return seg.keyAt(splitAt);
}
};
/**
* Always returns <code>null</code> (never accepts any splits).
*/
protected static final ISimpleSplitHandler rejectAllSplits = new ISimpleSplitHandler() {
public byte[] getSeparatorKey(IndexSegment seg, int fromIndex, int toIndex,
int splitAt) {
return null;
}
};
/**
* Accepts the recommended separator key unless it is GTE the key given to
* the constructor, in which case it refuses to accept any splits.
*/
protected static class RejectSplitsAfterKey implements ISimpleSplitHandler {
private final byte[] rejectKey;
public RejectSplitsAfterKey(final byte[] rejectKey) {
if (rejectKey == null)
throw new IllegalArgumentException();
this.rejectKey = rejectKey;
}
public byte[] getSeparatorKey(final IndexSegment seg,
final int fromIndex, final int toIndex, final int splitAt) {
final byte[] a = seg.keyAt(splitAt);
if (BytesUtil.compareBytes(a, rejectKey) >= 0) {
// reject any split GTE the key specified to the ctor.
return null;
}
// Otherwise accept the recommended separator key.
return a;
}
};
/**
* Generate an {@link IndexSegment} from the given BTree.
*
* @param src
* The source {@link BTree}.
*
* @return The {@link IndexSegmentBuilder}.
*/
static protected IndexSegmentBuilder doBuild(final String name,
final ILocalBTreeView src, final long commitTime,
final byte[] fromKey, final byte[] toKey) throws Exception {
if (src == null)
throw new IllegalArgumentException();
// final String name = getName();
final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
File outFile = null;
final IndexSegmentBuilder builder;
try {
// the file to be generated.
outFile = File.createTempFile(name, Options.SEG, tmpDir);
// new builder.
builder = IndexSegmentBuilder.newInstance(/*name, */src, outFile,
tmpDir, true/* compactingMerge */, commitTime, fromKey,
toKey);
// build the index segment.
builder.call();
return builder;
} catch (Throwable t) {
if (outFile != null && outFile.exists()) {
try {
outFile.delete();
} catch (Throwable t2) {
log.warn(t2.getLocalizedMessage(), t2);
}
}
if (t instanceof Exception)
throw (Exception) t;
throw new RuntimeException(t);
}
}
/**
* Mock implementation assigns index partitions from a counter beginning
* with ZERO (0), which is the first legal index partition identifier. The
* name parameter is ignored.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
static protected class MockPartitionIdFactory implements IPartitionIdFactory {
private int i = 0;
public int nextPartitionId(String nameIsIgnored) {
return i++;
}
}
}