package com.after_sunrise.oss.otdb.je.database.impl; import static com.google.common.base.Preconditions.checkNotNull; import static com.sleepycat.je.OperationStatus.SUCCESS; import java.io.IOException; import com.after_sunrise.oss.otdb.je.binding.TickKeyTupleBinding; import com.after_sunrise.oss.otdb.je.binding.TickValueTupleBinding; import com.after_sunrise.oss.otdb.je.database.TickDatabaseIterator; import com.after_sunrise.oss.otdb.je.entity.TickEntry; import com.after_sunrise.oss.otdb.je.entity.TickKey; import com.after_sunrise.oss.otdb.je.entity.TickValue; import com.sleepycat.je.Cursor; import com.sleepycat.je.DatabaseEntry; import com.sleepycat.je.LockMode; /** * @author takanori.takase */ public class TickDatabaseIteratorImpl implements TickDatabaseIterator { private final DatabaseEntry key = new DatabaseEntry(); private final DatabaseEntry val = new DatabaseEntry(); private final Cursor cursor; private final LockMode lockMode; private final TickKeyTupleBinding keyBinding; private final TickValueTupleBinding valBinding; private final TickKey start; private final TickKey end; public TickDatabaseIteratorImpl(Cursor cursor, LockMode lockMode, TickKeyTupleBinding keyBinding, TickValueTupleBinding valBinding, long id, long start, long end) { this.cursor = checkNotNull(cursor); this.lockMode = checkNotNull(lockMode); this.keyBinding = checkNotNull(keyBinding); this.valBinding = checkNotNull(valBinding); this.start = new TickKey(id, start, Long.MIN_VALUE); this.end = new TickKey(id, end, Long.MAX_VALUE); } @Override public void close() throws IOException { cursor.close(); } @Override public TickEntry first() throws IOException { return next(start.getTimestamp()); } @Override public TickEntry previous() throws IOException { if (cursor.getPrev(key, val, lockMode) != SUCCESS) { return null; } TickKey k = keyBinding.entryToObject(key); if (k.compareTo(start) < 0) { return null; } if (k.compareTo(end) > 0) { return previous(); } TickValue v = valBinding.entryToObject(val); return new TickEntry(k, v); } @Override public TickEntry previous(long timestamp) throws IOException { long adjusted = Math.min(timestamp, end.getTimestamp()); TickKey temp = new TickKey(end.getCodeId(), adjusted, Long.MAX_VALUE); keyBinding.objectToEntry(temp, key); // Returns equal or greater if (cursor.getSearchKeyRange(key, val, lockMode) != SUCCESS) { // If not found, cursor does not move, so force move here. cursor.getLast(key, val, lockMode); } TickKey k = keyBinding.entryToObject(key); if (k.compareTo(start) < 0) { return null; } if (k.compareTo(temp) > 0) { return previous(); } TickValue v = valBinding.entryToObject(val); return new TickEntry(k, v); } @Override public TickEntry next() throws IOException { if (cursor.getNext(key, val, lockMode) != SUCCESS) { return null; } TickKey k = keyBinding.entryToObject(key); if (k.compareTo(start) < 0) { return next(); } if (k.compareTo(end) > 0) { return null; } TickValue v = valBinding.entryToObject(val); return new TickEntry(k, v); } @Override public TickEntry next(long timestamp) throws IOException { long adjusted = Math.max(timestamp, start.getTimestamp()); TickKey temp = new TickKey(start.getCodeId(), adjusted, Long.MIN_VALUE); keyBinding.objectToEntry(temp, key); // Returns equal or greater if (cursor.getSearchKeyRange(key, val, lockMode) != SUCCESS) { return null; } TickKey k = keyBinding.entryToObject(key); if (k.compareTo(temp) < 0) { return next(); } if (k.compareTo(end) > 0) { return null; } TickValue v = valBinding.entryToObject(val); return new TickEntry(k, v); } @Override public TickEntry last() throws IOException { return previous(end.getTimestamp()); } }