package com.bigdata.btree; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import org.apache.log4j.Logger; import com.bigdata.util.Bytes; import com.bigdata.util.BytesUtil; /** * Imposes constraint that the key before the separatorKey must differ in * the first N bytes from the key after the separator key. */ public class FixedLengthPrefixSplits implements ISimpleSplitHandler, Serializable, Externalizable { protected static transient final Logger log = Logger .getLogger(FixedLengthPrefixSplits.class); /** * */ private static final long serialVersionUID = -4873807205429701805L; private int N; public FixedLengthPrefixSplits(final int nbytes) { if (nbytes <= 0) throw new IllegalArgumentException(); this.N = nbytes; } /** * Linear search for the first successor of the keyAt(splitAt) which * differs in the first N bytes. * * @todo This will be faster using an {@link ITupleCursor} if we have to * leaf the current leaf. * * @todo We could also search backward or use a forward/backward search, * or a progressive search, but there should seldom be any reason * to do so. * * @todo This could also be done without materializing the keys we are * testing if it was written at a much lower level. */ public byte[] getSeparatorKey(final IndexSegment seg, final int fromIndex, final int toIndex, final int splitAt) { final int N = this.N; final byte[] a = seg.keyAt(splitAt); for (int i = splitAt + 1; i < toIndex; i++) { final byte[] b = seg.keyAt(i); /* * Compare the first N bytes of those keys (unsigned byte[] * comparison). */ final int cmp = BytesUtil.compareBytesWithLenAndOffset(// 0/* aoff */, Bytes.SIZEOF_LONG/* alen */, a,// 0/* boff */, Bytes.SIZEOF_LONG/* blen */, b// ); // the keys must be correctly ordered. assert cmp <= 0; if (cmp < 0) { /* * The N byte prefix has changed. Clone the first N bytes of the * current key and return them to the caller. This is the * minimum length first successor of the recommended key which * can serve as a separator key for an N byte prefix constraint. */ final byte[] prefix = new byte[N]; System.arraycopy(b/* src */, 0/* srcPos */, prefix/* dest */, 0/* destPos */, N/* length */); if (log.isInfoEnabled()) log.info("Found: prefix=" + BytesUtil.toString(prefix) + ", splitAt=" + splitAt + ", i=" + i); return prefix; } } log.warn("No successor: nbytes=" + N + ", splitAt=" + splitAt); // No such successor! return null; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { N = in.readInt(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(N); } }