package com.feedly.cassandra.dao;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import me.prettyprint.cassandra.serializers.AsciiSerializer;
import me.prettyprint.cassandra.serializers.BytesArraySerializer;
import me.prettyprint.cassandra.serializers.CompositeSerializer;
import me.prettyprint.cassandra.serializers.DynamicCompositeSerializer;
import me.prettyprint.cassandra.serializers.IntegerSerializer;
import me.prettyprint.cassandra.serializers.LongSerializer;
import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.hector.api.Keyspace;
import me.prettyprint.hector.api.beans.ColumnSlice;
import me.prettyprint.hector.api.beans.Composite;
import me.prettyprint.hector.api.beans.CounterSlice;
import me.prettyprint.hector.api.beans.DynamicComposite;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hector.api.beans.HCounterColumn;
import me.prettyprint.hector.api.beans.Row;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.query.RangeSlicesQuery;
import me.prettyprint.hector.api.query.SliceCounterQuery;
import me.prettyprint.hector.api.query.SliceQuery;
import org.junit.Before;
import org.junit.Test;
import com.feedly.cassandra.EConsistencyLevel;
import com.feedly.cassandra.PersistenceManager;
import com.feedly.cassandra.entity.ByteIndicatorSerializer;
import com.feedly.cassandra.entity.EntityMetadata;
import com.feedly.cassandra.entity.EntityUtils;
import com.feedly.cassandra.entity.EnumSerializer;
import com.feedly.cassandra.entity.IndexMetadata;
import com.feedly.cassandra.entity.TestPartitioner;
import com.feedly.cassandra.entity.enhance.CompositeIndexedBean;
import com.feedly.cassandra.entity.enhance.CounterBean;
import com.feedly.cassandra.entity.enhance.ESampleEnum;
import com.feedly.cassandra.entity.enhance.EmbeddedBean;
import com.feedly.cassandra.entity.enhance.EmbeddedCounterBean;
import com.feedly.cassandra.entity.enhance.IEnhancedEntity;
import com.feedly.cassandra.entity.enhance.IndexedBean;
import com.feedly.cassandra.entity.enhance.ListBean;
import com.feedly.cassandra.entity.enhance.MapBean;
import com.feedly.cassandra.entity.enhance.NestedBean;
import com.feedly.cassandra.entity.enhance.ParentBean;
import com.feedly.cassandra.entity.enhance.ParentCounterBean;
import com.feedly.cassandra.entity.enhance.PartitionedIndexBean;
import com.feedly.cassandra.entity.enhance.SampleBean;
import com.feedly.cassandra.entity.enhance.SortedMapBean;
import com.feedly.cassandra.entity.enhance.TtlBean;
import com.feedly.cassandra.test.CassandraServiceTestBase;
@SuppressWarnings({"unchecked", "rawtypes"})
public class CassandraDaoBaseTest extends CassandraServiceTestBase
{
PersistenceManager _pm;
SampleBeanDao _dao;
MapBeanDao _mapDao;
SortedMapBeanDao _sortedMapDao;
ListBeanDao _listDao;
ParentBeanDao _parentBeanDao;
NestedBeanDao _nestedBeanDao;
IndexedBeanDao _indexedDao;
CompositeIndexedBeanDao _compositeIndexedDao;
CounterBeanDao _counterDao;
ParentCounterBeanDao _parentCounterDao;
RecordingStrategy _indexedStrategy, _compositeStrategy;
@Before
public void before()
{
_pm = new PersistenceManager();
_dao = new SampleBeanDao();
_dao.setKeyspaceFactory(_pm);
_dao.init();
_counterDao = new CounterBeanDao();
_counterDao.setKeyspaceFactory(_pm);
_counterDao.init();
_mapDao = new MapBeanDao();
_mapDao.setKeyspaceFactory(_pm);
_mapDao.init();
_sortedMapDao = new SortedMapBeanDao();
_sortedMapDao.setKeyspaceFactory(_pm);
_sortedMapDao.init();
_listDao = new ListBeanDao();
_listDao.setKeyspaceFactory(_pm);
_listDao.init();
_parentBeanDao = new ParentBeanDao();
_parentBeanDao.setKeyspaceFactory(_pm);
_parentBeanDao.init();
_parentCounterDao = new ParentCounterBeanDao();
_parentCounterDao.setKeyspaceFactory(_pm);
_parentCounterDao.init();
_nestedBeanDao = new NestedBeanDao();
_nestedBeanDao.setKeyspaceFactory(_pm);
_nestedBeanDao.init();
_indexedDao = new IndexedBeanDao();
_indexedDao.setKeyspaceFactory(_pm);
_indexedStrategy = new RecordingStrategy();
_indexedDao.setStaleValueIndexStrategy(_indexedStrategy);
_indexedDao.init();
_compositeIndexedDao = new CompositeIndexedBeanDao();
_compositeIndexedDao.setKeyspaceFactory(_pm);
_compositeStrategy = new RecordingStrategy();
_compositeIndexedDao.setStaleValueIndexStrategy(_compositeStrategy);
_compositeIndexedDao.init();
configurePersistenceManager(_pm);
_pm.setPackagePrefixes(new String[] {SampleBean.class.getPackage().getName()});
_pm.init();
}
private void assertBean(String msg, SampleBean bean, ColumnSlice<String, byte[]> columnSlice)
{
assertEquals(msg, 9 + (bean.getUnmapped() == null ? 0 : bean.getUnmapped().size()), columnSlice.getColumns().size());
for(HColumn<String, byte[]> col : columnSlice.getColumns())
{
String n = col.getName();
if(n.equals("boolVal"))
assertColumn(msg, bean.getBoolVal(), false, col);
else if(n.equals("charVal"))
assertColumn(msg, bean.getCharVal(), false, col);
else if(n.equals("dateVal"))
assertColumn(msg, bean.getDateVal(), false, col);
else if(n.equals("d"))
assertColumn(msg, bean.getDoubleVal(), false, col);
else if(n.equals("floatVal"))
assertColumn(msg, bean.getFloatVal(), false, col);
else if(n.equals("intVal"))
assertColumn(msg, bean.getIntVal(), false, col);
else if(n.equals("l"))
assertColumn(msg, bean.getLongVal(), false, col);
else if(n.equals("s"))
assertColumn(msg, bean.getStrVal(), false, col);
else if(n.equals("sampleEnum"))
{
byte[] value = col.getValue();
assertEquals(msg, bean.getSampleEnum(), new EnumSerializer(ESampleEnum.class).fromBytes(value));
assertEquals(msg, bean.getSampleEnum().name(), StringSerializer.get().fromBytes(value));
}
else
assertColumn(bean.getUnmapped().get(n), true, col);
}
}
private void assertColumn(Object expected, boolean indicatorExpected, HColumn<?, byte[]> col)
{
assertColumn(null, expected, indicatorExpected, col);
}
private void assertColumn(String message, Object expected, boolean indicatorExpected, HColumn<?, byte[]> col)
{
byte[] value = col.getValue();
if(indicatorExpected)
{
assertEquals(message, ByteIndicatorSerializer.INDICATOR_BYTES.get(expected.getClass()), col.getValue()[0]);
value = new byte[col.getValue().length - 1];
System.arraycopy(col.getValue(), 1, value, 0, value.length);
}
assertEquals(message, expected, EntityUtils.getSerializer(expected.getClass()).fromBytes(value));
}
private <T> void assertBeansEqual(List<T> expecteds, List<T> actuals)
{
for(int i = 0; i < Math.min(expecteds.size(), actuals.size()); i++)
{
assertEquals("position[" + i + "]", expecteds.get(i), actuals.get(i));
}
assertEquals("size", expecteds.size(), actuals.size());
}
/*
* begin test cases
*/
@Test
public void testSimplePut()
{
int numBeans = 5;
List<SampleBean> beans = new ArrayList<SampleBean>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setUnmapped(new HashMap<String, Object>());
bean.setSampleEnum(ESampleEnum.values()[i % ESampleEnum.values().length]);
for(int j = 0; j <= i; j++)
bean.getUnmapped().put("unmapped-" + j, j);
beans.add(bean);
}
for(SampleBean bean : beans)
{
_dao.put(bean);
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
assertFalse(((IEnhancedEntity) bean).getUnmappedFieldsModified());
SliceQuery<Long,String,byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), AsciiSerializer.get(), BytesArraySerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("sample");
query.setRange("", "", false, 100);
ColumnSlice<String, byte[]> columnSlice = query.execute().get();
assertBean("beans[" + bean.getIntVal() + "]", bean, columnSlice);
}
SampleBean bean0 = beans.get(0);
//make sure only dirty fields are saved
bean0.setStrVal("updated");
bean0.setDoubleVal(100.0);
bean0.setUnmapped((Map) Collections.singletonMap("unmapped-0", 100));
IEnhancedEntity bean = (IEnhancedEntity) bean0;
bean.getModifiedFields().clear(8);
bean.setUnmappedFieldsModified(false);
_dao.put(bean0);
bean0.setStrVal("str-0");
bean0.setUnmapped((Map) Collections.singletonMap("unmapped-0", 0));
SliceQuery<Long,String,byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), AsciiSerializer.get(), BytesArraySerializer.get());
query.setKey(bean0.getRowKey());
query.setColumnFamily("sample");
query.setRange("", "", false, 100);
assertBean("dirty test", bean0, query.execute().get());
}
@Test
public void testCounterPut()
{
int numBeans = 5;
List<CounterBean> beans = new ArrayList<CounterBean>();
List<ParentCounterBean> pbeans = new ArrayList<ParentCounterBean>();
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = new CounterBean();
bean.setRowKey(new Long(i));
bean.setCounterVal(new CounterColumn(i*10));
beans.add(bean);
ParentCounterBean pbean = new ParentCounterBean();
pbean.setRowkey(new Long(i));
pbean.setCounterProp(new CounterColumn(i*20));
pbean.setEmbeddedProp(createEmbeddedCounterBean(i));
pbeans.add(pbean);
}
for(CounterBean bean : beans)
{
_counterDao.put(bean);
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
assertFalse(((IEnhancedEntity) bean).getUnmappedFieldsModified());
SliceCounterQuery<Long,String> query = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), StringSerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("counter_cntr");
query.setRange("", "", false, 100);
CounterSlice<String> columnSlice = query.execute().get();
HCounterColumn<String> counterColumn = columnSlice.getColumns().get(0);
assertEquals("beans[" + bean.getRowKey() + "]", 1, columnSlice.getColumns().size());
assertEquals("beans[" + bean.getRowKey() + "]", bean.getRowKey()*10, counterColumn.getValue());
assertEquals("c", counterColumn.getName());
bean.getCounterVal().setIncrement(10);
_counterDao.put(bean);
columnSlice = query.execute().get();
counterColumn = columnSlice.getColumns().get(0);
assertEquals("beans[" + bean.getRowKey() + "]", 10 + bean.getRowKey()*10, counterColumn.getValue());
/*
* null out values and resave, ensure values are deleted
*/
bean.setCounterVal(null);
_counterDao.put(bean);
columnSlice = query.execute().get();
assertTrue(columnSlice.getColumns().isEmpty());
}
for(ParentCounterBean bean : pbeans)
{
_parentCounterDao.put(bean);
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
assertFalse(((IEnhancedEntity) bean).getUnmappedFieldsModified());
SliceCounterQuery<Long,DynamicComposite> query = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), DynamicCompositeSerializer.get());
query.setKey(bean.getRowkey());
query.setColumnFamily("parentcounterbean_cntr");
query.setRange(new DynamicComposite(""), new DynamicComposite("z"), false, 100);
CounterSlice<DynamicComposite> columnSlice = query.execute().get();
assertEquals("beans[" + bean.getRowkey() + "]", 2, columnSlice.getColumns().size());
assertEquals("beans[" + bean.getRowkey() + "]", bean.getRowkey() * 20, columnSlice.getColumnByName(new DynamicComposite("c")).getValue());
assertEquals("beans[" + bean.getRowkey() + "]", bean.getRowkey(), columnSlice.getColumnByName(new DynamicComposite("e", "c")).getValue());
bean.getCounterProp().setIncrement(10);
_parentCounterDao.put(bean);
columnSlice = query.execute().get();
assertEquals("beans[" + bean.getRowkey() + "]", 2, columnSlice.getColumns().size());
assertEquals("beans[" + bean.getRowkey() + "]", bean.getRowkey() * 20 + 10, columnSlice.getColumnByName(new DynamicComposite("c")).getValue());
assertEquals("beans[" + bean.getRowkey() + "]", bean.getRowkey(), columnSlice.getColumnByName(new DynamicComposite("e", "c")).getValue());
/*
* null out values and resave, ensure values are deleted
*/
bean.getEmbeddedProp().setCounterProp(null);
_parentCounterDao.put(bean);
columnSlice = query.execute().get();
assertEquals("beans[" + bean.getRowkey() + "]", 1, columnSlice.getColumns().size());
assertEquals("beans[" + bean.getRowkey() + "]", bean.getRowkey() * 20 + 10, columnSlice.getColumnByName(new DynamicComposite("c")).getValue());
assertNull("beans[" + bean.getRowkey() + "]", columnSlice.getColumnByName(new DynamicComposite("e", "c")));
}
}
@Test
public void testColumnFamilyTtl() throws InterruptedException
{
CassandraDaoBase<Long, TtlBean> dao = new CassandraDaoBase<Long, TtlBean>(Long.class, TtlBean.class, EConsistencyLevel.ONE);
dao.setKeyspaceFactory(_pm);
dao.init();
TtlBean bean = new TtlBean();
bean.setRowKey(10L);
bean.setStrVal1("v1");
bean.setStrVal2("v2");
bean.setStrVal3("v3");
dao.put(bean);
TtlBean tmpl = new TtlBean();
tmpl.setStrVal1(bean.getStrVal1());
tmpl.setStrVal2(bean.getStrVal2());
tmpl.setStrVal3(bean.getStrVal3());
assertEquals(1, dao.mfind(tmpl).size());
assertEquals(1, dao.rangeFindStats().getNumOps());
assertEquals(bean, dao.get(bean.getRowKey()));
Thread.sleep(7500);
dao.rangeFindStats().reset();
assertEquals(0, dao.mfind(tmpl).size()); //index row should have expired as well
assertEquals(0, dao.rangeFindStats().getNumOps());
bean.setStrVal1(null);
assertEquals(bean, dao.get(bean.getRowKey()));
Thread.sleep(5000);
bean.setStrVal3(null);
assertEquals(bean, dao.get(bean.getRowKey()));
Thread.sleep(5000);
assertNull(dao.get(bean.getRowKey()));
}
@Test
public void testColumnTtl() throws InterruptedException
{
/*
* simple
*/
SampleBean bean = new SampleBean();
bean.setRowKey(10L);
bean.setTtlVal(2);
_dao.put(bean);
assertEquals(bean.getTtlVal(), _dao.get(bean.getRowKey()).getTtlVal());
Thread.sleep(3000);
assertNull(_dao.get(bean.getRowKey()));
/*
* embedded
*/
EmbeddedBean embedded = new EmbeddedBean();
embedded.setStrProp("foo");
embedded.setDoubleProp(1.0);
ParentBean parent = new ParentBean();
parent.setRowkey(10L);
parent.setEmbeddedProp(embedded);
parent.setListProp(Collections.singletonList(embedded));
_parentBeanDao.put(parent);
assertEquals(parent, _parentBeanDao.get(parent.getRowkey()));
Thread.sleep(3000);
ParentBean actual = _parentBeanDao.get(parent.getRowkey());
assertNull(actual.getListProp().get(0).getStrProp());
assertEquals(parent.getEmbeddedProp().getStrProp(), actual.getEmbeddedProp().getStrProp());
Thread.sleep(2000);
actual = _parentBeanDao.get(parent.getRowkey());
assertNull(actual.getEmbeddedProp());
/*
* List
*/
ListBean list = new ListBean();
list.setRowkey(10L);
list.setStrProp("Foo");
list.setListProp(Arrays.<Object>asList("foo1", "foo2"));
_listDao.put(list);
assertEquals(list, _listDao.get(list.getRowkey()));
Thread.sleep(3000);
assertNull(_listDao.get(list.getRowkey()).getListProp());
/*
* Map
*/
MapBean map = new MapBean();
map.setRowkey(10L);
map.setStrProp("Foo");
map.setMapProp(new HashMap<String, Object>());
map.getMapProp().put("key1", "val1");
_mapDao.put(map);
Thread.sleep(2500);
assertEquals(map, _mapDao.get(map.getRowkey()));
map.setMapProp(Collections.<String, Object>singletonMap("key2", "val2"));
_mapDao.put(map);
Thread.sleep(4000);
map.getMapProp().remove("key1");
assertEquals(map, _mapDao.get(map.getRowkey()));
}
@Test
public void testDelete()
{
int numBeans = 5;
List<SampleBean> beans = new ArrayList<SampleBean>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setSampleEnum(ESampleEnum.VALUE1);
bean.setUnmapped(new HashMap<String, Object>());
for(int j = 0; j <= i; j++)
bean.getUnmapped().put("unmapped-" + j, j);
beans.add(bean);
}
for(SampleBean bean : beans)
{
_dao.put(bean);
}
SampleBean bean0 = beans.get(0);
_dao.delete(bean0.getRowKey());
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = beans.get(i);
SliceQuery<Long,String,byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), AsciiSerializer.get(), BytesArraySerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("sample");
query.setRange("", "", false, 100);
ColumnSlice<String, byte[]> columnSlice = query.execute().get();
if(i == 0)
{
assertEquals(0, columnSlice.getColumns().size()); //"tombstone" row still exists
assertNull(_dao.get(bean0.getRowKey()));
}
else
assertBean("beans[" + bean.getIntVal() + "]", bean, columnSlice);
}
assertEquals(1, _dao.deleteStats().getNumCassandraOps());
assertEquals(1, _dao.deleteStats().getNumOps());
assertEquals(0, _dao.deleteStats().getNumCols());
assertEquals(1, _dao.deleteStats().getNumRows());
assertEquals(1, _dao.deleteStats().getRecentTimings().length);
_dao.mdelete(Arrays.asList(beans.get(1).getRowKey(), beans.get(2).getRowKey()));
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = beans.get(i);
SliceQuery<Long,String,byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), AsciiSerializer.get(), BytesArraySerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("sample");
query.setRange("", "", false, 100);
ColumnSlice<String, byte[]> columnSlice = query.execute().get();
if(i < 3)
{
assertEquals(0, columnSlice.getColumns().size()); //"tombstone" row still exists
assertNull(_dao.get(bean0.getRowKey()));
}
else
assertBean("beans[" + bean.getIntVal() + "]", bean, columnSlice);
}
assertEquals(3, _dao.deleteStats().getNumCassandraOps());
assertEquals(2, _dao.deleteStats().getNumOps());
assertEquals(0, _dao.deleteStats().getNumCols());
assertEquals(3, _dao.deleteStats().getNumRows());
assertEquals(2, _dao.deleteStats().getRecentTimings().length);
}
@Test
public void testCounterDelete()
{
int numBeans = 5;
List<CounterBean> beans = new ArrayList<CounterBean>();
List<ParentCounterBean> pbeans = new ArrayList<ParentCounterBean>();
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = new CounterBean();
bean.setRowKey(new Long(i));
bean.setCounterVal(new CounterColumn(i*10));
beans.add(bean);
ParentCounterBean pbean = new ParentCounterBean();
pbean.setRowkey(new Long(i));
pbean.setCounterProp(new CounterColumn(i*20));
pbeans.add(pbean);
_counterDao.put(bean);
_parentCounterDao.put(pbean);
}
CounterBean bean0 = beans.get(0);
ParentCounterBean pbean0 = pbeans.get(0);
_counterDao.delete(bean0.getRowKey());
_parentCounterDao.delete(pbean0.getRowkey());
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = beans.get(i);
SliceCounterQuery<Long,String> query = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), StringSerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("counter_cntr");
query.setRange("", "", false, 100);
CounterSlice<String> columnSlice = query.execute().get();
if(i == 0)
{
assertEquals(0, columnSlice.getColumns().size()); //"tombstone" row still exists
// assertNull(_dao.get(bean0.getRowKey()));
}
else
assertEquals("beans[" + bean.getRowKey() + "]", 1, columnSlice.getColumns().size());
ParentCounterBean pbean = pbeans.get(i);
SliceCounterQuery<Long, DynamicComposite> pquery = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), DynamicCompositeSerializer.get());
pquery.setKey(pbean.getRowkey());
pquery.setColumnFamily("parentcounterbean_cntr");
pquery.setRange(new DynamicComposite(""), new DynamicComposite("z"), false, 100);
CounterSlice<String> pslice = query.execute().get();
if(i == 0)
{
assertEquals(0, pslice.getColumns().size()); //"tombstone" row still exists
// assertNull(_dao.get(bean0.getRowKey()));
}
else
assertEquals("beans[" + bean.getRowKey() + "]", 1, pslice.getColumns().size());
}
_counterDao.mdelete(Arrays.asList(beans.get(1).getRowKey(), beans.get(2).getRowKey()));
_parentCounterDao.mdelete(Arrays.asList(pbeans.get(1).getRowkey(), pbeans.get(2).getRowkey()));
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = beans.get(i);
SliceCounterQuery<Long,String> query = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), StringSerializer.get());
query.setKey(bean.getRowKey());
query.setColumnFamily("counter_cntr");
query.setRange("", "", false, 100);
CounterSlice<String> columnSlice = query.execute().get();
if(i < 3)
{
assertEquals(0, columnSlice.getColumns().size()); //"tombstone" row still exists
// assertNull(_dao.get(bean0.getRowKey()));
}
else
assertEquals("beans[" + bean.getRowKey() + "]", 1, columnSlice.getColumns().size());
ParentCounterBean pbean = pbeans.get(i);
SliceCounterQuery<Long, DynamicComposite> pquery = HFactory.createCounterSliceQuery(keyspace, LongSerializer.get(), DynamicCompositeSerializer.get());
pquery.setKey(pbean.getRowkey());
pquery.setColumnFamily("parentcounterbean_cntr");
pquery.setRange(new DynamicComposite(""), new DynamicComposite("z"), false, 100);
CounterSlice<String> pslice = query.execute().get();
if(i < 3)
{
assertEquals(0, pslice.getColumns().size()); //"tombstone" row still exists
// assertNull(_dao.get(bean0.getRowKey()));
}
else
assertEquals("beans[" + bean.getRowKey() + "]", 1, pslice.getColumns().size());
}
}
private EmbeddedBean embeddedBean(int cnt, int mult)
{
EmbeddedBean rv = new EmbeddedBean();
rv.setDoubleProp(1.1*mult);
rv.setStrProp("estr-" + cnt);
rv.setListProp(new ArrayList<Integer>());
rv.setMapProp(new HashMap<String, Integer>());
rv.setUnmappedHandler(new HashMap<String, Object>());
for(int i = 0; i < cnt; i++)
{
rv.getListProp().add(i*mult);
rv.getMapProp().put("key-" + i, i*mult*2);
rv.getUnmappedHandler().put("unmapped-"+i, "unmapped-" + i*mult*3);
}
return rv;
}
@Test
public void testEmbeddedPut() throws Exception
{
ParentBean bean = new ParentBean();
bean.setRowkey(10L);
bean.setListProp(new ArrayList<EmbeddedBean>());
bean.getListProp().add(embeddedBean(1, 1)); //5 vals
bean.getListProp().add(embeddedBean(2, 2)); //8 vals
bean.setMapProp(new HashMap<String, EmbeddedBean>());
bean.getMapProp().put("mapProp1", embeddedBean(1, 3)); //5 vals
bean.getMapProp().put("mapProp2", embeddedBean(2, 4)); //8 vals
bean.setStrProp("strProp-val"); //1 val
bean.setEmbeddedProp(new EmbeddedBean()); //will be 5 vals
bean.getEmbeddedProp().setListProp(new ArrayList<Integer>());
bean.getEmbeddedProp().getListProp().add(100);
bean.getEmbeddedProp().getListProp().add(200);
bean.getEmbeddedProp().setMapProp(new HashMap<String, Integer>());
bean.getEmbeddedProp().getMapProp().put("mapProp1", 1000);
bean.getEmbeddedProp().getMapProp().put("mapProp2", 2000);
bean.getEmbeddedProp().setStrProp("estrProp-val");
_parentBeanDao.put(bean);
assertEmbeddedReset(bean);
DynamicCompositeSerializer dcs = new DynamicCompositeSerializer();
SliceQuery<Long, DynamicComposite, byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), dcs, BytesArraySerializer.get());
query.setKey(bean.getRowkey());
query.setColumnFamily("parentbean");
query.setRange(new DynamicComposite(), new DynamicComposite(), false, 100);
ColumnSlice<DynamicComposite, byte[]> slice = query.execute().get();
assertEquals(5 + 8 + 5 + 8 + 1 + 5, slice.getColumns().size());
assertColumn(bean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("s")));
assertEmbeddedColumn(bean.getEmbeddedProp(), slice, new DynamicComposite("e"));
for(int i = 0; i < bean.getListProp().size(); i++)
assertEmbeddedColumn(bean.getListProp().get(i), slice, new DynamicComposite("l", i));
for(Entry<String, EmbeddedBean> entry : bean.getMapProp().entrySet())
assertEmbeddedColumn(entry.getValue(), slice, new DynamicComposite("m", entry.getKey()));
}
private void assertEmbeddedReset(ParentBean... beans)
{
for(int i = 0; i < beans.length; i++)
{
ParentBean bean = beans[i];
List<EmbeddedBean> embedded = new ArrayList<EmbeddedBean>();
embedded.add(bean.getEmbeddedProp());
embedded.addAll(bean.getListProp());
embedded.addAll(bean.getMapProp().values());
for(EmbeddedBean e : embedded)
{
assertTrue(e.getStrProp() + " " + i, ((IEnhancedEntity) e).getModifiedFields().isEmpty());
assertFalse(e.getStrProp() + " " + i, ((IEnhancedEntity) e).getUnmappedFieldsModified());
}
}
}
private void assertEmbeddedColumn(EmbeddedBean bean,
ColumnSlice<DynamicComposite, byte[]> slice,
DynamicComposite prefix)
{
prefix.add("s");
assertColumn(bean.getStrProp(), false, slice.getColumnByName(prefix));
prefix.remove(prefix.size()-1);
if(bean.getDoubleProp() != 0)
{
prefix.add("d");
assertColumn(bean.getDoubleProp(), false, slice.getColumnByName(prefix));
prefix.remove(prefix.size()-1);
}
prefix.add("m");
for(Map.Entry entry : bean.getMapProp().entrySet())
{
prefix.add(entry.getKey());
assertColumn(entry.getValue(), false, slice.getColumnByName(prefix));
prefix.remove(prefix.size()-1);
}
prefix.remove(prefix.size()-1);
prefix.add("l");
for(int i = 0; i < bean.getListProp().size(); i++)
{
prefix.add(i);
assertColumn(bean.getListProp().get(i), false, slice.getColumnByName(prefix));
prefix.remove(prefix.size()-1);
}
prefix.remove(prefix.size()-1);
if(bean.getUnmappedHandler() != null)
{
for(Entry<String, Object> entry : bean.getUnmappedHandler().entrySet())
{
prefix.add(entry.getKey());
assertColumn(entry.getValue(), true, slice.getColumnByName(prefix));
prefix.remove(prefix.size()-1);
}
}
}
@Test
public void testCollectionPut() throws Exception
{
/*
* Map
*/
MapBean mapBean = new MapBean();
mapBean.setRowkey(10L);
mapBean.setMapProp(new HashMap<String, Object>());
mapBean.getMapProp().put("longMapProp", 100L);
mapBean.getMapProp().put("strMapProp", "strMapProp-val");
mapBean.setStrProp("strProp-val");
mapBean.setStrProp1("strProp1-val");
mapBean.setUnmapped((Map)Collections.singletonMap("unmapped-1", "val1"));
_mapDao.put(mapBean);
DynamicCompositeSerializer dcs = new DynamicCompositeSerializer();
SliceQuery<Long, DynamicComposite, byte[]> query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), dcs, BytesArraySerializer.get());
query.setKey(mapBean.getRowkey());
query.setColumnFamily("mapbean");
query.setRange(new DynamicComposite(), new DynamicComposite(), false, 100);
ColumnSlice<DynamicComposite, byte[]> slice = query.execute().get();
assertEquals(5, slice.getColumns().size());
assertColumn(mapBean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(mapBean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(mapBean.getMapProp().get("strMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "strMapProp")));
assertColumn(mapBean.getMapProp().get("longMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "longMapProp")));
//try serializing using unmapped handler with specified serializer
assertColumn(mapBean.getUnmapped().get("unmapped-1"), false, slice.getColumnByName(new DynamicComposite("unmapped-1")));
//null out a value and resave
mapBean.getMapProp().put("strMapProp", null);
mapBean.setUnmapped(Collections.<String, String>singletonMap("unmapped-1", null));
_mapDao.put(mapBean);
slice = query.execute().get();
assertEquals(3, slice.getColumns().size());
assertColumn(mapBean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(mapBean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(mapBean.getMapProp().get("longMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "longMapProp")));
/*
* SortedMap
*/
SortedMapBean sortedMapBean = new SortedMapBean();
sortedMapBean.setRowkey(10L);
sortedMapBean.setMapProp(new TreeMap<String, Object>());
sortedMapBean.getMapProp().put("longMapProp", 100L);
sortedMapBean.getMapProp().put("strMapProp", "strMapProp-val");
sortedMapBean.setStrProp("strProp-val");
sortedMapBean.setStrProp1("strProp1-val");
_sortedMapDao.put(sortedMapBean);
query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), dcs, BytesArraySerializer.get());
query.setKey(sortedMapBean.getRowkey());
query.setColumnFamily("sortedmapbean");
query.setRange(new DynamicComposite(), new DynamicComposite(), false, 100);
slice = query.execute().get();
assertEquals(4, slice.getColumns().size());
assertColumn(sortedMapBean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(sortedMapBean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(sortedMapBean.getMapProp().get("strMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "strMapProp")));
assertColumn(sortedMapBean.getMapProp().get("longMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "longMapProp")));
//null out a value and resave
sortedMapBean.getMapProp().put("strMapProp", null);
_sortedMapDao.put(sortedMapBean);
slice = query.execute().get();
assertEquals(3, slice.getColumns().size());
assertColumn(sortedMapBean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(sortedMapBean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(sortedMapBean.getMapProp().get("longMapProp"), true, slice.getColumnByName(new DynamicComposite("m", "longMapProp")));
/*
* List
*/
ListBean bean = new ListBean();
bean.setRowkey(10L);
bean.setListProp(new ArrayList<Object>());
bean.getListProp().add("strListProp-val0");
bean.getListProp().add(100L);
bean.getListProp().add("strListProp-val2");
bean.setStrProp("strProp-val");
bean.setStrProp1("strProp1-val");
_listDao.put(bean);
query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), dcs, BytesArraySerializer.get());
query.setKey(bean.getRowkey());
query.setColumnFamily("listbean");
query.setRange(new DynamicComposite(), new DynamicComposite(), false, 100);
slice = query.execute().get();
assertEquals(5, slice.getColumns().size());
assertColumn(bean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(bean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(bean.getListProp().get(0), true, slice.getColumnByName(new DynamicComposite("l", 0)));
assertColumn(bean.getListProp().get(1), true, slice.getColumnByName(new DynamicComposite("l", 1)));
assertColumn(bean.getListProp().get(2), true, slice.getColumnByName(new DynamicComposite("l", 2)));
//null out a value and resave
bean.getListProp().set(1, null);
_listDao.put(bean);
slice = query.execute().get();
assertEquals(4, slice.getColumns().size());
assertColumn(bean.getStrProp(), false, slice.getColumnByName(new DynamicComposite("strProp")));
assertColumn(bean.getStrProp1(), false, slice.getColumnByName(new DynamicComposite("strProp1")));
assertColumn(bean.getListProp().get(0), true, slice.getColumnByName(new DynamicComposite("l", 0)));
assertColumn(bean.getListProp().get(2), true, slice.getColumnByName(new DynamicComposite("l", 1)));
/*
* Nested
*/
NestedBean nbean = new NestedBean();
nbean.setRowkey(10L);
List<List<Double>> lol = new ArrayList<List<Double>>();
List<Map<String, String>> lom = new ArrayList<Map<String, String>>();
List<Map<Long, List<Double>>> lomol = new ArrayList<Map<Long,List<Double>>>();
Map<String, Map<Integer, Integer>> mom = new HashMap<String, Map<Integer,Integer>>();
Map<String, List<String>> mol = new HashMap<String, List<String>>();
Map<String, List<Map<String, Date>>> molom = new HashMap<String, List<Map<String,Date>>>();
int numCols = 0;
int numD1 = 5;
int numD2 = 7;
int numD3 = 3;
for(int i = 0; i < numD1; i++)
{
lol.add(new ArrayList<Double>());
lom.add(new HashMap<String, String>());
lomol.add(new HashMap<Long, List<Double>>());
mom.put("key-" + i, new HashMap<Integer, Integer>());
mol.put("key-" + i, new ArrayList<String>());
molom.put("key-" + i, new ArrayList<Map<String,Date>>());
for(int j = 0; j < numD2; j++)
{
lol.get(i).add(i*j*1.1);
numCols++;
lom.get(i).put("key-" + j, String.valueOf(i+j+1.1));
numCols++;
mom.get("key-" + i).put(j, i*j);
numCols++;
mol.get("key-" + i).add(i + "-" + j);
numCols++;
lomol.get(i).put(new Long(j), new ArrayList<Double>());
molom.get("key-" + i).add(new HashMap<String, Date>());
for(int k = 0; k < numD3; k++)
{
lomol.get(i).get(new Long(j)).add(i+j+k+.33);
numCols++;
molom.get("key-" + i).get(j).put(i + "-" + j + "-" + k, new Date(System.currentTimeMillis() - i*j*k));
numCols++;
}
}
}
nbean.setListOfListProp(lol);
nbean.setListOfMapProp(lom);
nbean.setListOfMapOfListProp(lomol);
nbean.setMapOfListProp(mol);
nbean.setMapOfMapProp(mom);
nbean.setMapOfListOfMapProp(molom);
_nestedBeanDao.put(nbean);
query = HFactory.createSliceQuery(keyspace, LongSerializer.get(), dcs, BytesArraySerializer.get());
query.setKey(nbean.getRowkey());
query.setColumnFamily("nestedbean");
query.setRange(new DynamicComposite(), new DynamicComposite(), false, 1000);
slice = query.execute().get();
assertEquals(numCols, slice.getColumns().size());
for(HColumn<DynamicComposite, byte[]> c : slice.getColumns())
{
if(c.getName().size() == 3 && c.getName().get(2) instanceof ByteBuffer)
{
c.getName().set(2, IntegerSerializer.get().fromByteBuffer((ByteBuffer) c.getName().get(2))); //dc uses bigint rather than int for some reason...
}
}
for(int i = 0; i < numD1; i++)
{
for(int j = 0; j < numD2; j++)
{
assertColumn(nbean.getListOfListProp().get(i).get(j), false, slice.getColumnByName(new DynamicComposite("listOfListProp", i, j)));
assertColumn(nbean.getListOfMapProp().get(i).get("key-" + j), false, slice.getColumnByName(new DynamicComposite("listOfMapProp", i, "key-" + j)));
assertColumn(nbean.getMapOfMapProp().get("key-" + i).get(j), false, slice.getColumnByName(new DynamicComposite("mapOfMapProp", "key-" + i, j)));
assertColumn(nbean.getMapOfListProp().get("key-" + i).get(j), false, slice.getColumnByName(new DynamicComposite("mapOfListProp", "key-" + i, j)));
for(int k = 0; k < numD3; k++)
{
assertColumn(nbean.getListOfMapOfListProp().get(i).get(new Long(j)).get(k), false, slice.getColumnByName(new DynamicComposite("listOfMapOfListProp", i, new Long(j), k)));
Date exp = nbean.getMapOfListOfMapProp().get("key-" + i).get(j).get(i + "-" + j + "-" + k);
HColumn<DynamicComposite, byte[]> act = slice.getColumnByName(new DynamicComposite("mapOfListOfMapProp", "key-" + i, j, i + "-" + j + "-" + k));
assertColumn(exp, false, act);
}
}
}
}
private EmbeddedCounterBean createEmbeddedCounterBean(long base)
{
EmbeddedCounterBean ebean = new EmbeddedCounterBean();
ebean.setCounterProp(new CounterColumn(base));
ebean.setStrProp("estr-"+ base);
return ebean;
}
private ParentCounterBean createParentCounterBean(long key)
{
ParentCounterBean bean = new ParentCounterBean();
long inc = key*10;
bean.setRowkey(key);
bean.setCounterProp(new CounterColumn(inc++));
bean.setStrProp("str-"+key);
bean.setEmbeddedProp(createEmbeddedCounterBean(inc++));
bean.setListProp(new ArrayList<EmbeddedCounterBean>());
bean.setMapProp(new HashMap<String, EmbeddedCounterBean>());
for(int i = 0; i <= key; i++)
bean.getListProp().add(createEmbeddedCounterBean(inc++));
for(int i = 0; i <= key; i++)
bean.getMapProp().put("mapkey-" + i, createEmbeddedCounterBean(inc++));
return bean;
}
private void convertParentCounterBean(ParentCounterBean bean)
{
bean.setCounterProp(toStoredForm(bean.getCounterProp()));
convertEmbeddedCounterBean(bean.getEmbeddedProp());
for(EmbeddedCounterBean e : bean.getListProp())
convertEmbeddedCounterBean(e);
for(EmbeddedCounterBean e : bean.getMapProp().values())
convertEmbeddedCounterBean(e);
}
private void convertEmbeddedCounterBean(EmbeddedCounterBean bean)
{
bean.setCounterProp(toStoredForm(bean.getCounterProp()));
}
private CounterColumn toStoredForm(CounterColumn cc)
{
return new CounterColumn(cc.getIncrement(), null);
}
@Test
public void testCounterGet()
{
int numBeans = 5;
List<CounterBean> beans = new ArrayList<CounterBean>();
List<ParentCounterBean> pbeans = new ArrayList<ParentCounterBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
CounterBean cbean = new CounterBean();
cbean.setRowKey((long) i);
cbean.setCounterVal(new CounterColumn(i*10));
beans.add(cbean);
CounterBean copy = new CounterBean();
copy.setRowKey(cbean.getRowKey());
copy.setCounterVal(new CounterColumn(i*10));
_counterDao.put(copy); //saving clears increment, use copy for comparisons
ParentCounterBean pbean = createParentCounterBean(i);
pbeans.add(pbean);
_parentCounterDao.put(createParentCounterBean(i));
keys.add((long) i);
}
List<CounterBean> actualBeans = new ArrayList<CounterBean>();
List<ParentCounterBean> actualPbeans = new ArrayList<ParentCounterBean>();
List<CounterBean> bulkActualBeans = new ArrayList<CounterBean>(_counterDao.mget(keys));
List<ParentCounterBean> bulkActualPbeans = new ArrayList<ParentCounterBean>(_parentCounterDao.mget(keys));
Collections.sort(bulkActualBeans);
Collections.sort(bulkActualPbeans);
for(int i = 0; i < numBeans; i++)
{
actualBeans.add(_counterDao.get(beans.get(i).getRowKey()));
actualPbeans.add(_parentCounterDao.get(pbeans.get(i).getRowkey()));
//convert counters to stored for easy comparison
beans.get(i).setCounterVal(toStoredForm(beans.get(i).getCounterVal()));
convertParentCounterBean(pbeans.get(i));
}
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = beans.get(i), actual = actualBeans.get(i), bulkActual = bulkActualBeans.get(i);
assertEquals(bean, actual);
assertEquals(bean, bulkActual);
ParentCounterBean pbean = pbeans.get(i), pactual = actualPbeans.get(i), bulkPactual = bulkActualPbeans.get(i);
assertEquals(pbean, pactual);
assertEquals(pbean, bulkPactual);
}
/*
* range
*/
actualBeans = new ArrayList<CounterBean>();
actualPbeans = new ArrayList<ParentCounterBean>();
for(int i = 0; i < numBeans; i++)
{
actualBeans.add(_counterDao.get(beans.get(i).getRowKey(), null, new GetOptions("b", "d")));
actualPbeans.add(_parentCounterDao.get(pbeans.get(i).getRowkey(), null, new GetOptions(new CollectionProperty("listProp", 1), new CollectionProperty("listProp", 3))));
}
bulkActualBeans = _counterDao.mget(keys, null, new GetOptions("b", "d"));
bulkActualPbeans = _parentCounterDao.mget(keys, null, new GetOptions(new CollectionProperty("listProp", 1), new CollectionProperty("listProp", 3)));
Collections.sort(bulkActualBeans);
int nullCnt = 0;
for(int i = bulkActualPbeans.size() - 1; i >= 0; i--)
{
if(bulkActualPbeans.get(i) == null)
{
bulkActualPbeans.remove(i);
nullCnt++;
}
}
assertEquals(1, nullCnt);
Collections.sort(bulkActualPbeans); //can't sort a list with null vals.
bulkActualPbeans.add(0, null); //add the null value back to preserve the comparison ordering below
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = beans.get(i), actual = actualBeans.get(i), bulkActual = bulkActualBeans.get(i);
assertEquals(bean, actual);
assertEquals(bean, bulkActual);
ParentCounterBean pbean = pbeans.get(i), pactual = actualPbeans.get(i), bulkPactual = bulkActualPbeans.get(i);
if(i == 0)
{
assertNull(pactual);
}
else
{
for(ParentCounterBean a : Arrays.asList(pactual, bulkPactual))
{
assertEquals(pbean.getRowkey(), a.getRowkey());
assertNull(a.getCounterProp());
assertNull(a.getEmbeddedProp());
assertNull(a.getMapProp());
assertNull(a.getStrProp());
if(i >= 1)
{
for(int j = 1; j <= Math.min(i, 3); j++)
assertEquals(pbean.getListProp().get(j), a.getListProp().get(j));
}
}
}
}
/*
* includes/excludes
*/
actualBeans = new ArrayList<CounterBean>();
actualPbeans = new ArrayList<ParentCounterBean>();
Set<Object> includes = new HashSet<Object>();
includes.add("counterProp");
includes.add("strProp");
includes.add(new CollectionProperty("embeddedProp", "s"));
includes.add("listProp");
for(int i = 0; i < numBeans; i++)
{
actualBeans.add(_counterDao.get(beans.get(i).getRowKey(), null, new GetOptions(Collections.singleton("counterVal"), null)));
actualPbeans.add(_parentCounterDao.get(pbeans.get(i).getRowkey(), null, new GetOptions(includes, null)));
}
bulkActualBeans = _counterDao.mget(keys, null, new GetOptions(Collections.singleton("counterVal"), null));
bulkActualPbeans = _parentCounterDao.mget(keys, null, new GetOptions(includes, null));
Collections.sort(bulkActualBeans);
Collections.sort(bulkActualPbeans);
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = beans.get(i), actual = actualBeans.get(i), bulkActual = bulkActualBeans.get(i);
assertEquals(bean, actual);
assertEquals(bean, bulkActual);
ParentCounterBean pbean = pbeans.get(i), pactual = actualPbeans.get(i), bulkPactual = bulkActualPbeans.get(i);
pbean.getEmbeddedProp().setCounterProp(null);
pbean.setMapProp(null);
assertEquals(pbean, pactual);
assertEquals(pbean, bulkPactual);
}
}
@Test
public void testSimpleGet()
{
int numBeans = 5;
List<SampleBean> beans = new ArrayList<SampleBean>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setSampleEnum(ESampleEnum.values()[i % ESampleEnum.values().length]);
bean.setUnmapped(new HashMap<String, Object>());
for(int j = 0; j <= 100; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);
beans.add(bean);
}
for(SampleBean bean : beans)
_dao.put(bean);
int expectedOps = 0;
assertEquals(expectedOps, _dao.getStats().getNumOps());
assertEquals(expectedOps, _dao.getStats().getNumCassandraOps());
for(SampleBean bean : beans)
{
SampleBean loaded = _dao.get(bean.getRowKey());
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
assertFalse(((IEnhancedEntity) loaded).getUnmappedFieldsModified());
assertEquals(bean, loaded);
assertNotNull(loaded.getUnmapped());
assertFalse(loaded.getUnmapped().isEmpty());
assertEquals(++expectedOps, _dao.getStats().getNumOps());
assertEquals(110*expectedOps, _dao.getStats().getNumCols());
assertEquals(2*expectedOps, _dao.getStats().getNumCassandraOps()); //large number of unmapped cols requires addl slice query per row
assertEquals(expectedOps, _dao.getStats().getRecentTimings().length);
}
SampleBean bean0 = beans.get(0);
//test null update
bean0.setStrVal(null);
bean0.setLongVal(2000);
_dao.put(bean0);
assertEquals(bean0, _dao.get(bean0.getRowKey()));
//test partial
SampleBean partial = new SampleBean();
partial.setRowKey(1000L);
partial.setStrVal("hello");
_dao.put(partial);
assertEquals(partial, _dao.get(partial.getRowKey()));
//test non-existent
assertNull(_dao.get(-5L));
}
@Test
public void testSimpleMget()
{
try
{
_dao.mget(Arrays.asList(-1L, -1L));
fail("duplicate keys not allowed");
}
catch(IllegalArgumentException ex)
{
//success
}
int numBeans = 500;
List<SampleBean> beans = new ArrayList<SampleBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setSampleEnum(ESampleEnum.values()[i % ESampleEnum.values().length]);
beans.add(bean);
keys.add(beans.get(i).getRowKey());
bean.setUnmapped(new TreeMap<String, Object>());
for(int j = 0; j <= 100; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);
}
_dao.mput(beans);
List<Long> keyList = new ArrayList<Long>(keys);
keyList.add(-5L); //non-existent
List<SampleBean> actual = new ArrayList<SampleBean>( _dao.mget(keyList) );
Collections.sort(actual);
assertEquals(beans.size(), actual.size());
for(int i = beans.size() - 1; i >= 0; i--)
{
SampleBean loaded = actual.get(i);
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
if(loaded.getUnmapped() != null)
loaded.setUnmapped(new TreeMap<String, Object>(loaded.getUnmapped()));
assertEquals("bean[" + i + "]", beans.get(i), loaded);
}
assertEquals(1, _dao.getStats().getNumOps());
assertEquals(505, _dao.getStats().getNumCassandraOps());
assertEquals(numBeans*110, _dao.getStats().getNumCols());
assertEquals(numBeans+1, _dao.getStats().getNumRows());
assertEquals(1, _dao.getStats().getRecentTimings().length);
}
@Test
public void testSimpleMgetAll()
{
int numBeans = 201;
List<SampleBean> beans = new ArrayList<SampleBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setSampleEnum(ESampleEnum.values()[i % ESampleEnum.values().length]);
beans.add(bean);
keys.add(beans.get(i).getRowKey());
bean.setUnmapped(new TreeMap<String, Object>());
for(int j = 0; j <= 100; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);
}
_dao.mput(beans);
List<SampleBean> actual = new ArrayList<SampleBean>( _dao.mgetAll() );
Collections.sort(actual);
assertEquals(beans.size(), actual.size());
for(int i = beans.size() - 1; i >= 0; i--)
{
SampleBean loaded = actual.get(i);
assertEquals("bean[" + i + "]", beans.get(i), loaded);
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
}
GetAllOptions options = new GetAllOptions();
options.setMaxRows(150);
actual = new ArrayList<SampleBean>(_dao.mgetAll(options));
assertEquals(150, actual.size());
Set<Long> actualKeys = new HashSet<Long>();
for(SampleBean loaded : actual)
{
assertTrue(actualKeys.add(loaded.getRowKey()));
assertEquals(beans.get(loaded.getRowKey().intValue()), loaded);
}
//delete half the beans to create empty rows, make sure code still works
for(int i = beans.size() - 1; i >= 0; i=i-2)
_dao.delete(beans.remove(i).getRowKey());
actual = new ArrayList<SampleBean>( _dao.mgetAll() );
Collections.sort(actual);
assertEquals(beans.size(), actual.size());
for(int i = beans.size() - 1; i >= 0; i--)
{
SampleBean loaded = actual.get(i);
assertEquals("bean[" + i + "]", beans.get(i), loaded);
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
}
}
@Test
public void testCounterMgetAll()
{
int numBeans = 201;
List<CounterBean> beans = new ArrayList<CounterBean>();
List<ParentCounterBean> pbeans = new ArrayList<ParentCounterBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
CounterBean bean = new CounterBean();
bean.setRowKey(new Long(i));
bean.setCounterVal(new CounterColumn(i));
beans.add(bean);
keys.add(beans.get(i).getRowKey());
ParentCounterBean pbean = new ParentCounterBean();
pbean.setRowkey(new Long(i));
//mod result == 0 -> counter cols
// == 1 -> normal cols
// == 2 -> counter and normal cols
if(i%3 != 0)
{
pbean.setStrProp("str-"+i);
pbean.setEmbeddedProp(new EmbeddedCounterBean());
pbean.getEmbeddedProp().setStrProp("estr-"+i);
}
if(i%3 != 1)
{
pbean.setCounterProp(new CounterColumn(i));
pbean.setEmbeddedProp(new EmbeddedCounterBean());
pbean.getEmbeddedProp().setCounterProp(new CounterColumn(i*10));
}
pbeans.add(pbean);
}
_counterDao.mput(beans);
_parentCounterDao.mput(pbeans);
List<CounterBean> actuals = new ArrayList<CounterBean>( _counterDao.mgetAll() );
Collections.sort(actuals);
assertEquals(beans.size(), actuals.size());
for(int i = beans.size() - 1; i >= 0; i--)
{
CounterBean actual = actuals.get(i);
assertTrue(((IEnhancedEntity) actual).getModifiedFields().isEmpty());
assertEquals("bean[" + i + "]", beans.get(i).getRowKey(), actual.getRowKey());
assertEquals("bean[" + i + "]", i, actual.getCounterVal().getStored());
}
/*
* only normal cols
*/
GetAllOptions options = new GetAllOptions(Collections.singleton("strProp"), null);
List<ParentCounterBean> pactuals = new ArrayList<ParentCounterBean>( _parentCounterDao.mgetAll(options) );
Collections.sort(pactuals);
List<ParentCounterBean> pbeans2 = new ArrayList<ParentCounterBean>();
for(int i = 0; i < pbeans.size(); i++)
{
if(i%3 != 0)
pbeans2.add(pbeans.get(i));
}
assertEquals(pbeans2.size(), pactuals.size());
for(int i = 0; i < pbeans2.size(); i++)
{
ParentCounterBean pactual = pactuals.get(i);
assertTrue(((IEnhancedEntity) pactual).getModifiedFields().isEmpty());
assertEquals("bean[" + i + "]", pbeans2.get(i).getRowkey(), pactual.getRowkey());
assertEquals("bean[" + i + "]", pbeans2.get(i).getStrProp(), pactual.getStrProp());
}
/*
* only counter cols
*/
options = new GetAllOptions(Collections.singleton("counterProp"), null);
options.setGetCounterColumns();
pactuals = new ArrayList<ParentCounterBean>( _parentCounterDao.mgetAll(options) );
Collections.sort(pactuals);
pbeans2 = new ArrayList<ParentCounterBean>();
for(int i = 0; i < pbeans.size(); i++)
{
if(i%3 != 1)
pbeans2.add(pbeans.get(i));
}
assertEquals(pbeans2.size(), pactuals.size());
for(int i = 0; i < pbeans2.size(); i++)
{
ParentCounterBean pactual = pactuals.get(i);
assertTrue(((IEnhancedEntity) pactual).getModifiedFields().isEmpty());
assertEquals("bean[" + i + "]", pbeans2.get(i).getRowkey(), pactual.getRowkey());
assertEquals("bean[" + i + "]", pbeans2.get(i).getRowkey(), pactual.getCounterProp().getStored());
}
}
@Test
public void testEmbeddedGet() throws Exception
{
int numBeans = 5;
List<ParentBean> beans = new ArrayList<ParentBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
ParentBean bean = new ParentBean();
bean.setRowkey(new Long(i));
keys.add(bean.getRowkey());
beans.add(bean);
bean.setListProp(new ArrayList<EmbeddedBean>());
bean.getListProp().add(embeddedBean(1, i+1));
bean.getListProp().add(embeddedBean(2, i+2));
bean.getListProp().add(embeddedBean(3, i+3));
bean.setMapProp(new HashMap<String, EmbeddedBean>());
bean.getMapProp().put("mapProp1", embeddedBean(1, i+3)); //3 vals
bean.getMapProp().put("mapProp2", embeddedBean(2, i+4));
bean.setStrProp("strProp-"+i); //1 val
bean.setEmbeddedProp(new EmbeddedBean()); //will be 5 vals
bean.getEmbeddedProp().setListProp(new ArrayList<Integer>());
bean.getEmbeddedProp().getListProp().add(i+100);
bean.getEmbeddedProp().getListProp().add(i+200);
bean.getEmbeddedProp().setMapProp(new HashMap<String, Integer>());
bean.getEmbeddedProp().getMapProp().put("mapProp1", i+1000);
bean.getEmbeddedProp().getMapProp().put("mapProp2", i+2000);
bean.getEmbeddedProp().setStrProp("estrProp-"+i);
}
_parentBeanDao.mput(beans);
for(int i = 0; i < numBeans; i++)
{
ParentBean expected = beans.get(i);
ParentBean actual = _parentBeanDao.get(expected.getRowkey());
assertEquals(expected.getStrProp(), actual.getStrProp());
assertEquals(expected.getEmbeddedProp(), actual.getEmbeddedProp());
assertEquals(expected.getListProp(), actual.getListProp());
assertEquals(expected.getMapProp(), actual.getMapProp());
assertEquals(expected, actual);
assertEmbeddedReset(actual);
}
List<ParentBean> bulkActuals = new ArrayList<ParentBean>(_parentBeanDao.mget(keys));
Collections.sort(bulkActuals);
assertEquals(beans, bulkActuals);
assertEmbeddedReset(bulkActuals.toArray(new ParentBean[0]));
/*
* test partials
*/
for(long i = 0; i < numBeans; i++)
{
Set<Object> includes = new HashSet<Object>();
includes.add("embeddedProp");
GetOptions options = new GetOptions(includes, null);
ParentBean bean = beans.get((int) i);
ParentBean expected = new ParentBean();
expected.setRowkey(bean.getRowkey());
expected.setEmbeddedProp(bean.getEmbeddedProp());
ParentBean actualBean = _parentBeanDao.get(i, null, options);
assertEquals("bean-" + i, expected, actualBean);
expected.setListProp(Arrays.asList(new EmbeddedBean[] {null, bean.getListProp().get(1)}));
includes.add(new CollectionProperty("listProp", 1));
actualBean = _parentBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setMapProp(bean.getMapProp());
includes.add("mapProp");
actualBean = _parentBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
includes.clear();
includes.add(new CollectionProperty("embeddedProp", "s"));
expected = new ParentBean();
expected.setRowkey(bean.getRowkey());
expected.setEmbeddedProp(new EmbeddedBean());
expected.getEmbeddedProp().setStrProp(bean.getEmbeddedProp().getStrProp());
actualBean = _parentBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
}
/*
* test partial ranges
*/
for(long i = 0; i < numBeans; i++)
{
//note double prop is not set
GetOptions options = new GetOptions(new CollectionProperty("embeddedProp", "a"), new CollectionProperty("embeddedProp", "n"));
ParentBean bean = beans.get((int) i);
ParentBean expected = new ParentBean();
expected.setRowkey(bean.getRowkey());
expected.setEmbeddedProp(new EmbeddedBean());
expected.getEmbeddedProp().setListProp(bean.getEmbeddedProp().getListProp());
expected.getEmbeddedProp().setMapProp(bean.getEmbeddedProp().getMapProp());
ParentBean actualBean = _parentBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
}
}
@Test
public void testMapGet()
{
int numBeans = 5;
List<MapBean> beans = new ArrayList<MapBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
MapBean bean = new MapBean();
bean.setRowkey(new Long(i));
bean.setStrProp("str-" + i);
keys.add(bean.getRowkey());
bean.setUnmapped(new HashMap<String, String>());
for(int j = 0; j <= 150; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);
bean.setMapProp(new HashMap<String, Object>());
for(int j = 50; j <= 200; j++)
bean.getMapProp().put("propval-" + j, "val-" + i + "-" + j);
beans.add(bean);
}
_mapDao.mput(beans);
int expectedOps = 0;
for(MapBean bean : beans)
{
MapBean loaded = _mapDao.get(bean.getRowkey());
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
assertFalse(((IEnhancedEntity) loaded).getUnmappedFieldsModified());
assertEquals(bean, loaded);
assertNotNull(loaded.getUnmapped());
assertFalse(loaded.getUnmapped().isEmpty());
assertEquals(++expectedOps, _mapDao.getStats().getNumOps());
assertEquals(303*expectedOps, _mapDao.getStats().getNumCols());
assertEquals(4*expectedOps, _mapDao.getStats().getNumCassandraOps());
assertEquals(expectedOps, _mapDao.getStats().getRecentTimings().length);
}
/*
* bulk load
*/
//get all
List<MapBean> loaded = new ArrayList<MapBean>( _mapDao.mgetAll());
Collections.sort(loaded);
for(MapBean bean : beans)
{
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
}
assertBeansEqual(beans, loaded);
//get multiple
loaded = new ArrayList<MapBean>( _mapDao.mget(keys));
Collections.sort(loaded);
for(MapBean bean : beans)
{
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
}
assertBeansEqual(beans, loaded);
MapBean bean0 = beans.get(0);
//test null update
for(int i = 50; i < 75; i++)
bean0.getMapProp().put("propval-" + i, null);
assertEquals(151, bean0.getMapProp().size()); //sanity check we are overwriting properties to null
_mapDao.put(bean0);
Iterator<Entry<String, Object>> iter = bean0.getMapProp().entrySet().iterator();
while(iter.hasNext())
{
if(iter.next().getValue() == null)
iter.remove();
}
assertEquals(bean0, _mapDao.get(bean0.getRowkey()));
}
@Test
public void testSortedMapGet()
{
int numBeans = 5;
List<SortedMapBean> beans = new ArrayList<SortedMapBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
SortedMapBean bean = new SortedMapBean();
bean.setRowkey(new Long(i));
bean.setStrProp("str-" + i);
keys.add(bean.getRowkey());
bean.setMapProp(new TreeMap<String, Object>());
for(int j = 50; j <= 100; j++)
bean.getMapProp().put("propval-" + j, "val-" + i + "-" + j);
beans.add(bean);
}
_sortedMapDao.mput(beans);
for(SortedMapBean bean : beans)
{
SortedMapBean loaded = _sortedMapDao.get(bean.getRowkey());
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
assertEquals(bean, loaded);
}
//bulk load
List<SortedMapBean> loaded = new ArrayList<SortedMapBean>( _sortedMapDao.mget(keys));
Collections.sort(loaded);
for(SortedMapBean bean : beans)
{
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
}
assertBeansEqual(beans, loaded);
SortedMapBean bean0 = beans.get(0);
//test null update
for(int i = 50; i < 75; i++)
bean0.getMapProp().put("propval-" + i, null);
assertEquals(51, bean0.getMapProp().size()); //sanity check we are overwriting properties to null
_sortedMapDao.put(bean0);
Iterator<Entry<String, Object>> iter = bean0.getMapProp().entrySet().iterator();
while(iter.hasNext())
{
if(iter.next().getValue() == null)
iter.remove();
}
assertEquals(bean0, _sortedMapDao.get(bean0.getRowkey()));
}
@Test
public void testListGet()
{
int numBeans = 5;
List<ListBean> beans = new ArrayList<ListBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
ListBean bean = new ListBean();
bean.setRowkey(new Long(i));
bean.setStrProp("str-" + i);
keys.add(bean.getRowkey());
bean.setListProp(new ArrayList<Object>());
for(int j = 0; j <= 100; j++)
bean.getListProp().add("val-" + i + "-" + j);
beans.add(bean);
}
_listDao.mput(beans);
int expectedOps = 0;
for(ListBean bean : beans)
{
ListBean loaded = _listDao.get(bean.getRowkey());
assertTrue(((IEnhancedEntity) loaded).getModifiedFields().isEmpty());
assertEquals(bean, loaded);
assertEquals(++expectedOps, _listDao.getStats().getNumOps());
assertEquals(102*expectedOps, _listDao.getStats().getNumCols());
assertEquals(2*expectedOps, _listDao.getStats().getNumCassandraOps()); //large number of unmapped cols requires addl slice query per row
assertEquals(expectedOps, _listDao.getStats().getRecentTimings().length);
}
/*
* bulk load
*/
//load all
List<ListBean> loaded = new ArrayList<ListBean>( _listDao.mgetAll());
Collections.sort(loaded);
for(ListBean bean : beans)
{
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
}
assertBeansEqual(beans, loaded);
//load multiple
loaded = new ArrayList<ListBean>( _listDao.mget(keys));
Collections.sort(loaded);
for(ListBean bean : beans)
{
assertTrue(((IEnhancedEntity) bean).getModifiedFields().isEmpty());
}
assertBeansEqual(beans, loaded);
ListBean bean0 = beans.get(0);
//test null update
for(int i = 0; i < 50; i++)
bean0.getListProp().set(i, null);
_listDao.put(bean0);
Iterator<Object> iter = bean0.getListProp().iterator();
while(iter.hasNext())
{
if(iter.next() == null)
iter.remove();
}
assertEquals(bean0, _listDao.get(bean0.getRowkey()));
}
@Test
public void testNestedGet() throws Exception
{
List<NestedBean> beans = new ArrayList<NestedBean>();
List<Long> keys = new ArrayList<Long>();
int numBeans = 10;
int numD1 = 5;
int numD2 = 7;
int numD3 = 3;
for(long n = 0; n < numBeans; n++)
{
NestedBean bean = new NestedBean();
bean.setRowkey(n);
keys.add(bean.getRowkey());
List<List<Double>> lol = new ArrayList<List<Double>>();
List<Map<String, String>> lom = new ArrayList<Map<String, String>>();
List<Map<Long, List<Double>>> lomol = new ArrayList<Map<Long,List<Double>>>();
Map<String, Map<Integer, Integer>> mom = new HashMap<String, Map<Integer,Integer>>();
Map<String, List<String>> mol = new HashMap<String, List<String>>();
Map<String, List<Map<String, Date>>> molom = new HashMap<String, List<Map<String,Date>>>();
for(int i = 0; i < numD1; i++)
{
lol.add(new ArrayList<Double>());
lom.add(new HashMap<String, String>());
lomol.add(new HashMap<Long, List<Double>>());
mom.put("key-" + i, new HashMap<Integer, Integer>());
mol.put("key-" + i, new ArrayList<String>());
molom.put("key-" + i, new ArrayList<Map<String,Date>>());
for(int j = 0; j < numD2; j++)
{
lol.get(i).add(i*j*1.1);
lom.get(i).put("key-" + j, String.valueOf(i+j+1.1));
mom.get("key-" + i).put(j, i*j);
mol.get("key-" + i).add(i + "-" + j);
lomol.get(i).put(new Long(j), new ArrayList<Double>());
molom.get("key-" + i).add(new HashMap<String, Date>());
for(int k = 0; k < numD3; k++)
{
lomol.get(i).get(new Long(j)).add(i+j+k+.33);
molom.get("key-" + i).get(j).put(i + "-" + j + "-" + k, new Date(System.currentTimeMillis() - i*j*k));
}
}
}
bean.setListOfListProp(lol);
bean.setListOfMapProp(lom);
bean.setListOfMapOfListProp(lomol);
bean.setMapOfListProp(mol);
bean.setMapOfMapProp(mom);
bean.setMapOfListOfMapProp(molom);
beans.add(bean);
}
_nestedBeanDao.mput(beans);
assertEquals(1, _nestedBeanDao.putStats().getNumOps());
assertEquals((35+35+35+35+35*3+35*3)*numBeans, _nestedBeanDao.putStats().getNumCols());
assertEquals((35+35+35+35+35*3+35*3)*numBeans, _nestedBeanDao.putStats().getNumCassandraOps());
assertEquals(numBeans, _nestedBeanDao.putStats().getNumRows());
assertEquals(1, _nestedBeanDao.putStats().getRecentTimings().length);
int expectedOps = 0;
for(int i = 0; i < numBeans; i++)
{
NestedBean actual = _nestedBeanDao.get((long) i);
NestedBean expected = beans.get(i);
assertEquals("key " + expected.getRowkey(), expected.getListOfListProp(), actual.getListOfListProp());
assertEquals("key " + expected.getRowkey(), expected.getListOfMapProp(), actual.getListOfMapProp());
assertEquals("key " + expected.getRowkey(), expected.getListOfMapOfListProp(), actual.getListOfMapOfListProp());
assertEquals("key " + expected.getRowkey(), expected.getMapOfListProp(), actual.getMapOfListProp());
assertEquals("key " + expected.getRowkey(), expected.getMapOfMapProp(), actual.getMapOfMapProp());
assertEquals("key " + expected.getRowkey(), expected.getMapOfListOfMapProp(), actual.getMapOfListOfMapProp());
//this is actually sufficient, previous are to aid debugging inequalities
assertEquals("key " + expected.getRowkey(), expected, actual);
assertEquals(++expectedOps, _nestedBeanDao.getStats().getNumOps());
assertEquals((35+35+35+35+35*3+35*3)*expectedOps, _nestedBeanDao.getStats().getNumCols());
assertEquals(4*expectedOps, _nestedBeanDao.getStats().getNumCassandraOps()); //large number of unmapped cols requires addl slice query per row
assertEquals(expectedOps, _nestedBeanDao.getStats().getRecentTimings().length);
}
List<NestedBean> actual = new ArrayList<NestedBean>(_nestedBeanDao.mget(keys));
Collections.sort(actual);
assertEquals(beans, actual);
/*
* test partials
*/
for(long i = 0; i < numBeans; i++)
{
Set<String> includes = new HashSet<String>();
includes.add("listOfListProp");
GetOptions options = new GetOptions(includes, null);
NestedBean bean = beans.get((int) i);
NestedBean expected = new NestedBean();
expected.setRowkey(bean.getRowkey());
expected.setListOfListProp(bean.getListOfListProp());
NestedBean actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setListOfMapProp(bean.getListOfMapProp());
includes.add("listOfMapProp");
actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setListOfMapOfListProp(bean.getListOfMapOfListProp());
includes.add("listOfMapOfListProp");
actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setMapOfMapProp(bean.getMapOfMapProp());
includes.add("mapOfMapProp");
actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setMapOfListProp(bean.getMapOfListProp());
includes.add("mapOfListProp");
actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
expected.setMapOfListOfMapProp(bean.getMapOfListOfMapProp());
includes.add("mapOfListOfMapProp");
actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
}
/*
* test partial ranges
*/
for(long i = 0; i < numBeans; i++)
{
GetOptions options = new GetOptions(new CollectionProperty("listOfMapOfListProp", 2), new CollectionProperty("listOfMapOfListProp", 4));
NestedBean bean = beans.get((int) i);
NestedBean expected = new NestedBean();
expected.setRowkey(bean.getRowkey());
List<Map<Long,List<Double>>> subList = new ArrayList<Map<Long,List<Double>>>(bean.getListOfMapOfListProp().subList(2, 5));
subList.add(0, null);
subList.add(0, null);
expected.setListOfMapOfListProp(subList);
NestedBean actualBean = _nestedBeanDao.get(i, null, options);
assertEquals(expected, actualBean);
options = new GetOptions(new CollectionProperty("mapOfListOfMapProp", "key-2"), new CollectionProperty("mapOfListOfMapProp", "key-4"));
expected.setMapOfListOfMapProp(new HashMap<String, List<Map<String,Date>>>());
expected.getMapOfListOfMapProp().put("key-2", bean.getMapOfListOfMapProp().get("key-2"));
expected.getMapOfListOfMapProp().put("key-3", bean.getMapOfListOfMapProp().get("key-3"));
expected.getMapOfListOfMapProp().put("key-4", bean.getMapOfListOfMapProp().get("key-4"));
_nestedBeanDao.get(i, actualBean, options);
assertEquals(expected, actualBean);
}
}
@Test
public void testGetPartial() throws Exception
{
int numBeans = 501;
List<SampleBean> beans = new ArrayList<SampleBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setUnmapped(new HashMap<String, Object>());
for(int j = 0; j <= 20; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);//place them between fixed properties
beans.add(bean);
keys.add(bean.getRowKey());
}
_dao.mput(beans);
keys.add(-52345L);//non existent
keys.add(2, -7234324324L);//non existent
List<SampleBean> bulkActuals = _dao.mget(keys, null, new GetOptions(null, Collections.singleton("boolVal")));
List<SampleBean> bulkAllActuals = new ArrayList<SampleBean>(_dao.mgetAll(new GetAllOptions(null, Collections.singleton("boolVal"))));
assertEquals(keys.size(), bulkActuals.size());
assertNull(bulkActuals.remove(bulkActuals.size()-1));
assertNull(bulkActuals.remove(2));
keys.remove(keys.size()-1);
keys.remove(2);
Collections.sort(bulkActuals);
Collections.sort(bulkAllActuals);
for(int i = 0; i < numBeans; i++)
{
SampleBean saved = beans.get(i);
SampleBean expected = (SampleBean) saved.clone();
expected.setBoolVal(false); //false is default value for boolean
expected.setUnmapped(null); //can't efficiently do exclusions and include unmapped columns right now as c* ranges are inclusive
SampleBean actual = _dao.get(saved.getRowKey(), null, new GetOptions(null, Collections.singleton("boolVal")));
assertEquals(expected, actual);
assertEquals(expected, bulkActuals.get(i));
assertEquals(expected, bulkAllActuals.get(i));
}
Set<String> props = new HashSet<String>();
props.add("charVal");
for(int j = 20; j >= 11; j--)
props.add("unmapped-" + j);
bulkActuals = _dao.mget(keys, null, new GetOptions(props, null));
bulkAllActuals = new ArrayList<SampleBean>(_dao.mgetAll(new GetAllOptions(props, null)));
Collections.sort(bulkActuals);
Collections.sort(bulkAllActuals);
assertEquals(numBeans, bulkActuals.size());
assertEquals(numBeans, bulkAllActuals.size());
List<SampleBean> expecteds = new ArrayList<SampleBean>();
List<SampleBean> actuals = new ArrayList<SampleBean>();
for(int i = 0; i < numBeans; i++)
{
SampleBean saved = beans.get(i);
SampleBean expected = new SampleBean();
expected.setRowKey(saved.getRowKey());
expected.setCharVal(saved.getCharVal());
TreeMap<String, Object> unmapped = new TreeMap<String, Object>(saved.getUnmapped());
for(int j = 10; j >= 0; j--)
unmapped.remove("unmapped-" + j);
expected.setUnmapped(unmapped);
SampleBean actual = _dao.get(saved.getRowKey(), null, new GetOptions(props, null));
assertEquals(expected, actual);
assertEquals(expected, bulkActuals.get(i));
assertEquals(expected, bulkAllActuals.get(i));
expecteds.add(expected);
actuals.add(expected);
}
_dao.mget(keys, bulkActuals, new GetOptions(Collections.singleton("intVal"), null));
for(int i = 0; i < numBeans; i++)
{
SampleBean saved = beans.get(i);
SampleBean actual = actuals.get(i);
SampleBean expected = expecteds.get(i);
expected.setIntVal(saved.getIntVal());
_dao.get(saved.getRowKey(), actual, new GetOptions(Collections.singleton("intVal"), null)); //update the bean
assertEquals(expected, actual);
assertEquals(expected, bulkActuals.get(i));
}
}
@Test
public void testGetPartialRange() throws Exception
{
int numBeans = 5;
List<SampleBean> beans = new ArrayList<SampleBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
SampleBean bean = new SampleBean();
bean.setRowKey(new Long(i));
bean.setBoolVal(i%2 == 0);
bean.setCharVal((char) ('a' + i));
bean.setDateVal(new Date(System.currentTimeMillis() + 60000*i));
bean.setDoubleVal(i * .1);
bean.setFloatVal(i / .5f);
bean.setIntVal(i);
bean.setLongVal(-i);
bean.setStrVal("str-" + i);
bean.setUnmapped(new HashMap<String, Object>());
for(int j = 0; j <= 20; j++)
bean.getUnmapped().put("unmapped-" + j, "val-" + i + "-" + j);
beans.add(bean);
keys.add(bean.getRowKey());
}
_dao.mput(beans);
List<SampleBean> bulkAllActuals = new ArrayList<SampleBean>(_dao.mgetAll(new GetAllOptions("c", "cv")));
List<SampleBean> bulkActuals = _dao.mget(keys, null, new GetOptions("c", "cv"));
List<SampleBean> actuals = new ArrayList<SampleBean>();
List<SampleBean> expecteds = new ArrayList<SampleBean>();
Collections.sort(bulkAllActuals);
Collections.sort(bulkActuals);
for(int i = 0; i < beans.size(); i++)
{
SampleBean saved = beans.get(i);
SampleBean expected = new SampleBean();
expected.setRowKey(saved.getRowKey());
expected.setCharVal(saved.getCharVal());
expected.setUnmapped(null); //when using exclude, unmapped properties are ignored
actuals.add(_dao.get(saved.getRowKey(), null, new GetOptions("c", "cv")));
assertEquals(expected, actuals.get(i));
assertEquals(expected, bulkActuals.get(i));
assertEquals(expected, bulkAllActuals.get(i));
expecteds.add(expected);
}
bulkActuals = _dao.mget(keys, bulkActuals, new GetOptions("d", "daa"));
for(int i = 0; i < beans.size(); i++)
{
SampleBean saved = beans.get(i);
SampleBean expected = expecteds.get(i);
actuals.set(i, _dao.get(saved.getRowKey(), actuals.get(i), new GetOptions("d", "daa")));//includes double's physical name
expected.setDoubleVal(saved.getDoubleVal());
assertEquals(expected, actuals.get(i));
assertEquals(expected, bulkActuals.get(i));
}
bulkActuals = _dao.mget(keys, bulkActuals, new GetOptions("unmapped-10", "unmapped-19"));
for(int i = 0; i < beans.size(); i++)
{
SampleBean saved = beans.get(i);
SampleBean expected = expecteds.get(i);
expected.setUnmapped(new HashMap<String, Object>());
for(int j = 10; j < 20; j++)
expected.getUnmapped().put("unmapped-" + j, saved.getUnmapped().get("unmapped-" + j));
actuals.set(i, _dao.get(saved.getRowKey(), actuals.get(i), new GetOptions("unmapped-10", "unmapped-19")));
assertEquals(expected, actuals.get(i));
assertEquals(expected, bulkActuals.get(i));
}
}
@Test
public void testGetPartialCollectionRange() throws Exception
{
int numBeans = 5;
List<MapBean> mapBeans = new ArrayList<MapBean>();
List<ListBean> listBeans = new ArrayList<ListBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
ListBean lbean = new ListBean();
lbean.setRowkey(new Long(i));
lbean.setStrProp("str-" + i);
lbean.setStrProp1("str1-" + i);
lbean.setListProp(new ArrayList<Object>());
for(int j = 0; j <= 200; j++)
lbean.getListProp().add(i*1000 + j);
MapBean mbean = new MapBean();
mbean.setRowkey(new Long(i));
mbean.setStrProp("str-" + i);
mbean.setStrProp1("str1-" + i);
mbean.setMapProp(new HashMap<String, Object>());
for(int j = 0; j <= 200; j++)
mbean.getMapProp().put("key-" + j + "-" + i, i*1000 + j);
mapBeans.add(mbean);
listBeans.add(lbean);
keys.add(lbean.getRowkey());
}
_listDao.mput(listBeans);
_mapDao.mput(mapBeans);
/*
* lists
*/
//do the same test using bulk API
List<ListBean> bulkListActuals = _listDao.mget(keys, null, new GetOptions("strProp1", "strProp1"));
assertEquals(numBeans, bulkListActuals.size());
Collections.sort(bulkListActuals);
List<ListBean> singleListActuals = new ArrayList<ListBean>();
for(int i = 0; i < listBeans.size(); i++)
{
ListBean saved = listBeans.get(i);
ListBean expected = new ListBean();
expected.setRowkey(saved.getRowkey());
expected.setStrProp1(saved.getStrProp1());
singleListActuals.add(_listDao.get(saved.getRowkey(), null, new GetOptions("strProp1", "strProp1")));
assertEquals(expected, singleListActuals.get(i));
assertEquals(expected, bulkListActuals.get(i));
}
List<ListBean> bulkListAllActuals = new ArrayList<ListBean>(_listDao.mgetAll(new GetAllOptions(new CollectionProperty("listProp", 25),
new CollectionProperty("listProp", 175))));
_listDao.mget(keys, bulkListActuals, new GetOptions(new CollectionProperty("listProp", 25), new CollectionProperty("listProp", 175)));
assertEquals(numBeans, bulkListActuals.size());
assertEquals(numBeans, bulkListAllActuals.size());
Collections.sort(bulkListAllActuals);
for(int i = 0; i < listBeans.size(); i++)
{
ListBean saved = listBeans.get(i);
ListBean expected = new ListBean();
expected.setRowkey(saved.getRowkey());
expected.setStrProp1(saved.getStrProp1());
expected.setListProp(new ArrayList<Object>());
for(int j = 0; j <= 175; j++)
expected.getListProp().add(j < 25 ? null : saved.getListProp().get(j));
_listDao.get(saved.getRowkey(), singleListActuals.get(i), new GetOptions(new CollectionProperty("listProp", 25), new CollectionProperty("listProp", 175)));
assertEquals(expected, singleListActuals.get(i));
assertEquals(expected, bulkListActuals.get(i));
expected.setStrProp1(null);
assertEquals(expected, bulkListAllActuals.get(i));
}
/*
* maps
*/
//do the same test using bulk API
List<MapBean> bulkMapActuals = _mapDao.mget(keys, null, new GetOptions("strProp1", "strProp1"));
List<MapBean> mapActuals = new ArrayList<MapBean>();
List<MapBean> expectedMaps = new ArrayList<MapBean>();
assertEquals(numBeans, bulkMapActuals.size());
Collections.sort(bulkMapActuals);
for(int i = 0; i < mapBeans.size(); i++)
{
MapBean saved = mapBeans.get(i);
MapBean expected = new MapBean();
expected.setRowkey(saved.getRowkey());
expected.setStrProp1(saved.getStrProp1());
MapBean actual = _mapDao.get(saved.getRowkey(), null, new GetOptions("strProp1", "strProp1"));
assertEquals(expected, actual);
assertEquals(expected, bulkMapActuals.get(i));
mapActuals.add(actual);
expectedMaps.add(expected);
}
/*
* load a range from within a collection
*/
String start = "key-100", end = "key-201";
List<MapBean> bulkMapAllActuals =
new ArrayList<MapBean>(_mapDao.mgetAll(new GetAllOptions(new CollectionProperty("mapProp", start), new CollectionProperty("mapProp", end))));
bulkMapActuals = _mapDao.mget(keys, mapActuals,
new GetOptions(new CollectionProperty("mapProp", start), new CollectionProperty("mapProp", end)));
assertEquals(numBeans, bulkMapActuals.size());
assertEquals(numBeans, bulkMapAllActuals.size());
Collections.sort(bulkMapAllActuals);
for(int i = 0; i < mapBeans.size(); i++)
{
MapBean saved = mapBeans.get(i);
MapBean expected = expectedMaps.get(i);
mapActuals.set(i, _mapDao.get(saved.getRowkey(), mapActuals.get(i),
new GetOptions(new CollectionProperty("mapProp", start), new CollectionProperty("mapProp", end))));
expected.setRowkey(saved.getRowkey());
expected.setMapProp(new HashMap<String, Object>());
for(Object o : saved.getMapProp().entrySet())
{
Map.Entry<String, Object> e = (Map.Entry<String, Object>) o;
String k = e.getKey();
if(k.compareTo(start) >= 0 && k.compareTo(end) <= 0)
expected.getMapProp().put(k, e.getValue());
}
assertEquals(expected, mapActuals.get(i));
assertEquals(expected, bulkMapActuals.get(i));
expected.setStrProp1(null);
assertEquals(expected, bulkMapAllActuals.get(i));
}
}
@Test
public void testHashFind() throws Exception
{
int numBeans = 2*CassandraDaoBase.ROW_RANGE_SIZE+1;//force dao to do multiple ranges
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
List<CompositeIndexedBean> cIdxBeans = new ArrayList<CompositeIndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('a');
idxBean.setIntVal(i/10);
idxBean.setIntVal2(i/2);
idxBean.setLongVal(i/10L);
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
CompositeIndexedBean cIdxBean = new CompositeIndexedBean();
cIdxBean.setRowKey(new Long(i));
cIdxBean.setCharVal('a');
cIdxBean.setIntVal(i/10);
cIdxBean.setLongVal(i/10);
cIdxBean.setStrVal("strval");
cIdxBeans.add(cIdxBean);
}
_indexedDao.mput(idxBeans);
_compositeIndexedDao.mput(cIdxBeans);
List<IndexedBean> idxActuals;
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setIntVal(5);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(50, 60), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
FindOptions options = new FindOptions();
options.setMaxRows(5); //ensure max rows honored
assertEquals(5, _indexedDao.mfind(idxTmpl, options).size());
options.setMaxRows(CassandraDaoBase.ROW_RANGE_SIZE*2);
assertEquals(10, _indexedDao.mfind(idxTmpl, options).size());
CompositeIndexedBean cIdxTmpl = new CompositeIndexedBean();
cIdxTmpl.setIntVal(5);
List<CompositeIndexedBean> cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfind(cIdxTmpl));
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxBeans.subList(50, 60), cIdxActuals);
for(CompositeIndexedBean cIdxBean : cIdxActuals)
assertTrue(((IEnhancedEntity) cIdxBean).getModifiedFields().isEmpty());
_indexedDao.hashFindStats().reset();
_indexedDao.hashFindIndexStats().reset();
idxTmpl = new IndexedBean();
idxTmpl.setStrVal("strval");
Collection<IndexedBean> actualColl = _indexedDao.mfind(idxTmpl);
idxActuals = new ArrayList<IndexedBean>();
assertEquals(1, _indexedDao.hashFindStats().getNumOps());
assertEquals(0, _indexedDao.hashFindStats().getNumCassandraOps());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE*5, _indexedDao.hashFindStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.hashFindStats().getNumRows());
assertEquals(1, _indexedDao.hashFindStats().getRecentTimings().length);
assertEquals(1, _indexedDao.hashFindIndexStats().getNumOps());
assertEquals(1, _indexedDao.hashFindIndexStats().getNumCassandraOps());
assertEquals(0, _indexedDao.hashFindIndexStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.hashFindIndexStats().getNumRows());
assertEquals(1, _indexedDao.hashFindIndexStats().getRecentTimings().length);
for(IndexedBean b : actualColl) //test incremental iteration rather than all() method
idxActuals.add(b);
assertEquals(1, _indexedDao.hashFindStats().getNumOps());
assertEquals(0, _indexedDao.hashFindStats().getNumCassandraOps());
assertEquals(numBeans*5, _indexedDao.hashFindStats().getNumCols());
assertEquals(numBeans, _indexedDao.hashFindStats().getNumRows());
assertEquals(3, _indexedDao.hashFindStats().getRecentTimings().length);
assertEquals(1, _indexedDao.hashFindIndexStats().getNumOps());
assertEquals(3, _indexedDao.hashFindIndexStats().getNumCassandraOps());
assertEquals(0, _indexedDao.hashFindIndexStats().getNumCols());
assertEquals(numBeans, _indexedDao.hashFindIndexStats().getNumRows());
assertEquals(3, _indexedDao.hashFindIndexStats().getRecentTimings().length);
Collections.sort(idxActuals);
assertBeansEqual(idxBeans, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
//ensure subsequent iteration also works
idxActuals.clear();
for(IndexedBean b : actualColl)
idxActuals.add(b);
Collections.sort(idxActuals);
assertBeansEqual(idxBeans, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
//now update a single bean so that the fetched range is exactly the batch size
IndexedBean upd = idxBeans.get(0);
upd.setStrVal("strval-updated");
_indexedDao.put(upd);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(1, numBeans), idxActuals);
cIdxTmpl = new CompositeIndexedBean();
cIdxTmpl.setStrVal("strval");
cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfind(cIdxTmpl));
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxBeans, cIdxActuals);
for(CompositeIndexedBean cIdxBean : cIdxActuals)
assertTrue(((IEnhancedEntity) cIdxBean).getModifiedFields().isEmpty());
/*
* test non-indexed property filtering
*/
idxTmpl = new IndexedBean();
idxTmpl.setIntVal(5);
idxTmpl.setIntVal2(27);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(54, 56), idxActuals);
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = idxBeans.get(i);
idxBean.setIntVal(0);
idxBean.setIntVal2(i == 140 ? 1 : 0);
idxBeans.add(idxBean);
}
_indexedDao.mput(idxBeans);
idxTmpl.setIntVal(0);
idxTmpl.setIntVal2(0);
List<IndexedBean> expecteds = new ArrayList<IndexedBean>(idxBeans.subList(0, 140));
expecteds.addAll(idxBeans.subList(141, numBeans));
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(expecteds, idxActuals);
}
@Test
public void testHashFindPartialColRange() throws Exception
{
int numBeans = CassandraDaoBase.ROW_RANGE_SIZE+1;//force dao to do multiple ranges
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
List<CompositeIndexedBean> cIdxBeans = new ArrayList<CompositeIndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i/10);
idxBean.setLongVal((long) i);
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
CompositeIndexedBean cIdxBean = new CompositeIndexedBean();
cIdxBean.setRowKey(new Long(i));
cIdxBean.setCharVal('c');
cIdxBean.setIntVal(i/10);
cIdxBean.setLongVal(i);
cIdxBean.setStrVal("strval");
cIdxBeans.add(cIdxBean);
}
_indexedDao.mput(idxBeans);
_compositeIndexedDao.mput(cIdxBeans);
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setIntVal(5);
List<IndexedBean> idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl, new FindOptions("longVal", "t")));
List<IndexedBean> idxExpecteds = new ArrayList<IndexedBean>();
Collections.sort(idxActuals);
for(int i = 50; i < 60; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxBean.setStrVal(idxBeans.get(i).getStrVal());
idxExpecteds.add(idxBean);
}
assertBeansEqual(idxExpecteds, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
CompositeIndexedBean cIdxTmpl = new CompositeIndexedBean();
cIdxTmpl.setIntVal(5);
List<CompositeIndexedBean> cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfind(cIdxTmpl, new FindOptions("longVal", "t")));
List<CompositeIndexedBean> cIdxExpecteds = new ArrayList<CompositeIndexedBean>();
for(int i = 50; i < 60; i++)
{
CompositeIndexedBean idxBean = new CompositeIndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxBean.setStrVal(idxBeans.get(i).getStrVal());
cIdxExpecteds.add(idxBean);
}
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxExpecteds, cIdxActuals);
for(CompositeIndexedBean cIdxBean : cIdxActuals)
assertTrue(((IEnhancedEntity) cIdxBean).getModifiedFields().isEmpty());
/*
* try collection properties
*/
List<ListBean> listBeans = new ArrayList<ListBean>();
List<Object> coll = new ArrayList<Object>();
for(int i = 0; i < 20; i++)
coll.add(i);
for(int i = 0; i < numBeans; i++)
{
ListBean bean = new ListBean();
bean.setRowkey(new Long(i));
bean.setStrProp("s" + i/10);
bean.setStrProp1("s2");
bean.setListProp(new ArrayList<Object>());
bean.setListProp(coll);
listBeans.add(bean);
}
_listDao.mput(listBeans);
ListBean lTmpl = new ListBean();
lTmpl.setStrProp("s5");
/*
* partial list
*/
int startIdx = 4, endIdx = 15;
FindOptions options = new FindOptions(new CollectionProperty("listProp", startIdx), new CollectionProperty("listProp", endIdx));
List<ListBean> listActuals = new ArrayList<ListBean>( _listDao.mfind(lTmpl, options) );
Collections.sort(listActuals);
assertEquals(10, listActuals.size());
List<Object> expectedColl = new ArrayList<Object>();
for(int i = 0; i <= endIdx; i++)
expectedColl.add(i < startIdx ? null : i);
for(int i = 50; i < 60; i++)
{
ListBean expected = new ListBean();
expected.setRowkey(listBeans.get(i).getRowkey());
expected.setListProp(expectedColl);
assertEquals(expected, listActuals.get(i-50));
}
/*
* full list
*/
options = new FindOptions(Collections.singleton("listProp"), null);
listActuals = new ArrayList<ListBean>( _listDao.mfind(lTmpl, options) );
Collections.sort(listActuals);
assertEquals(10, listActuals.size());
for(int i = 0; i < 10; i++)
{
ListBean expected = new ListBean();
expected.setRowkey(listBeans.get(50+i).getRowkey());
expected.setListProp(listBeans.get(50+i).getListProp());
assertEquals(expected, listActuals.get(i));
}
//delete a list value. key remains in the DB, ensure no value is returned...
ListBean lb = listBeans.get(55);
int cnt = lb.getListProp().size();
lb.setListProp(new ArrayList<Object>());
for(int i = 0; i < cnt; i++)
lb.getListProp().add(null);
_listDao.put(lb);
listActuals = new ArrayList<ListBean>( _listDao.mfind(lTmpl, options) );
Collections.sort(listActuals);
assertEquals(9, listActuals.size());
for(int i = 0; i < 10; i++)
{
if(i == 5)
continue; //deleted value
ListBean expected = new ListBean();
expected.setRowkey(listBeans.get(50+i).getRowkey());
expected.setListProp(listBeans.get(50+i).getListProp());
assertEquals(expected, listActuals.get(i < 5 ? i : i - 1));
}
}
@Test
public void testHashFindPartial() throws Exception
{
int numBeans = CassandraDaoBase.ROW_RANGE_SIZE+1;//force dao to do multiple ranges
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
List<CompositeIndexedBean> cIdxBeans = new ArrayList<CompositeIndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i/10);
idxBean.setLongVal((long) i);
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
CompositeIndexedBean cIdxBean = new CompositeIndexedBean();
cIdxBean.setRowKey(new Long(i));
cIdxBean.setCharVal('c');
cIdxBean.setIntVal(i/10);
cIdxBean.setLongVal(i);
cIdxBean.setStrVal("strval");
cIdxBeans.add(cIdxBean);
}
_indexedDao.mput(idxBeans);
_compositeIndexedDao.mput(cIdxBeans);
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setIntVal(5);
List<IndexedBean> idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl, new FindOptions(Collections.singleton("longVal"), null)));
List<IndexedBean> idxExpecteds = new ArrayList<IndexedBean>();
Collections.sort(idxActuals);
for(int i = 50; i < 60; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxExpecteds.add(idxBean);
}
assertBeansEqual(idxExpecteds, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
CompositeIndexedBean cIdxTmpl = new CompositeIndexedBean();
cIdxTmpl.setIntVal(5);
FindOptions options = new FindOptions(null, Collections.singleton("intVal"));
List<CompositeIndexedBean> cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfind(cIdxTmpl, options));
List<CompositeIndexedBean> cIdxExpecteds = new ArrayList<CompositeIndexedBean>();
for(int i = 50; i < 60; i++)
{
CompositeIndexedBean idxBean = new CompositeIndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setCharVal(idxBeans.get(i).getCharVal());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxBean.setStrVal(idxBeans.get(i).getStrVal());
cIdxExpecteds.add(idxBean);
}
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxExpecteds, cIdxActuals);
for(CompositeIndexedBean cIdxBean : cIdxActuals)
assertTrue(((IEnhancedEntity) cIdxBean).getModifiedFields().isEmpty());
/*
* try collection properties
*/
List<ListBean> listBeans = new ArrayList<ListBean>();
List<Object> coll = new ArrayList<Object>();
for(int i = 0; i < 20; i++)
coll.add(i);
for(int i = 0; i < numBeans; i++)
{
ListBean bean = new ListBean();
bean.setRowkey(new Long(i));
bean.setStrProp("s" + i/10);
bean.setStrProp1("s2");
bean.setListProp(new ArrayList<Object>());
bean.setListProp(coll);
listBeans.add(bean);
}
_listDao.mput(listBeans);
ListBean lTmpl = new ListBean();
lTmpl.setStrProp("s5");
int startIdx = 4, endIdx = 15;
Set<Object> includes = new HashSet<Object>();
for(int i = startIdx; i <= endIdx; i++)
includes.add(new CollectionProperty("listProp", i));
List<ListBean> listActuals = new ArrayList<ListBean>( _listDao.mfind(lTmpl, new FindOptions(includes, null)) );
Collections.sort(listActuals);
assertEquals(10, listActuals.size());
List<Object> expectedColl = new ArrayList<Object>();
for(int i = 0; i <= endIdx; i++)
expectedColl.add(i < startIdx ? null : i);
for(int i = 50; i < 60; i++)
{
ListBean expected = new ListBean();
expected.setRowkey(listBeans.get(i).getRowkey());
expected.setListProp(expectedColl);
assertEquals(expected, listActuals.get(i-50));
}
}
@Test
public void testHashFindCounters() throws Exception
{
int numBeans = 6;
List<ParentCounterBean> beans = new ArrayList<ParentCounterBean>();
List<Long> keys = new ArrayList<Long>();
for(int i = 0; i < numBeans; i++)
{
ParentCounterBean bean = createParentCounterBean(i);
bean.setStrProp("str-" + i/3);
beans.add(bean);
bean = createParentCounterBean(i); //use a different bean, saving a counter resets the increment
bean.setStrProp("str-" + i/3);
_parentCounterDao.put(bean);
keys.add((long) i);
}
ParentCounterBean tmpl = new ParentCounterBean();
tmpl.setStrProp(beans.get(0).getStrProp());
List<ParentCounterBean> expectedBeans = beans.subList(0, 3);
List<ParentCounterBean> actualBeans;
actualBeans = new ArrayList<ParentCounterBean>(_parentCounterDao.mfind(tmpl));
Collections.sort(actualBeans);
//convert counters to stored for easy comparison
for(int i = 0; i < numBeans; i++)
convertParentCounterBean(beans.get(i));
for(int i = 0; i < expectedBeans.size(); i++)
{
ParentCounterBean expected = expectedBeans.get(i), actual = actualBeans.get(i);
assertEquals("bean-" + i, expected, actual);
}
/*
* range
*/
actualBeans = new ArrayList<ParentCounterBean>();
actualBeans.addAll(_parentCounterDao.mfind(tmpl, new FindOptions(new CollectionProperty("listProp", 1), new CollectionProperty("listProp", 3))));
Collections.sort(actualBeans);
expectedBeans = beans.subList(1, 3); //bean 0 doesn't have any elements in listProp
assertEquals(expectedBeans.size(), actualBeans.size());
for(int i = 0; i < expectedBeans.size(); i++)
{
ParentCounterBean pbean = expectedBeans.get(i), actual = actualBeans.get(i);
assertEquals(pbean.getRowkey(), actual.getRowkey());
assertNull(actual.getCounterProp());
assertNull(actual.getEmbeddedProp());
assertNull(actual.getMapProp());
assertNull(actual.getStrProp());
if(i >= 1)
{
for(int j = 1; j <= Math.min(i, 3); j++)
assertEquals(pbean.getListProp().get(j), actual.getListProp().get(j));
}
}
/*
* includes/excludes
*/
Set<Object> includes = new HashSet<Object>();
includes.add("counterProp");
includes.add("strProp");
includes.add(new CollectionProperty("embeddedProp", "s"));
includes.add("listProp");
actualBeans = new ArrayList<ParentCounterBean>(_parentCounterDao.mfind(tmpl, new FindOptions(includes, null)));
expectedBeans = beans.subList(0, 3);
assertEquals(expectedBeans.size(), actualBeans.size());
Collections.sort(actualBeans);
for(int i = 0; i < expectedBeans.size(); i++)
{
ParentCounterBean bean = expectedBeans.get(i), actual = actualBeans.get(i);
bean.getEmbeddedProp().setCounterProp(null);
bean.setMapProp(null);
assertEquals(bean, actual);
}
}
@Test
public void testRangeIndexUpdate() throws Exception
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(0L);
idxBean.setLongVal(100L);
idxBean.setStrVal("sv");
idxBean.setStrVal2("sv2");
_indexedDao.put(idxBean);
idxBean.setStrVal("sv");
idxBean.setStrVal2("sv2");
idxBean.setLongVal(200L);
_indexedDao.put(idxBean);
IndexedBean start = new IndexedBean(), end = new IndexedBean();
//this range will get both values of the index, the stale one and the correct one
start.setLongVal(0L);
end.setLongVal(500L);
Collection<IndexedBean> actuals = _indexedDao.mfindBetween(start, end);
assertEquals(1, actuals.size());
assertEquals(200L, actuals.iterator().next().getLongVal());
assertEquals(1, _indexedStrategy.records.size());
assertEquals(1, _indexedStrategy.records.get(0).values.size());
assertEquals(100L, _indexedStrategy.records.get(0).values.iterator().next().getColumnName().get(0));
_indexedStrategy.records.clear();
idxBean.setStrVal("sv");
idxBean.setStrVal2("sv2");
idxBean.setLongVal(300L);
_indexedDao.put(idxBean);
_indexedDao.delete(idxBean.getRowKey());
assertEquals(0, _indexedDao.mfindBetween(start, end).size());
assertEquals(1, _indexedStrategy.records.size());
assertEquals(3, _indexedStrategy.records.get(0).values.size()); //strategy is not deleting values from index
Iterator<StaleIndexValue> iterator = _indexedStrategy.records.get(0).values.iterator();
assertEquals(100L, iterator.next().getColumnName().get(0));
assertEquals(200L, iterator.next().getColumnName().get(0));
assertEquals(300L, iterator.next().getColumnName().get(0));
}
@Test
public void testRangeIndexFind() throws Exception
{
int numBeans = CassandraDaoBase.ROW_RANGE_SIZE;
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
List<CompositeIndexedBean> cIdxBeans = new ArrayList<CompositeIndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i);
idxBean.setIntVal2(i);
idxBean.setLongVal(i/10L);
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
CompositeIndexedBean cIdxBean = new CompositeIndexedBean();
cIdxBean.setCharVal('c');
cIdxBean.setRowKey(new Long(i));
cIdxBean.setIntVal(i);
cIdxBean.setLongVal(i/10);
cIdxBean.setStrVal("strval");
cIdxBeans.add(cIdxBean);
}
_indexedDao.mput(idxBeans);
_compositeIndexedDao.mput(cIdxBeans);
assertEquals(1, _indexedDao.putIndexStats().getNumOps());
assertEquals(3*numBeans, _indexedDao.putIndexStats().getNumCols());
assertEquals(3*numBeans+2, _indexedDao.putIndexStats().getNumCassandraOps());
assertEquals(numBeans, _indexedDao.putIndexStats().getNumRows());
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
List<IndexedBean> idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(50, 60), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
idxTmpl.setIntVal2(55); //add post fetch filter...
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
assertBeansEqual(Collections.singletonList(idxBeans.get(55)), idxActuals);
CompositeIndexedBean cIdxTmpl = new CompositeIndexedBean();
cIdxTmpl.setLongVal(5);
List<CompositeIndexedBean> cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfind(cIdxTmpl));
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxBeans.subList(50, 60), cIdxActuals);
for(CompositeIndexedBean cIdxBean : cIdxActuals)
assertTrue(((IEnhancedEntity) cIdxBean).getModifiedFields().isEmpty());
assertEquals(0, _indexedStrategy.records.size());
assertEquals(0, _compositeStrategy.records.size());
int idx = 50;
for(IndexedBean bean : idxBeans.subList(50, 55))
{
bean.setStrVal2(null);
bean.setLongVal(idx++ % 2 == 0 ? -1L : null);
}
_indexedDao.mput(idxBeans.subList(50, 55));
idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(55, 60), idxActuals);
assertEquals(1, _indexedStrategy.records.size());
StaleIndexUpdateRecord record = _indexedStrategy.records.get(0);
DynamicCompositeSerializer compositeSer = new DynamicCompositeSerializer();
Set<Long> actualStaleRowKeys = new HashSet<Long>();
Set<Long> expectedStaleRowKeys = new HashSet<Long>();
/*
* validate the clock values
*/
for(StaleIndexValue stale : record.values)
{
actualStaleRowKeys.add((Long) stale.getColumnName().get(1));
SliceQuery<DynamicComposite,DynamicComposite,byte[]> query =
HFactory.createSliceQuery(keyspace, compositeSer, compositeSer, BytesArraySerializer.get());
query.setKey(stale.getRowKey());
query.setColumnNames(stale.getColumnName());
query.setColumnFamily("indexedbean_idx");
List<HColumn<DynamicComposite,byte[]>> columns = query.execute().get().getColumns();
assertEquals(1, columns.size());
assertEquals(stale.getClock(), columns.get(0).getClock());
}
assertEquals(5, record.values.size());
for(IndexedBean i : idxBeans.subList(50, 55))
expectedStaleRowKeys.add(i.getRowKey());
assertEquals(expectedStaleRowKeys, actualStaleRowKeys);
/*
* do a between find
*/
IndexedBean endIdxTmpl = new IndexedBean();
endIdxTmpl.setLongVal(6L);
idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(idxTmpl, endIdxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(55, 70), idxActuals);
assertEquals(2, _indexedStrategy.records.size());
record = _indexedStrategy.records.get(1);
assertEquals(5, record.values.size());
actualStaleRowKeys.clear();
for(StaleIndexValue stale : record.values)
actualStaleRowKeys.add((Long) stale.getColumnName().get(1));
assertEquals(expectedStaleRowKeys, actualStaleRowKeys);
idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
idxTmpl.setIntVal(58);
endIdxTmpl = new IndexedBean();
endIdxTmpl.setLongVal(6L);
endIdxTmpl.setIntVal(63);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(idxTmpl, endIdxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(58, 64), idxActuals);
CompositeIndexedBean endCIdxTmpl = new CompositeIndexedBean();
endCIdxTmpl.setLongVal(6);
cIdxActuals = new ArrayList<CompositeIndexedBean>(_compositeIndexedDao.mfindBetween(cIdxTmpl, endCIdxTmpl));
Collections.sort(cIdxActuals);
assertBeansEqual(cIdxBeans.subList(50, 70), cIdxActuals);
}
@Test
public void testRangeFindPartial() throws Exception
{
int numBeans = 1 + CassandraDaoBase.ROW_RANGE_SIZE * 3;//force dao to do multiple ranges
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i);
idxBean.setLongVal((long) Math.min(i/CassandraDaoBase.COL_RANGE_SIZE, 2));
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
}
_indexedDao.mput(idxBeans);
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setLongVal(2L);
Collection<IndexedBean> collection = _indexedDao.mfind(idxTmpl, new FindOptions(Collections.singleton("intVal"), null));
assertEquals(1, _indexedDao.rangeFindStats().getNumOps());
assertEquals(1, _indexedDao.rangeFindStats().getNumCassandraOps());
assertEquals(2*CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.rangeFindStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.rangeFindStats().getNumRows());
assertEquals(1, _indexedDao.rangeFindStats().getRecentTimings().length);
assertEquals(1, _indexedDao.rangeFindIndexStats().getNumOps());
assertEquals(1, _indexedDao.rangeFindIndexStats().getNumCassandraOps());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.rangeFindIndexStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE, _indexedDao.rangeFindIndexStats().getNumRows());
assertEquals(1, _indexedDao.rangeFindIndexStats().getRecentTimings().length);
List<IndexedBean> idxActuals = new ArrayList<IndexedBean>(collection);
assertEquals(2, _indexedDao.rangeFindStats().getNumOps());
assertEquals(2, _indexedDao.rangeFindStats().getNumCassandraOps());
assertEquals(2*(CassandraDaoBase.ROW_RANGE_SIZE+1), _indexedDao.rangeFindStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE+1, _indexedDao.rangeFindStats().getNumRows());
assertEquals(2, _indexedDao.rangeFindStats().getRecentTimings().length);
assertEquals(1, _indexedDao.rangeFindIndexStats().getNumOps());
assertEquals(2, _indexedDao.rangeFindIndexStats().getNumCassandraOps());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE+1, _indexedDao.rangeFindIndexStats().getNumCols());
assertEquals(CassandraDaoBase.ROW_RANGE_SIZE+1, _indexedDao.rangeFindIndexStats().getNumRows());
assertEquals(2, _indexedDao.rangeFindIndexStats().getRecentTimings().length);
List<IndexedBean> idxExpecteds = new ArrayList<IndexedBean>();
Collections.sort(idxActuals);
for(int i = 100; i < 301; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setIntVal(idxBeans.get(i).getIntVal());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxExpecteds.add(idxBean);
}
assertBeansEqual(idxExpecteds.subList(100, 201), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
IndexedBean startIdxTmpl = new IndexedBean();
startIdxTmpl.setLongVal(1L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(startIdxTmpl, idxTmpl, new FindBetweenOptions(Collections.singleton("intVal"), null)));
Collections.sort(idxActuals);
assertBeansEqual(idxExpecteds, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
}
@Test
public void testRangeFindPartialColRange() throws Exception
{
int numBeans = CassandraDaoBase.ROW_RANGE_SIZE;
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i);
idxBean.setLongVal(i/10L);
idxBean.setStrVal("strval");
idxBean.setStrVal2(null);
idxBeans.add(idxBean);
}
_indexedDao.mput(idxBeans);
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setLongVal(5L);
List<IndexedBean> idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl, new FindOptions("intVal", "t")));
List<IndexedBean> idxExpecteds = new ArrayList<IndexedBean>();
Collections.sort(idxActuals);
for(int i = 50; i < 70; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(idxBeans.get(i).getRowKey());
idxBean.setIntVal(idxBeans.get(i).getIntVal());
idxBean.setLongVal(idxBeans.get(i).getLongVal());
idxBean.setStrVal(idxBeans.get(i).getStrVal());
idxExpecteds.add(idxBean);
}
assertBeansEqual(idxExpecteds.subList(0, 10), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
IndexedBean endIdxTmpl = new IndexedBean();
endIdxTmpl.setLongVal(6L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(idxTmpl, endIdxTmpl, new FindBetweenOptions("intVal", "t")));
Collections.sort(idxActuals);
assertBeansEqual(idxExpecteds, idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
}
@Test
public void testRangeCompositeIndex() throws Exception
{
int numBeans = 30;
List<IndexedBean> idxBeans = new ArrayList<IndexedBean>();
for(int i = 0; i < numBeans; i++)
{
IndexedBean idxBean = new IndexedBean();
idxBean.setRowKey(new Long(i));
idxBean.setCharVal('c');
idxBean.setIntVal(i);
idxBean.setLongVal((i%5)/2L);
idxBean.setStrVal("strval-" + i/5);
idxBean.setStrVal2("strval2-" + i/5);
idxBeans.add(idxBean);
}
_indexedDao.mput(idxBeans);
List<IndexedBean> idxActuals;
IndexedBean idxTmpl = new IndexedBean();
idxTmpl.setStrVal2("strval2-1");
idxTmpl.setLongVal(1L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(7, 9), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
//try a leading index match
idxTmpl = new IndexedBean();
idxTmpl.setStrVal2("strval2-1");
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfind(idxTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(5, 10), idxActuals);
IndexedBean startTmpl = new IndexedBean(), endTmpl = new IndexedBean();
startTmpl.setStrVal("strval-1");
endTmpl.setStrVal("strval-2");
endTmpl.setLongVal(1L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(startTmpl, endTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(5, 14), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
startTmpl.setStrVal("strval-1");
startTmpl.setLongVal(2L);
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(startTmpl, endTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(9, 14), idxActuals);
for(IndexedBean idxBean : idxActuals)
assertTrue(((IEnhancedEntity) idxBean).getModifiedFields().isEmpty());
//try a leading index match
startTmpl = new IndexedBean();
endTmpl = new IndexedBean();
startTmpl.setStrVal2("strval2-1");
endTmpl.setStrVal2("strval2-3");
idxActuals = new ArrayList<IndexedBean>(_indexedDao.mfindBetween(startTmpl, endTmpl));
Collections.sort(idxActuals);
assertBeansEqual(idxBeans.subList(5, 20), idxActuals);
}
@Test
public void testManyPartitions() throws Exception
{
TestPartitioner.partitionHistory().clear();
TestPartitioner.rangePartitionHistory().clear();
PartitionIndexBeanDao dao = new PartitionIndexBeanDao();
dao.setKeyspaceFactory(_pm);
dao.init();
int numBeans = 1000;
List<PartitionedIndexBean> idxBeans = new ArrayList<PartitionedIndexBean>();
for(long i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = new PartitionedIndexBean();
idxBean.setRowKey(i);
idxBean.setPartitionedValue(i);
idxBeans.add(idxBean);
}
dao.mput(idxBeans);
PartitionedIndexBean tmpl = new PartitionedIndexBean();
tmpl.setPartitionedValue(0L);
PartitionedIndexBean endTmpl = new PartitionedIndexBean();
//ends up searching 1500 partitions, meaning each partition will initially be asked for one column and then a subsequent get will
//find an additional column in the partition
endTmpl.setPartitionedValue(numBeans*3L);
assertEquals(1000, dao.mfindBetween(tmpl, endTmpl).size());
}
@Test
public void testIndexPartitioning() throws Exception
{
TestPartitioner.partitionHistory().clear();
TestPartitioner.rangePartitionHistory().clear();
PartitionIndexBeanDao dao = new PartitionIndexBeanDao();
dao.setKeyspaceFactory(_pm);
dao.init();
int numBeans = 100;
List<PartitionedIndexBean> idxBeans = new ArrayList<PartitionedIndexBean>();
for(long i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = new PartitionedIndexBean();
idxBean.setRowKey(i);
idxBean.setPartitionedValue(i/10);
idxBeans.add(idxBean);
}
dao.mput(idxBeans);
assertEquals(numBeans, TestPartitioner.partitionHistory().size());
/*
* check index table row count
*/
BytesArraySerializer bas = BytesArraySerializer.get();
RangeSlicesQuery<byte[],byte[],byte[]> query = HFactory.createRangeSlicesQuery(keyspace, bas, bas, bas);
query.setKeys(null, null);
query.setColumnFamily("pib_idx");
query.setRange(null, null, false, 100);
Iterator<Row<byte[], byte[], byte[]>> iterator = query.execute().get().iterator();
int cnt = 0;
while(iterator.hasNext())
{
cnt++;
Row<byte[], byte[], byte[]> row = iterator.next();
assertEquals(20, row.getColumnSlice().getColumns().size());
}
assertEquals(numBeans/20, cnt);
TestPartitioner.partitionHistory().clear();
assertTrue(TestPartitioner.rangePartitionHistory().isEmpty());
/*
* range find
*/
PartitionedIndexBean tmpl = new PartitionedIndexBean();
tmpl.setPartitionedValue(5L);
List<PartitionedIndexBean> actual = new ArrayList<PartitionedIndexBean>(dao.mfind(tmpl));
Collections.sort(actual);
assertBeansEqual(idxBeans.subList(50, 60), actual);
assertEquals(1, TestPartitioner.partitionHistory().size());
assertEquals(1, TestPartitioner.partitionHistory().get(0).get(0).size());
assertEquals(2L, TestPartitioner.partitionHistory().get(0).get(0).get(0));
assertTrue(TestPartitioner.rangePartitionHistory().isEmpty());
TestPartitioner.partitionHistory().clear();
/*
* range between find
*/
PartitionedIndexBean endTmpl = new PartitionedIndexBean();
endTmpl.setPartitionedValue(7L);
actual = new ArrayList<PartitionedIndexBean>(dao.mfindBetween(tmpl, endTmpl));
Collections.sort(actual);
assertBeansEqual(idxBeans.subList(50, 80), actual);
assertTrue(TestPartitioner.partitionHistory().isEmpty());
assertEquals(1, TestPartitioner.rangePartitionHistory().size());
List<List<Object>> expectedRange = new ArrayList<List<Object>>();
expectedRange.add(Collections.<Object>singletonList(2L));
expectedRange.add(Collections.<Object>singletonList(3L));
assertBeansEqual(expectedRange, TestPartitioner.rangePartitionHistory().get(0));
TestPartitioner.partitionHistory().clear();
/*
* large range between find
*/
TestPartitioner.partitionHistory().clear();
TestPartitioner.rangePartitionHistory().clear();
numBeans = CassandraDaoBase.ROW_RANGE_SIZE*10;
idxBeans = new ArrayList<PartitionedIndexBean>();
for(long i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = new PartitionedIndexBean();
idxBean.setRowKey(1000+i);
idxBean.setPartitionedValue(1000+i*2);
idxBeans.add(idxBean);
}
dao.mput(idxBeans);
tmpl.setPartitionedValue(idxBeans.get(0).getPartitionedValue());
endTmpl.setPartitionedValue(idxBeans.get(numBeans-1).getPartitionedValue());
actual = new ArrayList<PartitionedIndexBean>(dao.mfindBetween(tmpl, endTmpl));
Collections.sort(actual);
assertBeansEqual(idxBeans, actual);
assertEquals(numBeans, TestPartitioner.rangePartitionHistory().get(0).size());
}
//for entities with multi-column indexes, when writing a value to indexes, all indexed values must be specified, otherwise the index
//becomes inconsistent
@Test
public void testMultiColumnIndexPut()
{
List<IndexedBean> beans = new ArrayList<IndexedBean>();
for(long i = 0; i < 10; i++)
{
IndexedBean bean = new IndexedBean();
bean.setRowKey(i);
bean.setStrVal(null);
bean.setStrVal2("sval2");
bean.setLongVal(i);
beans.add(bean);
}
_indexedDao.mput(beans);
//also test WAL cleaned up
EntityMetadata<IndexedBean> meta = new EntityMetadata<IndexedBean>(IndexedBean.class);
SliceQuery<byte[],byte[],byte[]> query = HFactory.createSliceQuery(_pm.createKeyspace(EConsistencyLevel.ONE),
BytesArraySerializer.get(), BytesArraySerializer.get(), BytesArraySerializer.get());
query.setKey(meta.getFamilyNameBytes());
query.setColumnFamily(PersistenceManager.CF_IDXWAL);
query.setRange(null, null, false, 100);
ColumnSlice<byte[],byte[]> slice = query.execute().get();
assertTrue(slice.getColumns().isEmpty());
IndexedBean expected = beans.get(5);
IndexedBean template = new IndexedBean();
template.setStrVal2(expected.getStrVal2());
template.setLongVal(expected.getLongVal());
assertEquals(expected, _indexedDao.find(template));
IndexedBean update = new IndexedBean();
update.setRowKey(expected.getRowKey());
update.setLongVal(expected.getLongVal()*5);
try
{
_indexedDao.put(update);
fail("partial index put should result in exception");
}
catch(IllegalArgumentException ex)
{
//success
}
}
@Test
public void testWal() throws Exception
{
long startTime = System.currentTimeMillis();
List<IndexedBean> beans = new ArrayList<IndexedBean>();
for(long i = 0; i < 10; i++)
{
IndexedBean bean = new IndexedBean();
bean.setRowKey(i);
bean.setStrVal(null);
bean.setStrVal2("sval2");
bean.setLongVal(i);
beans.add(bean);
}
_indexedDao.mput(beans);
Thread.sleep(1000);
EntityMetadata<IndexedBean> meta = new EntityMetadata<IndexedBean>(IndexedBean.class);
SliceQuery<byte[],Composite,byte[]> query = HFactory.createSliceQuery(_pm.createKeyspace(EConsistencyLevel.ONE),
BytesArraySerializer.get(), CompositeSerializer.get(), BytesArraySerializer.get());
query.setKey(meta.getFamilyNameBytes());
query.setColumnFamily(PersistenceManager.CF_IDXWAL);
query.setRange(null, null, false, 100);
ColumnSlice<Composite,byte[]> slice = query.execute().get();
assertEquals(0, slice.getColumns().size());
for(long i = 0; i < 10; i++)
{
IndexedBean bean = beans.get((int) i);
bean.setRowKey(i);
bean.setStrVal(null);
bean.setStrVal2("sval2");
bean.setLongVal(i);
beans.add(bean);
}
dropColumnFamily("indexedbean_idx");
try
{
_indexedDao.mput(beans);
}
catch(Exception ex)
{
//success
}
//data put failed, wal columns should exist
slice = query.execute().get();
assertEquals(10, slice.getColumns().size());
for(HColumn<Composite, byte[]> col : slice.getColumns())
{
Composite colName = col.getName();
assertEquals(2, colName.size());
assertEquals(System.currentTimeMillis(), (Long) colName.getComponent(0).getValue(LongSerializer.get()), 1000);
assertEquals(System.currentTimeMillis()*1000, col.getClock(), TimeUnit.MICROSECONDS.convert(1, TimeUnit.SECONDS));
long rowkey = LongSerializer.get().fromBytes((byte[]) colName.getComponent(1).getValue(BytesArraySerializer.get()));
boolean found = false;
for(int i = 0; i < beans.size(); i++)
{
if(beans.get(i).getRowKey().longValue() == rowkey)
{
beans.remove(i);
found = true;
break;
}
}
assertTrue("key " + rowkey, found);
}
_pm.init(); //recreate table
IndexedBean startTmpl = new IndexedBean(), endTmpl = new IndexedBean();
startTmpl.setLongVal(beans.get(0).getLongVal());
endTmpl.setLongVal(beans.get(beans.size() - 1).getLongVal());
_indexedDao.checkWal(startTime - 500);
assertEquals(0, _indexedDao.mfindBetween(startTmpl, endTmpl).size());
assertEquals(1, _indexedDao.walRecoveryStats().getNumOps());
assertEquals(1, _indexedDao.walRecoveryStats().getNumCassandraOps());
assertEquals(0, _indexedDao.walRecoveryStats().getNumCols());
assertEquals(1, _indexedDao.walRecoveryStats().getRecentTimings().length);
_indexedDao.walRecoveryStats().reset();
Thread.sleep(1000);
_indexedDao.checkWal(System.currentTimeMillis() - 100);
assertEquals(10, _indexedDao.mfindBetween(startTmpl, endTmpl).size());
assertEquals(1, _indexedDao.walRecoveryStats().getNumOps());
assertEquals(22, _indexedDao.walRecoveryStats().getNumCassandraOps());
assertEquals(10, _indexedDao.walRecoveryStats().getNumCols());
assertEquals(1, _indexedDao.walRecoveryStats().getRecentTimings().length);
}
@Test
public void testRangeIndexFindIteration() throws Exception
{
PartitionIndexBeanDao dao = new PartitionIndexBeanDao();
dao.setKeyspaceFactory(_pm);
dao.init();
int numBeans = 3*CassandraDaoBase.ROW_RANGE_SIZE + 1;
List<PartitionedIndexBean> idxBeans = new ArrayList<PartitionedIndexBean>();
for(long i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = new PartitionedIndexBean();
idxBean.setRowKey(i);
idxBean.setPartitionedValue(0L);
idxBeans.add(idxBean);
}
PartitionedIndexBean idxTmpl = new PartitionedIndexBean();
idxTmpl.setPartitionedValue(0L);
/*
* test partial initial batch
*/
testRangeFind(dao, idxBeans, idxTmpl, CassandraDaoBase.ROW_RANGE_SIZE/2, null);
/*
* test complete initial batch
*/
testRangeFind(dao, idxBeans, idxTmpl, CassandraDaoBase.ROW_RANGE_SIZE, null);
//test max rows
testRangeFind(dao, idxBeans, idxTmpl, CassandraDaoBase.ROW_RANGE_SIZE, CassandraDaoBase.ROW_RANGE_SIZE/2);
/*
* test complete subseqent batch
*/
testRangeFind(dao, idxBeans, idxTmpl, 2*CassandraDaoBase.ROW_RANGE_SIZE, null);
//test max rows
testRangeFind(dao, idxBeans, idxTmpl, CassandraDaoBase.ROW_RANGE_SIZE, (int) (CassandraDaoBase.ROW_RANGE_SIZE*1.5));
/*
* partial last batch
*/
testRangeFind(dao, idxBeans, idxTmpl, numBeans, null);
/*
* no rows
*/
idxTmpl.setPartitionedValue(11L);
assertTrue(dao.mfind(idxTmpl).isEmpty());
/*
* find between tests
*/
for(long i = 0; i < numBeans; i++)
{
idxBeans.get((int) i).setPartitionedValue(i/10);
}
dao.mput(idxBeans);
testRangeFindBetween(dao, idxBeans, 0, 5, EFindOrder.NONE, CassandraDaoBase.ROW_RANGE_SIZE);
testRangeFindBetween(dao, idxBeans, 0, 5, EFindOrder.ASCENDING, 30);
testRangeFindBetween(dao, idxBeans, 0, 5, EFindOrder.DESCENDING, 30);
testRangeFindBetween(dao, idxBeans, 0, 10, EFindOrder.ASCENDING, 100);
testRangeFindBetween(dao, idxBeans, 0, 10, EFindOrder.DESCENDING, 100);
testRangeFindBetween(dao, idxBeans, 0, 15, EFindOrder.ASCENDING, 150);
testRangeFindBetween(dao, idxBeans, 0, 15, EFindOrder.DESCENDING, 150);
testRangeFindBetween(dao, idxBeans, 0, 20, EFindOrder.ASCENDING, 200);
testRangeFindBetween(dao, idxBeans, 0, 20, EFindOrder.DESCENDING, 200);
testRangeFindBetween(dao, idxBeans, 0, 21, EFindOrder.ASCENDING, 201);
testRangeFindBetween(dao, idxBeans, 0, 21, EFindOrder.DESCENDING, 201);
testRangeFindBetween(dao, idxBeans, 0, 21, EFindOrder.ASCENDING, 101);
testRangeFindBetween(dao, idxBeans, 0, 21, EFindOrder.DESCENDING, 101);
//test > 100 vals in a partition...
for(int i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = idxBeans.get(i);
idxBean.setPartitionedValue(i/300L);
}
dao.mput(idxBeans);
idxTmpl.setPartitionedValue(0L);
Collection<PartitionedIndexBean> actuals = dao.mfind(idxTmpl);
Set<Long> keys = new HashSet<Long>();
for(PartitionedIndexBean actual : actuals)
{
long key = actual.getRowKey();
assertTrue(keys.add(key));
assertTrue(key >= 0);
assertTrue(key < 300);
assertEquals(0, actual.getPartitionedValue());
}
assertEquals(300, actuals.size());
FindBetweenOptions betweenOptions = new FindBetweenOptions();
betweenOptions.setRowOrder(EFindOrder.ASCENDING);
actuals = dao.mfindBetween(idxTmpl, idxTmpl, betweenOptions);
keys = new HashSet<Long>();
for(PartitionedIndexBean actual : actuals)
{
long key = actual.getRowKey();
assertTrue("duplicate key " + key + " size " + keys.size(), keys.add(key));
assertTrue(key >= 0);
assertTrue(key < 300);
assertEquals(0, actual.getPartitionedValue());
}
assertEquals(300, actuals.size());
betweenOptions.setRowOrder(EFindOrder.DESCENDING);
actuals = dao.mfindBetween(idxTmpl, idxTmpl, betweenOptions);
keys = new HashSet<Long>();
for(PartitionedIndexBean actual : actuals)
{
long key = actual.getRowKey();
assertTrue("duplicate key " + key + " size " + keys.size(), keys.add(key));
assertTrue(key >= 0);
assertTrue(key < 300);
assertEquals(0, actual.getPartitionedValue());
}
assertEquals(300, actuals.size());
for(int i = 0; i < numBeans; i++)
{
PartitionedIndexBean idxBean = idxBeans.get(i);
idxBean.setPartitionedValue(i/150L);
}
dao.mput(idxBeans);
PartitionedIndexBean startTmpl = new PartitionedIndexBean();
startTmpl.setPartitionedValue(0L);
idxTmpl.setPartitionedValue(1L);
FindBetweenOptions options = new FindBetweenOptions();
options.setMaxRows(280);
options.setRowOrder(EFindOrder.ASCENDING);
actuals = dao.mfindBetween(startTmpl, idxTmpl, options);
keys.clear();
int idx = 0;
for(PartitionedIndexBean actual : actuals)
{
long key = actual.getRowKey();
assertTrue(keys.add(key));
assertTrue(key >= 0);
assertTrue(key < 300);
assertEquals(idx/150, actual.getPartitionedValue());
idx++;
}
assertEquals(280, actuals.size());
}
private void testRangeFind(PartitionIndexBeanDao dao,
List<PartitionedIndexBean> beans,
PartitionedIndexBean template,
int batchSize,
Integer maxRows)
{
dao.mput(beans.subList(0, batchSize));
FindOptions options = new FindOptions();
if(maxRows != null)
options.setMaxRows(maxRows);
List<PartitionedIndexBean> actuals = new ArrayList<PartitionedIndexBean>(dao.mfind(template, options));
if(maxRows == null)
{
Collections.sort(actuals);
List<PartitionedIndexBean> expected = beans.subList(0, maxRows != null ? maxRows : batchSize);
assertBeansEqual(expected, actuals);
}
else
{
//can't guarantee what rows will com back, ensure the full amount came back and each row is unique
assertEquals(maxRows, actuals.size());
Set<Integer> indexes = new HashSet<Integer>();
for(PartitionedIndexBean bean : actuals)
{
boolean found = false;
for(int i = beans.size() - 1; i >= 0; i--)
{
if(bean.equals(beans.get(i)))
{
found = true;
assertTrue(bean.toString(), indexes.add(i));
}
}
assertTrue(bean.toString(), found);
}
}
}
private void testRangeFindBetween(PartitionIndexBeanDao dao, List<PartitionedIndexBean> idxBeans, long startVal, long endVal, EFindOrder order, int maxRows)
{
FindBetweenOptions options = new FindBetweenOptions();
options.setMaxRows(maxRows);
options.setRowOrder(order);
PartitionedIndexBean startTmpl = new PartitionedIndexBean();
PartitionedIndexBean endTmpl = new PartitionedIndexBean();
startTmpl.setPartitionedValue(startVal);
endTmpl.setPartitionedValue(endVal);
ArrayList<PartitionedIndexBean> actuals = new ArrayList<PartitionedIndexBean>(dao.mfindBetween(startTmpl, endTmpl, options));
Set<Long> ids = new HashSet<Long>();
if(order == EFindOrder.ASCENDING)
{
for(int i = 0; i < actuals.size(); i++)
{
long idxVal = startVal + i/10;
PartitionedIndexBean actual = actuals.get(i);
long key = actual.getRowKey();
long pval = actual.getPartitionedValue();
assertTrue("duplicate rowKey" + key, ids.add(key));
assertEquals("key " + key, pval, key/10);
assertEquals("val " + pval, idxVal, pval);
}
}
else if(order == EFindOrder.DESCENDING)
{
for(int i = actuals.size() - 1; i >= 0; i--)
{
long idxVal = endVal - i/10;
PartitionedIndexBean actual = actuals.get(i);
long key = actual.getRowKey();
long pval = actual.getPartitionedValue();
assertTrue("duplicate rowKey" + key, ids.add(key));
assertEquals("key " + key, pval, key/10);
assertEquals("val " + pval, idxVal, pval);
}
}
}
private class RecordingStrategy implements IStaleIndexValueStrategy
{
List<StaleIndexUpdateRecord> records = new ArrayList<StaleIndexUpdateRecord>();
@Override
public void handle(EntityMetadata<?> entity, IndexMetadata index, Keyspace keyspace, Collection<StaleIndexValue> values)
{
StaleIndexUpdateRecord record = new StaleIndexUpdateRecord();
record.entityMetadata = entity;
record.values = values;
record.index = index;
records.add(record);
}
}
@SuppressWarnings("unused")
private class StaleIndexUpdateRecord
{
EntityMetadata<?> entityMetadata;
Collection<StaleIndexValue> values;
IndexMetadata index;
}
}