com.bigdata.rdf.inf.FullyBufferedJustificationIterator 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
*/
package com.bigdata.rdf.inf;
import java.util.NoSuchElementException;
import com.bigdata.btree.IIndex;
import com.bigdata.btree.IRangeQuery;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.btree.keys.IKeyBuilder;
import com.bigdata.btree.keys.KeyBuilder;
import com.bigdata.btree.keys.SuccessorUtil;
import com.bigdata.rdf.spo.ISPO;
import com.bigdata.rdf.store.AbstractTripleStore;
/**
* Fully buffers and then visits all {@link Justification}s for a given
* statement.
*
* @author Bryan Thompson
* @version $Id$
*/
public class FullyBufferedJustificationIterator implements IJustificationIterator {
/** the database. */
private final AbstractTripleStore db;
/** the statement whose justifications are being visited. */
private final ISPO head;
/**
* Private key builder.
*
* Note: This capacity estimate is based on N longs per SPO, one head,
* and 2-3 SPOs in the tail. The capacity will be extended automatically
* if necessary.
*/
private final IKeyBuilder keyBuilder;
/** the index in which the justifications are stored. */
private final IIndex ndx;
private final Justification[] justifications;
private final int numJustifications;
private boolean open = true;
private int i = 0;
private Justification current = null;
/**
*
* @param db
* @param head The statement whose justifications will be materialized.
*/
public FullyBufferedJustificationIterator(final AbstractTripleStore db,
final ISPO head) {
assert db != null;
assert head != null;
this.db = db;
this.head = head;
this.ndx = db.getSPORelation().getJustificationIndex();
keyBuilder = KeyBuilder.newInstance();
head.s().encode(keyBuilder);
head.p().encode(keyBuilder);
head.o().encode(keyBuilder);
final byte[] fromKey = keyBuilder.getKey();
final byte[] toKey = SuccessorUtil.successor(fromKey.clone());
final long rangeCount = ndx.rangeCount(fromKey, toKey);
if (rangeCount > 5000000) {
// Limit at 5M. See https://sourceforge.net/apps/trac/bigdata/ticket/606 (Array Limits in Truth Maintenance)
throw new RuntimeException(
"Too many justifications to materialize: " + rangeCount);
}
this.justifications = new Justification[(int) rangeCount ];
/*
* Materialize the matching justifications.
*/
final ITupleIterator itr = ndx.rangeIterator(fromKey, toKey,
0/* capacity */, IRangeQuery.KEYS, null/* filter */);
int i = 0;
while (itr.hasNext()) {
justifications[i++] = (Justification) itr.next().getObject();
}
this.numJustifications = i;
}
public boolean hasNext() {
if(!open) return false;
assert i <= numJustifications;
if (i == numJustifications) {
return false;
}
return true;
}
public Justification next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
current = justifications[i++];
return current;
}
/**
* Removes the last {@link Justification} visited from the database
* (non-batch API).
*/
public void remove() {
if (!open)
throw new IllegalStateException();
if(current==null) {
throw new IllegalStateException();
}
/*
* Remove the justifications from the store (note that there is no value
* stored under the key).
*/
ndx.remove(Justification.getKey(keyBuilder, current));
}
public void close() {
if(!open) return;
open = false;
}
public Justification[] nextChunk() {
if (!hasNext()) {
throw new NoSuchElementException();
}
final Justification[] ret;
if (i == 0 && numJustifications == justifications.length) {
/*
* The SPO[] does not have any unused elements and nothing has been
* returned to the caller by next() so we can just return the
* backing array in this case.
*/
ret = justifications;
} else {
/*
* Create and return a new SPO[] containing only the statements
* remaining in the iterator.
*/
final int remaining = numJustifications - i;
ret = new Justification[remaining];
System.arraycopy(justifications, i, ret, 0, remaining);
}
// indicate that all statements have been consumed.
i = numJustifications;
return ret;
}
}