package org.apache.usergrid.persistence.collection.serialization.impl;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
import org.apache.usergrid.persistence.collection.MvccLogEntry;
import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategy;
import org.apache.usergrid.persistence.core.scope.ApplicationScope;
import org.apache.usergrid.persistence.model.entity.Id;
import com.google.common.base.Preconditions;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
/**
* Iterator that will iterate all versions of the entity from the log from < the specified maxVersion
*/
public class MinMaxLogEntryIterator implements Iterator<MvccLogEntry> {
private final MvccLogEntrySerializationStrategy logEntrySerializationStrategy;
private final ApplicationScope scope;
private final Id entityId;
private final int pageSize;
private Iterator<MvccLogEntry> elementItr;
private UUID nextStart;
/**
* @param logEntrySerializationStrategy The serialization strategy to get the log entries
* @param scope The scope of the entity
* @param entityId The id of the entity
* @param pageSize The fetch size to get when querying the serialization strategy
*/
public MinMaxLogEntryIterator( final MvccLogEntrySerializationStrategy logEntrySerializationStrategy,
final ApplicationScope scope, final Id entityId, final int pageSize ) {
Preconditions.checkArgument( pageSize > 0, "pageSize must be > 0" );
this.logEntrySerializationStrategy = logEntrySerializationStrategy;
this.scope = scope;
this.entityId = entityId;
this.pageSize = pageSize;
}
@Override
public boolean hasNext() {
if ( elementItr == null || !elementItr.hasNext() && nextStart != null ) {
try {
advance();
}
catch ( ConnectionException e ) {
throw new RuntimeException( "Unable to query cassandra", e );
}
}
return elementItr.hasNext();
}
@Override
public MvccLogEntry next() {
if ( !hasNext() ) {
throw new NoSuchElementException( "No more elements exist" );
}
return elementItr.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException( "Remove is unsupported" );
}
/**
* Advance our iterator
*/
public void advance() throws ConnectionException {
final int requestedSize;
if ( nextStart != null ) {
requestedSize = pageSize + 1;
}
else {
requestedSize = pageSize;
}
//loop through even entry that's < this one and remove it
List<MvccLogEntry> results = logEntrySerializationStrategy.loadReversed( scope, entityId, nextStart, requestedSize );
//we always remove the first version if it's equal since it's returned
if ( nextStart != null && results.size() > 0 && results.get( 0 ).getVersion().equals( nextStart ) ) {
results.remove( 0 );
}
//we have results, set our next start. If we miss our start version (due to deletion) and we request a +1, we want to ensure we set our next, hence the >=
if ( results.size() >= pageSize ) {
nextStart = results.get( results.size() - 1 ).getVersion();
}
//nothing left to do
else {
nextStart = null;
}
elementItr = results.iterator();
}
}