package nl.thanod.cassandra.alpha.map.supercolumn;
import java.util.*;
import nl.thanod.cassandra.CassandraConstants;
import org.apache.cassandra.thrift.*;
import org.apache.cassandra.thrift.Cassandra.Iface;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
public class SuperColumnFamilyKeySet implements Set<String> {
public static int BUFFER_SIZE = 100;
private final Iface client;
private final String keyspace;
private final String column_family;
private final ConsistencyLevel readLevel;
private final ConsistencyLevel writeLevel;
public SuperColumnFamilyKeySet(Cassandra.Iface client, String keyspace, String column_family) {
this(client, keyspace, column_family, ConsistencyLevel.ANY);
}
public SuperColumnFamilyKeySet(Cassandra.Iface client, String keyspace, String column_family, ConsistencyLevel consistency_level) {
this(client, keyspace, column_family, consistency_level, consistency_level);
}
public SuperColumnFamilyKeySet(Cassandra.Iface client, String keyspace, String column_family, ConsistencyLevel readLevel, ConsistencyLevel writeLevel) {
this.client = client;
this.keyspace = keyspace;
this.column_family = column_family;
this.readLevel = readLevel;
this.writeLevel = writeLevel;
}
@Override
public boolean add(String e) {
throw new UnsupportedOperationException("Unable to add things to a SuperColumnFamilyKeySet");
}
@Override
public boolean addAll(Collection<? extends String> c) {
throw new UnsupportedOperationException("Unable to add things to a SuperColumnFamilyKeySet");
}
@Override
public void clear() {
Iterator<String> keys = this.iterator();
while (keys.hasNext()) {
keys.next();
keys.remove();
}
}
@Override
public boolean contains(Object o) {
if (!(o instanceof String))
return false;
// because every key is contained, but maps returned could be empty
return true;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c)
if (!this.contains(o))
return false;
return true;
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
throw new NotImplementedException();
}
@Override
public Iterator<String> iterator() {
return new SuperColumnFamilyKeyIterator(client, keyspace, column_family, readLevel, writeLevel);
}
@Override
public boolean remove(Object o) {
if (!(o instanceof String))
return false;
try {
client.remove(this.keyspace, (String) o, new ColumnPath(this.column_family), CassandraConstants.getTime(), this.writeLevel);
return true;
} catch (Throwable ball) {
throw new RuntimeException("Unable to recover from " + ball.getClass().getCanonicalName(), ball);
}
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("Unable to remove things from a SuperColumnFamilyKeySet");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException("Unable to remove things from a SuperColumnFamilyKeySet");
}
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object[] toArray() {
throw new NotImplementedException();
}
@Override
public <T> T[] toArray(T[] a) {
throw new NotImplementedException();
}
static class SuperColumnFamilyKeyIterator implements Iterator<String> {
private final Iface client;
private final String keyspace;
private final String column_family;
private final Queue<String> buffer;
private final ConsistencyLevel readLevel;
private final ConsistencyLevel writeLevel;
private String lastBufferedKey = CassandraConstants.EMPTY_STRING;
private boolean finished = false;
private String readLast = null;
public SuperColumnFamilyKeyIterator(Cassandra.Iface client, String keyspace, String column_family, ConsistencyLevel readLevel, ConsistencyLevel writeLevel) {
this.client = client;
this.keyspace = keyspace;
this.column_family = column_family;
this.buffer = new LinkedList<String>();
this.readLevel = readLevel;
this.writeLevel = writeLevel;
}
private void fillBuffer() {
if (finished)
return;
try {
ColumnParent column_parent = new ColumnParent(this.column_family);
SlicePredicate predicate = new SlicePredicate();
predicate.slice_range = new SliceRange(CassandraConstants.EMPTY_BYTES, CassandraConstants.EMPTY_BYTES, false, 1);
// add one to the buffersize because you can find lastBufferedKey at the first place of the returned list
List<KeySlice> list = client.get_range_slice(this.keyspace, column_parent, predicate, lastBufferedKey, CassandraConstants.EMPTY_STRING, SuperColumnFamilyKeySet.BUFFER_SIZE+1, this.readLevel);
// if the first key is the one starting on, remove it
if (list.size() > 0 && lastBufferedKey.equals(list.get(0).key)) {
list.remove(0);
}
if (list.size() == 0) {
finished = true;
} else {
for (KeySlice k : list) {
if (k.columns.size() != 0)
buffer.add(k.key);
lastBufferedKey = k.key;
}
}
} catch (Throwable ball) {
//TODO find a way to handle the connection drops
ball.printStackTrace();
}
}
@Override
public boolean hasNext() {
while (!finished && buffer.size() == 0)
fillBuffer();
return buffer.size() > 0;
}
@Override
public String next() {
if (hasNext())
return readLast = buffer.poll();
else
readLast = null;
throw new NoSuchElementException();
}
@Override
public void remove() {
System.out.println("removing " + readLast);
if (readLast == null)
throw new IllegalStateException();
try {
client.remove(keyspace, readLast, new ColumnPath(column_family), CassandraConstants.getTime(), writeLevel);
} catch (Throwable ball) {
throw new RuntimeException("Unrecoverable exception " + ball.getClass().getCanonicalName(), ball);
}
}
}
}