/**
* Copyright 2013 Oak Ridge National Laboratory
* Author: James Horey <horeyjl@ornl.gov>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package gov.ornl.keva.table;
/**
* Java libs.
**/
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Iterator;
import java.util.Comparator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.nio.ByteBuffer;
import java.nio.BufferOverflowException;
/**
* Keva libs.
**/
import gov.ornl.keva.core.VectorClock;
import gov.ornl.keva.core.EmptyIterator;
import gov.ornl.keva.core.MergeSortedIterator;
import gov.ornl.keva.core.StreamIterator;
import gov.ornl.keva.core.PruneOptions;
/**
* Iterate through tables values, but filter out "tentative" values, and apply
* the pruning options.
*/
public class FilterBucketIterator extends StreamIterator<TableValue> {
private Iterator<? extends TableValue> iter;
private TableValue nextValue;
private PruneOptions pruneOptions;
private boolean hasSeenDelete; // Used during the pruning process.
private int numRemaining; // Keep track of the number of elements.
private int totalSize;
/**
* Filter out tentative values.
**/
public FilterBucketIterator(TableValueHistory history,
PruneOptions pruneOptions) {
super(null);
this.iter = history.iterator();
this.pruneOptions = pruneOptions;
nextValue = null;
hasSeenDelete = false;
numRemaining = history.size();
totalSize = numRemaining;
}
/**
* Help prune values.
**/
private boolean doPrune(TableValue value) {
if(pruneOptions != null) {
// Check if the user only wants the newest elements.
boolean pruneBySize = false;
if(pruneOptions.newest != -1 &&
numRemaining >= pruneOptions.newest) {
pruneBySize = true;
}
// We need to make sure that there
// is a delete operation on this history.
// Otherwise, we can safely return all the values.
if(pruneOptions.delete) {
// Need to prune all values that appear *before* the
// delete operation.
if(value.getStorageType() == TableValue.DELETE) {
hasSeenDelete = true;
return true; // Do not display the delete.
}
else {
return !hasSeenDelete || pruneBySize;
}
}
else {
return pruneBySize;
}
}
return false;
}
/**
* Get the number of elements being processed.
*/
public int size() {
return totalSize;
}
/**
* Indicate whether we have another element.
**/
@Override public boolean hasNext() {
nextValue = null;
while(iter.hasNext()) {
nextValue = iter.next();
numRemaining--;
if(nextValue.getFlags() != TableValue.TENTATIVE) {
// Check if we need to prune the value.
if(doPrune(nextValue)) {
continue;
}
// Ok found a good value.
break;
}
else {
// We accidently removed an item from the remaining count
// even though it was tentative. Just add that value back.
numRemaining++;
}
// Reset so that if the last value is tentative, we
// get a null value.
nextValue = null;
}
return nextValue != null;
}
/**
* Fetch the next element.
**/
@Override public TableValue next() {
return nextValue;
}
/**
* Remove current element.
**/
@Override public void remove() {
// Do not implement.
}
}