/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Aug 5, 2008
*/
package com.bigdata.btree.filter;
import java.util.UUID;
import com.bigdata.btree.AbstractBTreeTestCase;
import com.bigdata.btree.BTree;
import com.bigdata.btree.IRangeQuery;
import com.bigdata.btree.ITuple;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.btree.IndexMetadata;
import com.bigdata.btree.NOPTupleSerializer;
import com.bigdata.btree.keys.KeyBuilder;
import com.bigdata.btree.keys.TestKeyBuilder;
import com.bigdata.rawstore.SimpleMemoryRawStore;
/**
* @todo Add tests at that layer for cursor, reverse, remove, and other flag
* based iterator semantics. Potentially aggregate the stacked iterators
* into a package and their own test suite.
* <p>
* It would be best if that test suite could be reused against the
* federation as well, but testing with the federation generally requires
* additional effort in order to look for fence posts around chunk and
* partition boundaries.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestTupleFilters extends AbstractBTreeTestCase {
/**
*
*/
public TestTupleFilters() {
}
/**
* @param name
*/
public TestTupleFilters(String name) {
super(name);
}
/**
* Test of {@link IRangeQuery#REMOVEALL}. The state of the index is
* verified afterwards.
*/
public void test_removeAll() {
IndexMetadata metadata = new IndexMetadata(UUID.randomUUID());
metadata.setTupleSerializer(NOPTupleSerializer.INSTANCE);
BTree btree = BTree.create(new SimpleMemoryRawStore(), metadata);
final int nentries = 10;
final byte[][] keys = new byte[nentries][];
final byte[][] vals = new byte[nentries][];
for(int i=0; i<nentries; i++) {
keys[i] = TestKeyBuilder.asSortKey(i);
vals[i] = new byte[4];
r.nextBytes(vals[i]);
assertNull(btree.insert(keys[i], vals[i]));
}
/*
* Visit all tuples, removing each one as we go.
*/
{
int n = 0;
final ITupleIterator itr = btree.rangeIterator(null/* fromKey */,
null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT
| IRangeQuery.REMOVEALL, null/* filter */);
while(itr.hasNext()) {
final ITuple tuple = itr.next();
log.info(tuple.toString());
n++;
}
assertEquals(nentries, n);
}
/*
* Verify everything was removed.
*/
{
int n = 0;
final ITupleIterator itr = btree
.rangeIterator(null/* fromKey */, null/* toKey */,
0/* capacity */, IRangeQuery.DEFAULT, null/*filter*/);
while(itr.hasNext()) {
final ITuple tuple = itr.next();
log.error(tuple.toString());
n++;
}
assertEquals("Not expecting any entries",0,n);
}
}
/**
* Test of {@link IRangeQuery#REMOVEALL} using a {@link TupleFilter}. Only
* the even keys are deleted. The state of the index is verified afterwards.
*/
public void test_removeAll_with_TupleFilter() {
IndexMetadata metadata = new IndexMetadata(UUID.randomUUID());
metadata.setTupleSerializer(NOPTupleSerializer.INSTANCE);
BTree btree = BTree.create(new SimpleMemoryRawStore(), metadata);
final int capacity = 5;
final int nentries = 10;
final byte[][] keys = new byte[nentries][];
final byte[][] vals = new byte[nentries][];
for(int i=0; i<nentries; i++) {
keys[i] = TestKeyBuilder.asSortKey(i);
vals[i] = new byte[4];
r.nextBytes(vals[i]);
assertNull(btree.insert(keys[i], vals[i]));
}
/*
* Filter selects only the even keys.
*/
final TupleFilter filter = new TupleFilter() {
private static final long serialVersionUID = 1L;
protected boolean isValid(ITuple tuple) {
final byte[] key = tuple.getKey();
final int i = KeyBuilder.decodeInt(key, 0);
// delete only the even keys.
if (i % 2 == 0)
return true;
return false;
}
};
/*
* Range delete the keys matching the filter.
*/
{
final ITupleIterator itr = btree.rangeIterator(null/* fromKey */,
null/* toKey */, capacity, IRangeQuery.KEYS
| IRangeQuery.VALS | IRangeQuery.REMOVEALL, filter);
int ndeleted = 0;
while (itr.hasNext()) {
final ITuple tuple = itr.next();
if (log.isInfoEnabled())
log.info("visiting: "+tuple);
final byte[] key = tuple.getKey();
final int i = KeyBuilder.decodeInt(key, 0);
// delete only the even keys.
assertEquals(0, (i % 2));
final byte[] val = tuple.getValue();
assertEquals(keys[i], key);
assertEquals(vals[i], val);
ndeleted++;
}
assertEquals("#deleted", 5, ndeleted);
}
/*
* Now verify the state of the index.
*/
{
int nremaining = 0;
final ITupleIterator itr = btree.rangeIterator();
int n = 0;
while(itr.hasNext()) {
final ITuple tuple = itr.next();
final byte[] key = tuple.getKey();
final int i = KeyBuilder.decodeInt(key, 0);
// verify deleted only the even keys.
if (0 == (i % 2)) {
/*
* Found a key that decodes as an even integer.
*/
fail("n=" + n + ", tuple=" + tuple + ", i=" + i);
}
final byte[] val = tuple.getValue();
assertEquals(keys[i], key);
assertEquals(vals[i], val);
nremaining++;
}
assertEquals("#remaining", 5, nremaining);
}
}
// /**
// * Test explores the behavior of a filtering {@link Striterator} when
// * removing elements during traversal. The {@link Filter} uses a one step
// * lookahead, and this test is designed to see whether the {@link Filter}
// * causes the wrong element to be removed when {@link Iterator#remove()} is
// * invoked on the top level of the iterator stack.
// * <p>
// * Note: This test fails because remove() is broken for {@link Filter}.
// */
// public void test_striterator_remove() {
//
// List<Integer> l = new LinkedList<Integer>();
//
// l.add(0);
// l.add(1);
// l.add(2);
// l.add(3);
//
// IStriterator itr = new Striterator(l.iterator())
// .addFilter(new Filter() {
// private static final long serialVersionUID = 1L;
// /**
// * Accept only the even values.
// */
// @Override
// protected boolean isValid(Object obj) {
// final int i = ((Integer) obj).intValue();
// boolean ok = i == 0 || i == 2;
// log.info("obj="+i+", ok="+ok);
// return ok;
// }
// });
//
// int expected = 0;
//
// while(itr.hasNext()) {
//
// int actual = ((Integer)itr.next()).intValue();
//
// log.info("expected="+expected+", actual="+actual);
//
// assertEquals(expected,actual);
//
// assertTrue(l.contains(actual));
//
// itr.remove();
//
// assertFalse("list=" + l + ", should have removed " + actual, l
// .contains(actual));
//
// expected += 2;
//
// }
//
// }
}