package com.alvazan.orm.layer5.query;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import com.alvazan.orm.api.z5api.IndexColumnInfo;
import com.alvazan.orm.api.z8spi.conv.Precondition;
import com.alvazan.orm.api.z8spi.iter.AbstractCursor.Holder;
import com.alvazan.orm.api.z8spi.iter.DirectCursor;
import com.alvazan.orm.api.z8spi.iter.StringLocal;
/**
* After iterating through any node that only contains less than 500 results, we will not go back
* to noSQL store when using the Caching Cursor
* @author dhiller
*
* @param <T>
*/
public class CachingCursor<T> implements DirectCursor<IndexColumnInfo> {
private DirectCursor<IndexColumnInfo> cursor;
private List<IndexColumnInfo> cached = new ArrayList<IndexColumnInfo>();
private ListIterator<IndexColumnInfo> cachedIter;
private boolean cacheEnabled = false;
public CachingCursor(DirectCursor<IndexColumnInfo> cursor) {
Precondition.check(cursor, "cursor");
this.cursor = cursor;
}
@Override
public String toString() {
String tabs = StringLocal.getAndAdd();
String retVal = "CachingCursor["+tabs+cursor+tabs+"]";
StringLocal.set(tabs.length());
return retVal;
}
@Override
public Holder<IndexColumnInfo> nextImpl() {
if(cacheEnabled) {
return fetchFromCache();
}
Holder<IndexColumnInfo> next = cursor.nextImpl();
if(next != null) {
if(cached.size() < 500)
cached.add(next.getValue());
return next;
}
if(cached.size() < 500) {
cacheEnabled = true;
}
return null;
}
@Override
public Holder<IndexColumnInfo> previousImpl() {
if(cacheEnabled) {
return fetchPreviousFromCache();
}
Holder<IndexColumnInfo> previous = cursor.previousImpl();
if(previous != null) {
if(cached.size() < 500)
cached.add(0, previous.getValue());
return previous;
}
if(cached.size() < 500) {
cacheEnabled = true;
}
return null;
}
private Holder<IndexColumnInfo> fetchFromCache() {
if(cachedIter == null)
return null;
else if(!cachedIter.hasNext())
return null;
IndexColumnInfo next = cachedIter.next();
return new Holder<IndexColumnInfo>(next.copy());
}
private Holder<IndexColumnInfo> fetchPreviousFromCache() {
if(cachedIter == null)
return null;
else if(!cachedIter.hasPrevious())
return null;
IndexColumnInfo prev = cachedIter.previous();
return new Holder<IndexColumnInfo>(prev.copy());
}
@Override
public void beforeFirst() {
if(cacheEnabled)
cachedIter = cached.listIterator();
else
cursor.beforeFirst();
}
@Override
public void afterLast() {
if(cacheEnabled) {
cachedIter = cached.listIterator();
while(cachedIter.hasNext()) cachedIter.next();
}
else
cursor.afterLast();
}
}