package net.notdot.bdbdatastore.server;
import java.util.Arrays;
import net.notdot.bdbdatastore.Indexing;
import com.google.protobuf.InvalidProtocolBufferException;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.OperationStatus;
public class DatastorePKResultSet extends AbstractDatastoreResultSet {
protected Cursor cursor = null;
protected boolean exclusiveMin;
protected boolean positioned;
protected MessagePredicate predicate;
public DatastorePKResultSet(AppDatastore ds, Indexing.EntityKey startKey, boolean exclusiveMin, QuerySpec query, MessagePredicate predicate) throws DatabaseException {
super(ds, query);
this.currentPKey = new DatabaseEntry(startKey.toByteArray());
this.exclusiveMin = exclusiveMin;
this.predicate = predicate;
}
@Override
protected void closeCursor() throws DatabaseException {
this.cursor.close();
this.cursor = null;
}
@Override
protected void openCursor() throws DatabaseException {
this.cursor = ds.entities.openCursor(null, ds.getCursorConfig());
this.positioned = false;
}
@Override
protected boolean readInternal() throws DatabaseException, InvalidProtocolBufferException {
OperationStatus status;
if(positioned) {
// Cursor has already been used; just advance
status = cursor.getNext(currentPKey, currentValue, null);
} else {
if(currentValue == null) {
// Cursor has never been used before
this.currentValue = new DatabaseEntry();
byte[] startKeyBytes = currentPKey.getData();
status = cursor.getSearchKeyRange(currentPKey, currentValue, null);
if(status == OperationStatus.SUCCESS && exclusiveMin && Arrays.equals(startKeyBytes, currentPKey.getData())) {
// First key and the minimum is exclusive - fetch the next one
status = cursor.getNextNoDup(currentPKey, currentValue, null);
}
} else {
// Cursor has been reopened
status = cursor.getSearchBothRange(currentPKey, currentValue, null);
if(status == OperationStatus.SUCCESS) {
status = cursor.getNext(currentPKey, currentValue, null);
}
}
positioned = true;
}
if(status == OperationStatus.SUCCESS) {
if(this.predicate != null) {
this.currentPKeyEnt = Indexing.EntityKey.parseFrom(currentPKey.getData());
return this.predicate.evaluate(this.currentPKeyEnt);
}
return true;
} else if(status == OperationStatus.NOTFOUND) {
return false;
} else {
throw new DatabaseException(String.format("Failed to advance query cursor: returned %s", status));
}
}
}