com.bigdata.htree.BuddyBucketTupleIterator Maven / Gradle / Ivy
package com.bigdata.htree;
import java.util.NoSuchElementException;
import com.bigdata.btree.AbstractTuple;
import com.bigdata.btree.IRangeQuery;
import com.bigdata.btree.ITuple;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.btree.LeafTupleIterator;
import com.bigdata.btree.raba.IRaba;
import com.bigdata.util.BytesUtil;
/**
* Iterator visits all tuples in a buddy bucket having the desired key.
*
* Note: This implementation is NOT thread-safe.
*/
class BuddyBucketTupleIterator implements
ITupleIterator {
/** The key. */
private final byte[] key;
/** The bucket. */
private final BucketPage bucket;
// /** The index of the first slot in the buddy bucket. */
// private final int buddyOffset;
/** The index of the last slot in the buddy bucket. */
private final int lastSlot;
/** The index of the next slot to be visited. This is set by the
* constructor to the first slot and the tuple at that slot is pre-fetched.
*/
private int index;
private int lastVisited = -1;
private final AbstractTuple tuple;
public BuddyBucketTupleIterator(final byte[] key, final BucketPage bucket) {//, final int buddyOffset) {
if (key == null)
throw new IllegalArgumentException();
if (bucket == null)
throw new IllegalArgumentException();
this.key = key;
this.bucket = bucket;
// // #of slots on the page.
// final int slotsOnPage = bucket.slotsOnPage();
/*
* The index of the last slot in the buddy bucket.
*
* Note: The bucket page is not divided into buddy buckets, so we want
* to start at the first slot (index zero) and scan until the last slot
* (slotsOnPage-1).
*
* Note: Optimized (assumes tuples in the bucket page are known to be
* dense (no gaps), in which case we do not have to scan more than
* bucket.data.getKeyCount() slots).
*/
lastSlot = bucket.getKeys().size();//slotsOnPage;
// Lookup first slot to test.
index = bucket.lookupIndex(key);
tuple = new Tuple(bucket.htree, IRangeQuery.DEFAULT);
}
/**
* Examines the entry at {@link #index}. If it passes the criteria for an
* entry to visit then return true. Otherwise increment the {@link #index}
* until either all entries in this leaf have been exhausted -or- the an
* entry is identified that passes the various criteria.
*/
public boolean hasNext() {
if (index == -1) {
return false;
}
final IRaba keys = bucket.getKeys();
assert keys.size() == lastSlot;
assert keys.size() <= keys.capacity();
for( ; index < lastSlot; index++) {
// /*
// * TODO Skip deleted entries unless specifically requested.
// */
// if (hasDeleteMarkers && !visitDeleted
// && leaf.getDeleteMarker(index)) {
//
// // skipping a deleted version.
// continue;
//
// }
if (!keys.isNull(index)) {
if (BytesUtil.bytesEqual(key, keys.get(index))) {
// entry @ index is next to visit.
return true;
}
}
// if key doesn't match terminate early since the keys are sorted
index = lastSlot;
} // next index.
// nothing left to visit in this buddy bucket.
return false;
}
public ITuple next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
lastVisited = index++;
tuple.copy(lastVisited, bucket);
return tuple;
}
/**
* Operation is not supported.
*
* TODO ITupleCursor and delete-behind are two ways to achieve this. See
* {@link LeafTupleIterator#remove()}. I also did a listener based
* iterator for GOM which supports concurrent mutation (as long as you
* obey the thread safety for the API).
*/
public void remove() {
throw new UnsupportedOperationException();
}
}