package org.wikipedia.miner.db;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.log4j.Logger;
import com.sleepycat.je.*;
//TODO: doesn't this always miss out on the last item?
/*TODO: what if the database is cached to memory?
*
* currently ignored, which is bad for speed, but more critically, would cause mismatches between data
* available via lookup, and data available via iteration (the former might be filtered, and the latter will not be)
*
*
*/
/**
* An iterator that will cycle through all entries in a WDatabase.
*
*
*
* @param <K>
* @param <V>
*/
public class WIterator<K,V> implements Iterator<WEntry<K,V>> {
WDatabase<K,V> db ;
Cursor cursor ;
WEntry<K,V> nextEntry ;
DatabaseEntry key = new DatabaseEntry() ;
DatabaseEntry value = new DatabaseEntry() ;
/**
* Creates an iterator that will cycle through all entries the given WDatabase.
*
* @param database an active (connected) WDatabase.
*/
public WIterator(WDatabase<K,V> database) {
this.db = database ;
cursor = db.getDatabase(true).openCursor(null, null) ;
cursor.setCacheMode(CacheMode.UNCHANGED) ;
queueNext() ;
}
public boolean hasNext() {
return (nextEntry != null);
}
public void remove() {
throw new UnsupportedOperationException() ;
}
/**
* Tidily closes the {@link Cursor} underlying this iterator. This should be called before
* destroying the object.
*/
public void close() {
cursor.close();
this.cursor = null ;
}
public void finalize() {
if (this.cursor != null) {
Logger.getLogger(WIterator.class).warn("Unclosed iterator. You may be causing a memory leak.") ;
}
}
public WEntry<K,V> next() {
if (nextEntry == null)
throw new NoSuchElementException() ;
WEntry<K,V> e = nextEntry ;
queueNext() ;
return e ;
}
private void queueNext() {
if (cursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
K k = db.keyBinding.entryToObject(key) ;
V v = db.valueBinding.entryToObject(value) ;
nextEntry = new WEntry<K,V>(k,v) ;
} else {
nextEntry = null ;
}
}
}