package org.yamcs.yarch.rocksdb;
import java.util.Arrays;
import org.rocksdb.RocksIterator;
import org.yamcs.utils.ByteArrayUtils;
/**
* wrapper around a rocksdb iterator that only supports prev() and is restricted to a range.
*
* if strictStart=true
* then the first rangeStart.length bytes of the key are compared with the rangeStart, if they are equal the record is skipped.
* same is valid for strictEnd
*
* So with the following DB:
* 1: 0x00 0x00 0x00 0x02
* 2: 0x01 0x01 0x01 0x00
* 3: 0x01 0x01 0x01 0x03
* 4: 0x01 0x01 0x02 0x00
*
* and rangeStart = 0x01 0x01 0x01, strictStart=true
*
* the iterator will skip records 1,2 and 3 and start from record 4
*
*
* @author nm
*
*/
public class DescendingRangeIterator implements DbIterator {
final RocksIterator iterator;
final byte[] rangeStart;
final boolean strictStart;
final byte[] rangeEnd;
final boolean strictEnd;
boolean valid = false;
private byte[] curKey;
public DescendingRangeIterator(RocksIterator it, byte[] rangeStart, boolean strictStart, byte[] rangeEnd, boolean strictEnd) {
this.iterator = it;
this.rangeStart = rangeStart;
this.rangeEnd = rangeEnd;
this.strictStart = strictStart;
this.strictEnd = strictEnd;
init();
}
private void init() {
boolean endFound = false;
if(rangeEnd == null) {
iterator.seekToLast();
if(iterator.isValid()) {
curKey = iterator.key();
endFound = true;
}
} else {
iterator.seek(rangeEnd); //seek moves cursor beyond the match
if(iterator.isValid()) {
curKey = iterator.key();
if(!strictEnd && Arrays.equals(curKey, rangeEnd)) {
endFound = true;
} else {
iterator.prev();
if(iterator.isValid()) {
curKey = iterator.key();
endFound = true;
}
}
} else { //reached the end of the table -> check the last entry
iterator.seekToLast();
if(iterator.isValid()) {
curKey = iterator.key();
endFound = true;
}
}
}
if(endFound) {
//check that it is not earlier than start
if(rangeStart!=null) {
int c = ByteArrayUtils.compare(rangeStart, curKey);
if((strictStart && c<0) || (c<=0)) {
valid = true;
}
} else {
valid = true;
}
}
}
@Override
public boolean isValid() {
return valid;
}
@Override
public void prev() {
if(!valid) throw new IllegalStateException("iterator is not valid");
iterator.prev();
if(iterator.isValid()) {
curKey = iterator.key();
if(rangeStart!=null) {
valid = false;
int c = ByteArrayUtils.compare(rangeStart, curKey);
if((strictStart && c<0) || (c<=0)) {
valid = true;
}
}
} else {
valid = false;
}
}
@Override
public void next() {
throw new UnsupportedOperationException("this is an desceinding iterator, next() not supported");
}
public byte[] key() {
if(!valid) throw new IllegalStateException("iterator is not valid");
return curKey;
}
public byte[] value() {
if(!valid) throw new IllegalStateException("iterator is not valid");
return iterator.value();
}
@Override
public void close() {
iterator.close();
}
}