package com.pardot.rhombus.util.faker; import com.datastax.driver.core.utils.UUIDs; import com.google.common.collect.*; import com.pardot.rhombus.Criteria; import com.pardot.rhombus.RhombusException; import com.pardot.rhombus.cobject.CDefinition; import com.pardot.rhombus.cobject.CField; import com.pardot.rhombus.cobject.CIndex; import com.pardot.rhombus.cobject.CObjectOrdering; import com.pardot.rhombus.cobject.shardingstrategy.*; import java.math.BigInteger; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; /** * User: Rob Righter * Date: 3/13/14 */ public class FakeCIndex { private CIndex index; private FakeIdRange uniqueRange = null; private List<FakeCIndex> indexesThatIAmASubsetOf = null; private Range<Long> wideRowCounterRange; private List<String> nonIndexValuesOnAnyIndex; private CDefinition def; public FakeCIndex(CIndex index, CDefinition def, Object startId, Long totalWideRows, Long totalObjectsPerWideRange, Long objectsPerShard ){ this.index = index; this.indexesThatIAmASubsetOf = Lists.newArrayList(); // Each index's id range is represented by a fakeIdRange object, which represents all the ids for that index, // across all the index's shards/wide rows this.uniqueRange = new FakeIdRange(def.getPrimaryKeyCDataType(),startId,totalObjectsPerWideRange,objectsPerShard,index.getShardingStrategy(), index.getKey()); this.wideRowCounterRange = Range.closed(1L, totalWideRows); this.def = def; this.nonIndexValuesOnAnyIndex = Lists.newArrayList(); List<String> masterIndexValuesList = Lists.newArrayList(); for(CIndex i : def.getIndexes().values()){ masterIndexValuesList.addAll(i.getCompositeKeyList()); } for(CField f : def.getFields().values()){ if(!masterIndexValuesList.contains(f.getName())){ this.nonIndexValuesOnAnyIndex.add(f.getName()); } } } public boolean isCovering(CIndex otherIndex) { return this.index.getKey().contains(otherIndex.getKey()); } public FakeIdRange getUniqueRange() { return uniqueRange; } public void addCoveringIndex(FakeCIndex findex) { indexesThatIAmASubsetOf.add(findex); } public Map<String, Object> makeObject(Long topCounter, FakeIdRange.IdInRange idInRange){ Map<String,Object> ret = Maps.newHashMap(); //set the Id ret.put("id", idInRange.getId()); //set the index values for(String indexValue : index.getCompositeKeyList()){ CField f = def.getField(indexValue); ret.put(indexValue,getFieldValueAtCounter(topCounter,f)); } //set the non-index values for(String nonIndexValue : this.nonIndexValuesOnAnyIndex){ CField f = def.getField(nonIndexValue); ret.put(nonIndexValue,getFieldValueAtCounter(idInRange.getCounterValue(),f)); } return ret; } public Object getSuggestedIdForStartofNextIndex(TimebasedShardingStrategy shardingStrategyOfNextIndex) throws RhombusException { return this.getUniqueRange().getSuggestedIdForStartofNextIndex(shardingStrategyOfNextIndex); } /** * * @return */ public Iterator<Map<String, Object>> getMasterIterator(CObjectOrdering ordering) throws RhombusException{ return getIterator(ordering, null, null); } public Iterator<Map<String, Object>> getIterator(CObjectOrdering ordering, Object startId, Object endId) throws RhombusException { ContiguousSet<Long> wideRowCounterSet = ContiguousSet.create(this.wideRowCounterRange, DiscreteDomain.longs()); Iterator<Long> topLevelWideRowIterator = (ordering == CObjectOrdering.ASCENDING) ? wideRowCounterSet.iterator() : wideRowCounterSet.descendingIterator(); return new FakeCIndexIterator(topLevelWideRowIterator, this.getUniqueRange(), ordering, startId, endId); } /** * * @param key Key of object to get * @return Object of type with key or null if it does not exist */ public Map<String, Object> getByKeyAndCounter(Long topLevelCounter, Object key) throws RhombusException { Map<String,Object> ret = null; if(uniqueRange.isIdInRange(key)){ return makeObject(topLevelCounter, uniqueRange.getIdInRangeAtCounter(uniqueRange.getCounterAtId(key))); } else { for(FakeCIndex fr : this.indexesThatIAmASubsetOf){ if(fr.getUniqueRange().isIdInRange(key)){ return makeObject(topLevelCounter, fr.getUniqueRange().getIdInRangeAtCounter(uniqueRange.getCounterAtId(key))); } } } return null; } public Iterator<Map<String, Object>> list(String objectType, Criteria criteria) { //TODO: get the counter range for this criteria and make an iterator for it return null; } public Object getFieldValueAtCounter(Long counter, CField field){ switch (field.getType()) { case ASCII: case VARCHAR: case TEXT: return counter+""; case INT: return Integer.valueOf(counter.intValue()); case BIGINT: case COUNTER: return Long.valueOf(counter); case BLOB: throw new IllegalArgumentException(); case BOOLEAN: return ((counter%2)==0)? Boolean.valueOf(true) : Boolean.valueOf(false); case DECIMAL: case FLOAT: return Float.valueOf(counter.floatValue()); case DOUBLE: return Double.valueOf(counter.floatValue()); case TIMESTAMP: return new Date(counter); case UUID: case TIMEUUID: return UUIDs.startOf(counter); case VARINT: return BigInteger.valueOf(counter); default: return null; } } public class FakeCIndexIterator implements Iterator<Map<String,Object>> { private FakeIdRange fRange; private Iterator<FakeIdRange.IdInRange> rowIt; private Iterator<Long> wideRowCounterIt; private CObjectOrdering ordering; Object startId; Object endId; Long currentWideRowCounter; public FakeCIndexIterator(Iterator<Long> wideRowCounterIt, FakeIdRange fRange, CObjectOrdering ordering, Object startId, Object endId) throws RhombusException{ this.fRange = fRange; this.ordering = ordering; this.startId = startId; this.endId = endId; resetRowIt(); this.wideRowCounterIt = wideRowCounterIt; this.currentWideRowCounter = wideRowCounterIt.next(); } public void resetRowIt() throws RhombusException { if((startId != null) && (endId != null)){ this.rowIt = fRange.getIterator(ordering,startId,endId); } else{ this.rowIt = fRange.getIterator(ordering); } } public boolean hasNext(){ return rowIt.hasNext(); } public Map<String,Object> next() { if(rowIt.hasNext()){ FakeIdRange.IdInRange lastIdInRange = rowIt.next(); return makeObject(lastIdInRange.getCounterValue(),lastIdInRange); } else { return null; } } public void remove(){ wideRowCounterIt.remove(); rowIt.remove(); } } }