com.bigdata.relation.accesspath.AccessPathFusedView Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
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 Oct 31, 2007
*/
package com.bigdata.relation.accesspath;
import org.apache.log4j.Logger;
import com.bigdata.bop.BOp;
import com.bigdata.bop.IPredicate;
import com.bigdata.btree.IIndex;
import com.bigdata.btree.ITuple;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.btree.view.FusedTupleIterator;
import com.bigdata.btree.view.FusedView;
import com.bigdata.striterator.ChunkedWrappedIterator;
import com.bigdata.striterator.IChunkedIterator;
import com.bigdata.striterator.IChunkedOrderedIterator;
import com.bigdata.striterator.IKeyOrder;
import cutthecrap.utils.striterators.Resolver;
import cutthecrap.utils.striterators.Striterator;
/**
* A read-only fused view of two access paths obtained for the same
* {@link IPredicate} constraint in two different databases (this is used for
* truth maintenance when reading on the union of a focus store and the
* database).
*
* FIXME review impl and write tests.
*
* FIXME Does not support {@link IPredicate.Annotations#ACCESS_PATH_FILTER}
*
* @author Bryan Thompson
* @version $Id$
*
* @deprecated by {@link BOp}s using the UNION of JOINs. However, also note that
* this is only used for TM and that the focus store is always local
* for TM.
*/
public class AccessPathFusedView implements IAccessPath {
protected static final Logger log = Logger.getLogger(IAccessPath.class);
private final AccessPath path1;
private final AccessPath path2;
/**
*
*/
public AccessPathFusedView(AccessPath path1,
AccessPath path2) {
if (path1 == null)
throw new IllegalArgumentException();
if (path2 == null)
throw new IllegalArgumentException();
if (path1 == path2)
throw new IllegalArgumentException();
final IPredicate p1 = path1.getPredicate();
final IPredicate p2 = path2.getPredicate();
if (p1.arity() != p2.arity())
throw new IllegalArgumentException();
final int arity = p1.arity();
for (int i = 0; i < arity; i++) {
if (!p1.get(i).equals(p2.get(i))) {
throw new IllegalArgumentException();
}
}
this.path1 = path1;
this.path2 = path2;
// // assume the flags from the first access path.
// this.flags = path1.flags;
}
@Override
public IPredicate getPredicate() {
return path1.getPredicate();
}
@Override
public boolean isEmpty() {
return path1.isEmpty() && path2.isEmpty();
}
/**
* {@inheritDoc}
*
* Note: You can not get an exact range count for a view.
*
* @throws UnsupportedOperationException
* if exact == true
.
*
* @todo an exact range count for a view could be written. It would have to
* use two iterators (like a {@link FusedView}) that progressed in
* sync so that duplicates could be detected. This means a full key
* range scan for both source access paths.
*/
@Override
public long rangeCount(boolean exact) {
if (exact) {
throw new UnsupportedOperationException();
}
// @todo check for overflow on Long#Max_value
return path1.rangeCount(exact) + path2.rangeCount(exact);
}
// final private int flags;
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException
* always.
*
* @todo this could be implemented with a variant (or relaxed form) of
* {@link FusedView}.
*/
@Override
public IIndex getIndex() {
throw new UnsupportedOperationException();
}
// @Override
// public ITupleIterator rangeIterator() {
//
// return rangeIterator(0/* capacity */);
//
// }
private ITupleIterator rangeIterator(final int capacity) {
/*
* assume the flags from the first access path.
*/
return new FusedTupleIterator, E>(path1.flags,//
false, // we do not want to see the deleted tuples.
new ITupleIterator[] {//
path1
.rangeIterator(capacity, path1.flags,
path1.indexLocalFilter),//
path2
.rangeIterator(capacity, path2.flags,
path2.indexLocalFilter) //
});
}
@Override
public IChunkedOrderedIterator iterator() {
return iterator(0L/* offset */, 0L/* limit */, 0/* capacity */);
}
// public IChunkedOrderedIterator iterator(int limit, int capacity) {
//
// return iterator(0L/* offset */, limit, capacity);
//
// }
/**
* FIXME write tests for optimizations for point tests and small limits. See
* {@link AccessPath#iterator(long, long, int) for impl details.
*
* FIXME handle non-zero offset.
*/
@Override
public IChunkedOrderedIterator iterator(final long offset, long limit,
int capacity) {
if (offset > 0L)
throw new UnsupportedOperationException();
if (limit == Long.MAX_VALUE) {
limit = 0L;
}
if (limit > AccessPath.MAX_FULLY_BUFFERED_READ_LIMIT) {
throw new UnsupportedOperationException();
}
/*
* @todo replace with ChunkedOrderedStriterator.
*/
if (path1.predicate.isFullyBound(path1.getKeyOrder())) {
if(log.isDebugEnabled())
log.debug("Predicate is fully bound.");
/*
* If the predicate is fully bound then there can be at most one
* element matched so we constrain the limit and capacity
* accordingly.
*/
capacity = 1;
limit = 1L;
} else if (limit > 0) {
/*
* A [limit] was specified.
*
* NOTE: When the [limit] is specified (GT ZERO) we MUST NOT let the
* DataService layer iterator read more than [limit] elements at a
* time.
*
* This is part of the contract for REMOVEALL - when you set the
* [limit] and specify REMOVEALL you are only removing the 1st
* [limit] elements in the traversal order.
*
* This is also part of the atomic queue operations contract - the
* head and tail queue operations function by specifying [limit :=
* 1] (tail also specifies the REVERSE traversal option).
*/
capacity = (int) limit;
}
final int chunkSize = (capacity == 0 ? IChunkedIterator.DEFAULT_CHUNK_SIZE
: capacity);
return new ChunkedWrappedIterator(new Striterator(
rangeIterator(capacity)).addFilter(new Resolver() {
private static final long serialVersionUID = 0L;
@Override
protected Object resolve(Object arg0) {
final ITuple tuple = (ITuple) arg0;
return tuple.getObject();
}
}), chunkSize, path1.keyOrder, null/* filter */);
}
@Override
public long removeAll() {
throw new UnsupportedOperationException();
}
@Override
public IKeyOrder getKeyOrder() {
return path1.getKeyOrder();
}
}