[Mulgara-svn] r1457 - in trunk: . conf/core src/jar/jrdf/java/org/mulgara/jrdf src/jar/query/java/org/mulgara/query src/jar/querylang/java/org/mulgara/itql src/jar/querylang/java/org/mulgara/protocol/http src/jar/querylang/java/org/mulgara/sparql src/jar/querylang/sablecc src/jar/resolver/java/org/mulgara/resolver src/jar/resolver-lucene/java/org/mulgara/resolver/lucene src/jar/resolver-memory/java/org/mulgara/resolver/memory src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype src/jar/resolver-null/java/org/mulgara/resolver/nullres src/jar/resolver-prefix/java/org/mulgara/resolver/prefix src/jar/resolver-spi/java/org/mulgara/resolver/spi src/jar/resolver-spi/java/org/mulgara/store/statement src/jar/resolver-store/java/org/mulgara/resolver/store src/jar/resolver-store/java/org/mulgara/store/statement src/jar/resolver-store/java/org/mulgara/store/statement/xa src/jar/resolver-store/java/org/mulgara/store/statement/xa11 src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11 src/jar/store-xa/java/org/mulgara/store/xa src/jar/tuples/java/org/mulgara/store/tuples src/jar/util-xa/java/org/mulgara/store/xa
pag at mulgara.org
pag at mulgara.org
Sat Jan 24 07:03:53 UTC 2009
Author: pag
Date: 2009-01-23 23:03:51 -0800 (Fri, 23 Jan 2009)
New Revision: 1457
Added:
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java
Removed:
trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
Modified:
trunk/.project
trunk/conf/core/mulgara-x-config.xml
trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java
trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java
trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java
trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java
trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java
trunk/src/jar/querylang/sablecc/itql.grammar
trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java
trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java
trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java
trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java
trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java
trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java
trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java
trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java
trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java
trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java
trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java
trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java
trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java
Log:
Merging XA1.1 branch into trunk. Keeping the default configuration at XA 1
Modified: trunk/.project
===================================================================
--- trunk/.project 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/.project 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>Mulgara-trunk</name>
+ <name>mulgara</name>
<comment></comment>
<projects>
</projects>
Modified: trunk/conf/core/mulgara-x-config.xml
===================================================================
--- trunk/conf/core/mulgara-x-config.xml 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/conf/core/mulgara-x-config.xml 2009-01-24 07:03:51 UTC (rev 1457)
@@ -26,7 +26,14 @@
all interfaces
-->
<Jetty>
- <Disabled>true</Disabled>
+ <Disabled>false</Disabled>
+ <Connector>
+ <!--<Host>localhost</Host>-->
+ <Port>8080</Port>
+ <Acceptors>5</Acceptors>
+ <MaxIdleTimeMs>60000</MaxIdleTimeMs>
+ <LowResourceMaxIdleTimeMs>5000</LowResourceMaxIdleTimeMs>
+ </Connector>
</Jetty>
<!-- The name of the server, used for RMI binding -->
@@ -81,11 +88,11 @@
and resolvers. The persistent resolver is used to manipulate the system
model.
-->
- <PersistentNodePoolFactory type="org.mulgara.store.nodepool.xa.XANodePoolFactory" dir="xaNodePool"/>
+ <PersistentNodePoolFactory type="org.mulgara.store.stringpool.xa11.XA11StringPoolFactory" dir="xaStringPool"/>
<TemporaryNodePoolFactory type="org.mulgara.store.nodepool.memory.MemoryNodePoolFactory"/>
- <PersistentStringPoolFactory type="org.mulgara.store.stringpool.xa.XAStringPoolFactory" dir="xaStringPool"/>
+ <PersistentStringPoolFactory type="org.mulgara.store.stringpool.xa11.XA11StringPoolFactory" dir="xaStringPool"/>
<TemporaryStringPoolFactory type="org.mulgara.store.stringpool.memory.MemoryStringPoolFactory"/>
- <PersistentResolverFactory type="org.mulgara.resolver.store.StatementStoreResolverFactory" dir="xaStatementStore"/>
+ <PersistentResolverFactory type="org.mulgara.resolver.store.XA11StatementStoreResolverFactory" dir="xaStatementStore"/>
<TemporaryResolverFactory type="org.mulgara.resolver.memory.MemoryResolverFactory" dir="tempStatementStore"/>
<!--
@@ -98,6 +105,8 @@
types.
-->
<DefaultContentHandler type="org.mulgara.content.rdfxml.RDFXMLContentHandler"/>
+ <ContentHandler type="org.mulgara.content.mp3.MP3ContentHandler"/>
+ <ContentHandler type="org.mulgara.content.mbox.MBoxContentHandler"/>
<ContentHandler type="org.mulgara.content.n3.N3ContentHandler"/>
<!--
@@ -108,7 +117,9 @@
<ResolverFactory type="org.mulgara.resolver.xsd.XSDResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.http.HttpResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.nodetype.NodeTypeResolverFactory"/>
+ <ResolverFactory type="org.mulgara.resolver.jar.JarResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.view.ViewResolverFactory"/>
+ <ResolverFactory type="org.mulgara.resolver.filesystem.FileSystemResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.prefix.PrefixResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.relational.RelationalResolverFactory"/>
<ResolverFactory type="org.mulgara.resolver.distributed.DistributedResolverFactory"/>
Modified: trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java
===================================================================
--- trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/jrdf/java/org/mulgara/jrdf/JRDFGraphUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -111,8 +111,8 @@
}
//reset model
- this.dropModel(this.modelURI);
- this.createModel(this.modelURI);
+ this.dropModel(modelURI);
+ this.createModel(modelURI);
//create and return graph
graph = new JRDFGraph(session, modelURI);
@@ -246,19 +246,18 @@
try {
String hostname = InetAddress.getLocalHost().getCanonicalHostName();
- this.serverURI = new URI("rmi", hostname, "/" + SERVER_NAME, null);
- this.modelURI = new URI("rmi", hostname, "/" + SERVER_NAME, MODEL_NAME);
+ serverURI = new URI("rmi", hostname, "/" + SERVER_NAME, null);
+ modelURI = new URI("rmi", hostname, "/" + SERVER_NAME, MODEL_NAME);
SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, false);
this.session = (LocalJRDFSession) sessionFactory.newJRDFSession();
//initialize model
- this.createModel(this.modelURI);
+ this.createModel(modelURI);
//let superclass set up too
super.setUp();
- }
- catch (Exception exception) {
+ } catch (Exception exception) {
exception.printStackTrace();
@@ -266,11 +265,11 @@
try {
tearDown();
+ } catch (Throwable t) {
+ logger.error("Encountered exception in exception handler. Ignoring.", t);
}
- finally {
- throw exception;
- }
+ throw exception;
}
}
@@ -281,7 +280,7 @@
*/
public void tearDown() throws Exception {
- this.dropModel(this.modelURI);
+ this.dropModel(modelURI);
//close the graph
if (graph != null) {
Deleted: trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/query/java/org/mulgara/query/ConstraintNegation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,185 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- * getModel() contributed by Netymon Pty Ltd on behalf of
- * The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.query;
-
-import java.util.*;
-
-// Third party packages
-// import org.apache.log4j.Logger;
-
-/**
- * A constraint expression composed of the negation (logical NOT) of one
- * subexpressions.
- *
- * @created 2001-10-29
- *
- * @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
- *
- * @version $Revision: 1.9 $
- *
- * @modified $Date: 2005/05/29 08:32:39 $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright © 2001-2003 <A href="http://www.PIsoftware.com/">Plugged In
- * Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class ConstraintNegation implements Constraint {
-
- // /** The logger */
- // private final static Logger logger = Logger.getLogger(ConstraintNegation.class.getName());
-
- /**
- * Allow newer compiled version of the stub to operate when changes
- * have not occurred with the class.
- * NOTE : update this serialVersionUID when a method or a public member is
- * deleted.
- */
- private static final long serialVersionUID = 9147228997817064907L;
-
- /**
- * The negated expression.
- */
- private Constraint constraint;
-
- //
- // Constructor
- //
-
- /**
- * Construct a constraint negation.
- *
- * @param constraint a non-<code>null</code> constraint
- * @throws IllegalArgumentException if <var>constraint</var> is
- * <code>null</code>
- */
- public ConstraintNegation(Constraint constraint) {
-
- // Validate "expression" parameter
- if (constraint == null) {
-
- throw new IllegalArgumentException("Null \"constraint\" parameter");
- }
-
- // Initialize fields
- this.constraint = constraint;
- }
-
- public boolean isRepeating() {
- return false;
- }
-
-
- /**
- * Get a constraint element by index.
- *
- * @param index The constraint element to retrieve, from 0 to 3.
- * @return The constraint element referred to by index.
- */
- public ConstraintElement getElement(int index) {
- return constraint.getElement(index);
- }
-
- public ConstraintElement getModel() {
- return constraint.getModel();
- }
-
-
- /**
- * Get all constraints which are variables. For back-compatibility, this
- * method currently ignores the fourth element of the triple.
- *
- * @return A set containing all variable constraints.
- */
- public Set<Variable> getVariables() {
- return constraint.getVariables();
- }
-
-
- /**
- * tests if the inner constraint is a ConstraintIs.
- *
- * @return <code>true</code> if the inner constraint is a ConstraintIs class.
- */
- public boolean isInnerConstraintIs() {
- return constraint instanceof ConstraintIs;
- }
-
- /**
- * Convert this object to a string.
- *
- * @return A string representation of this object.
- */
- public String toString() {
- return "not " + constraint;
- }
-
- /**
- * Creates a relatively unique value representing this constraint.
- *
- * @return A numerical combination of the elements and the anchor
- */
- public int hashCode() {
- return constraint.hashCode() * -1;
- }
-
- /**
- * Equality is by value.
- *
- * @param object PARAMETER TO DO
- * @return RETURNED VALUE TO DO
- */
- public boolean equals(Object object) {
-
- if (object == null) {
- return false;
- }
-
- if (object == this) {
- return true;
- }
-
- boolean returnValue = false;
-
- // Check that the given object is the correct class if so check each
- // element.
- if (object.getClass().equals(ConstraintNegation.class)) {
-
- ConstraintNegation tmpConstraint = (ConstraintNegation) object;
- returnValue = constraint.equals(tmpConstraint.constraint);
- }
-
- return returnValue;
- }
-}
Modified: trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/itql/ConstraintExpressionBuilder.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -169,11 +169,6 @@
tmpConstraint = ConstraintFactory.newConstraint(subject, predicate, object);
}
- // handle negated constraints
- if (((AConstraintConstraintFactor) rawConstraintFactor).getExclude() != null) {
- tmpConstraint = new ConstraintNegation(tmpConstraint);
- }
-
// Set new value.
if (logger.isDebugEnabled()) logger.debug("Setting constraint: " + tmpConstraint);
@@ -209,14 +204,7 @@
ConstraintExpressionBuilder builder = new ConstraintExpressionBuilder(interpreter);
embeddedConstraintExpression.apply((Switch) builder);
- tmpConstraintExpression = builder.getConstraintExpression();
-
- // handle negated expressions
- if (((AExpressionConstraintFactor) rawConstraintFactor).getExclude() != null) {
- tmpConstraintExpression = new ConstraintNegation((Constraint)tmpConstraintExpression);
- }
-
- setConstraintExpression(tmpConstraintExpression);
+ setConstraintExpression(builder.getConstraintExpression());
} catch (URISyntaxException use) {
uriException = use;
} catch (QueryException qe) {
Modified: trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/itql/ItqlInterpreterBeanUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -32,6 +32,7 @@
import org.mulgara.server.SessionFactory;
import org.mulgara.server.driver.SessionFactoryFinder;
import org.mulgara.util.Rmi;
+import org.mulgara.util.StackTrace;
import org.mulgara.util.TempDir;
// third party packages
@@ -91,7 +92,7 @@
private ItqlInterpreterBean bean = null;
/** host name of server */
- private static String hostName = System.getProperty("host.name");
+ private static String hostName = System.getProperty("host.name", "localhost");
/** an example model */
private static String testModel = "rmi://" + hostName + "/server1#itqlmodel";
@@ -617,15 +618,25 @@
// log that we're executing the test
log.debug("Starting backup API test 2");
- File file = new File(tmpDirectory, "server.gz");
- file.delete();
+ try {
+ File file = new File(tmpDirectory, "server.gz");
+ file.delete();
+
+ URI serverURI = new URI("rmi://localhost/server1");
+
+ bean.backup(serverURI, file);
+
+ assertTrue("Excepting a backup file", file.exists());
+ } catch (QueryException e) {
+ System.err.println("Error processing query" + e);
+ Throwable t = e.getCause();
+ while (t != null) {
+ System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+ t = t.getCause();
+ }
+ throw e;
+ }
- URI serverURI = new URI("rmi://localhost/server1");
-
- bean.backup(serverURI, file);
-
- assertTrue("Excepting a backup file", file.exists());
-
}
/**
@@ -639,15 +650,25 @@
// log that we're executing the test
log.debug("Starting backup API test 4");
- File file = new File(tmpDirectory, "server2.gz");
- file.delete();
-
- URI serverURI = new URI("rmi://localhost/server1");
-
- bean.backup(serverURI, new FileOutputStream(file));
-
- assertTrue("Excepting a backup file", file.exists());
-
+ try {
+ File file = new File(tmpDirectory, "server2.gz");
+ file.delete();
+
+ URI serverURI = new URI("rmi://localhost/server1");
+
+ bean.backup(serverURI, new FileOutputStream(file));
+
+ assertTrue("Excepting a backup file", file.exists());
+ } catch (QueryException e) {
+ System.err.println("Error processing query" + e);
+ Throwable t = e.getCause();
+ while (t != null) {
+ System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+ t = t.getCause();
+ }
+ throw e;
+ }
+
}
/**
@@ -700,18 +721,27 @@
*
* @throws Exception if the test fails
*/
- @SuppressWarnings("deprecation")
public void testRestoreApi1() throws Exception {
// log that we're executing the test
log.debug("Starting restore API test 1");
- File file = new File(tmpDirectory, "server2.gz");
+ try {
+ File file = new File(tmpDirectory, "server2.gz");
+
+ URI serverURI = new URI("rmi://localhost/server1");
+
+ bean.restore(file.toURL().openStream(), serverURI);
+ } catch (QueryException e) {
+ System.err.println("Error processing query" + e);
+ Throwable t = e.getCause();
+ while (t != null) {
+ System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+ t = t.getCause();
+ }
+ throw e;
+ }
- URI serverURI = new URI("rmi://localhost/server1");
-
- bean.restore(file.toURL().openStream(), serverURI);
-
}
/**
@@ -721,58 +751,67 @@
*
* @throws Exception if the test fails
*/
- @SuppressWarnings("deprecation")
public void testRoundTrip1() throws Exception {
- // log that we're executing the test
- log.debug("Starting round trip test 1");
+ try {
+ // log that we're executing the test
+ log.debug("Starting round trip test 1");
+
+ URI serverURI = new URI("rmi://" + hostName + "/server1");
+
+ // test the output
+ String select = "select $o from <" + testModel + "> " +
+ "where <rmi://" + hostName +
+ "/server1> <http://purl.org/dc/elements/1.1/creator> $o or " +
+ " <rmi://" + hostName +
+ "/foobar> <http://purl.org/dc/elements/1.1/creator> $o or " +
+ " <rmi://" + hostName +
+ "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> $o ;";
+
+ // insert statements with a subject the same as the
+ // server name
+ String insert = "insert " +
+ "<rmi://" + hostName +
+ "/server1> <http://purl.org/dc/elements/1.1/creator> 'foo' " +
+ "<rmi://" + hostName +
+ "/foobar> <http://purl.org/dc/elements/1.1/creator> 'foobar' " +
+ "<rmi://" + hostName +
+ "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> 'server1/foobar' " +
+ " into <" + testModel + ">;";
+
+ // insert the statement
+ bean.executeQuery(insert);
+
+ // select the statement
+ Answer answer = bean.executeQuery(select);
+ assertTrue("Excepting a answer before restore", answer != null);
+ assertTrue("Excepting a single result and found :" +
+ answer.getRowCount(), (answer.getRowCount() == 3));
+
+ //backup the server
+ File file = new File(tmpDirectory, "roundtrip.gz");
+ file.delete();
+ bean.backup(serverURI, new FileOutputStream(file));
+ assertTrue("Excepting a backup file", file.exists());
+
+ // restore the server
+ bean.restore(file.toURL().openStream(), serverURI);
+
+ // select the statement
+ answer = bean.executeQuery(select);
+ assertTrue("Excepting a answer after restore", answer != null);
+ assertTrue("Excepting a single result and found :" +
+ answer.getRowCount(), (answer.getRowCount() == 3));
+ } catch (QueryException e) {
+ System.err.println("Error processing query" + e);
+ Throwable t = e.getCause();
+ while (t != null) {
+ System.err.println("Caused by: " + t + StackTrace.throwableToString(t));
+ t = t.getCause();
+ }
+ throw e;
+ }
- URI serverURI = new URI("rmi://" + hostName + "/server1");
-
- // test the output
- String select = "select $o from <" + testModel + "> " +
- "where <rmi://" + hostName +
- "/server1> <http://purl.org/dc/elements/1.1/creator> $o or " +
- " <rmi://" + hostName +
- "/foobar> <http://purl.org/dc/elements/1.1/creator> $o or " +
- " <rmi://" + hostName +
- "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> $o ;";
-
- // insert statements with a subject the same as the
- // server name
- String insert = "insert " +
- "<rmi://" + hostName +
- "/server1> <http://purl.org/dc/elements/1.1/creator> 'foo' " +
- "<rmi://" + hostName +
- "/foobar> <http://purl.org/dc/elements/1.1/creator> 'foobar' " +
- "<rmi://" + hostName +
- "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> 'server1/foobar' " +
- " into <" + testModel + ">;";
-
- // insert the statement
- bean.executeQuery(insert);
-
- // select the statement
- Answer answer = bean.executeQuery(select);
- assertTrue("Excepting a answer before restore", answer != null);
- assertTrue("Excepting a single result and found :" +
- answer.getRowCount(), (answer.getRowCount() == 3));
-
- //backup the server
- File file = new File(tmpDirectory, "roundtrip.gz");
- file.delete();
- bean.backup(serverURI, new FileOutputStream(file));
- assertTrue("Excepting a backup file", file.exists());
-
- // restore the server
- bean.restore(file.toURL().openStream(), serverURI);
-
- // select the statement
- answer = bean.executeQuery(select);
- assertTrue("Excepting a answer after restore", answer != null);
- assertTrue("Excepting a single result and found :" +
- answer.getRowCount(), (answer.getRowCount() == 3));
-
}
/**
Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -21,6 +21,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -84,16 +85,13 @@
private static final String QUERY_ARG = "query";
/** The parameter identifying the output type. */
- protected static final String OUTPUT_ARG = "out";
+ protected static final String OUTPUT_ARG = "format";
- /** The output parameter value for indicating JSON output. */
- protected static final String OUTPUT_JSON = "json";
+ /** The header name for accepted mime types. */
+ protected static final String ACCEPT_HEADER = "Accept";
- /** The output parameter value for indicating XML output. */
- protected static final String OUTPUT_XML = "xml";
-
/** The default output type to use. */
- protected static final String DEFAULT_OUTPUT_TYPE = OUTPUT_XML;
+ protected static final Output DEFAULT_OUTPUT_TYPE = Output.XML;
/** The parameter identifying the graph. */
protected static final String DEFAULT_GRAPH_ARG = "default-graph-uri";
@@ -138,10 +136,10 @@
private SessionFactory cachedSessionFactory;
/** This object maps request types to the constructors for that output. */
- protected final Map<String,AnswerStreamConstructor> streamBuilders = new HashMap<String,AnswerStreamConstructor>();
+ protected final Map<Output,AnswerStreamConstructor> streamBuilders = new EnumMap<Output,AnswerStreamConstructor>(Output.class);
/** This object maps request types to the constructors for sending objects to that output. */
- protected final Map<String,ObjectStreamConstructor> objectStreamBuilders = new HashMap<String,ObjectStreamConstructor>();
+ protected final Map<Output,ObjectStreamConstructor> objectStreamBuilders = new EnumMap<Output,ObjectStreamConstructor>(Output.class);
/**
* Creates the servlet for communicating with the given server.
@@ -170,7 +168,7 @@
Answer result = executeQuery(query, req);
- String outputType = req.getParameter(OUTPUT_ARG);
+ Output outputType = getOutputType(req);
sendAnswer(result, outputType, resp);
try {
@@ -294,7 +292,7 @@
* @throws BadRequestException Due to a bad protocol type.
* @throws InternalErrorException Due to an error accessing the answer.
*/
- void sendAnswer(Answer answer, String outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+ void sendAnswer(Answer answer, Output outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
send(streamBuilders, answer, outputType, resp);
}
@@ -309,7 +307,7 @@
* @throws BadRequestException Due to a bad protocol type.
* @throws InternalErrorException Due to an error accessing the result.
*/
- void sendStatus(Object result, String outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+ void sendStatus(Object result, Output outputType, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
send(objectStreamBuilders, result, outputType, resp);
}
@@ -326,13 +324,12 @@
* @throws BadRequestException Due to a bad protocol type.
* @throws InternalErrorException Due to an error accessing the answer.
*/
- <T> void send(Map<String,? extends StreamConstructor<T>> builders, T data, String type, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
+ <T> void send(Map<Output,? extends StreamConstructor<T>> builders, T data, Output type, HttpServletResponse resp) throws IOException, BadRequestException, InternalErrorException {
resp.setContentType(CONTENT_TYPE);
resp.setHeader("pragma", "no-cache");
// establish the output type
if (type == null) type = DEFAULT_OUTPUT_TYPE;
- else type = type.toLowerCase();
// get the constructor for the stream outputter
StreamConstructor<T> constructor = builders.get(type);
@@ -404,7 +401,7 @@
Object result = executeCommand(cmd, req);
- String outputType = req.getParameter(OUTPUT_ARG);
+ Output outputType = getOutputType(req);
if (result instanceof Answer) {
sendAnswer((Answer)result, outputType, resp);
} else {
@@ -544,4 +541,49 @@
for (String p: knownParams) if (p.equalsIgnoreCase(name)) return true;
return false;
}
+
+
+ /**
+ * Determine the type of response we need.
+ * @param req The request object for the servlet connection.
+ * @return xml, json, rdfXml or rdfN3.
+ */
+ private Output getOutputType(HttpServletRequest req) {
+ Output type = DEFAULT_OUTPUT_TYPE;
+
+ // get the accepted types
+ String accepted = req.getHeader(ACCEPT_HEADER);
+ if (accepted != null) {
+ type = Output.forMime(accepted);
+ }
+
+ // check the URI parameters
+ String reqOutputName = req.getParameter(OUTPUT_ARG);
+ if (reqOutputName != null) {
+ Output reqOutput = Output.valueOf(reqOutputName.toUpperCase());
+ if (reqOutput != null) type = reqOutput;
+ }
+ return type;
+ }
+
+
+ /**
+ * Enumeration of the various output types, depending on mime type.
+ */
+ enum Output {
+ XML("application/sparql-results+xml"),
+ JSON("application/sparql-results+json"),
+ RDFXML("application/rdf+xml"),
+ N3("text/rdf+n3");
+
+ final String mimeText;
+ private Output(String mimeText) { this.mimeText = mimeText; }
+
+ static private Map<String,Output> outputs = new HashMap<String,Output>();
+ static {
+ for (Output o: Output.values()) outputs.put(o.mimeText, o);
+ }
+
+ static Output forMime(String mimeText) { return outputs.get(mimeText); }
+ }
}
Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/SparqlServlet.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -60,9 +60,10 @@
AnswerStreamConstructor xmlBuilder = new AnswerStreamConstructor() {
public StreamedAnswer fn(Answer ans, OutputStream s) { return new StreamedSparqlXMLAnswer(ans, s); }
};
- streamBuilders.put(OUTPUT_JSON, jsonBuilder);
- streamBuilders.put(OUTPUT_XML, xmlBuilder);
- streamBuilders.put(null, xmlBuilder);
+ streamBuilders.put(Output.JSON, jsonBuilder);
+ streamBuilders.put(Output.XML, xmlBuilder);
+ streamBuilders.put(Output.RDFXML, xmlBuilder); // TODO: create an RDF/XML Builder
+ streamBuilders.put(Output.N3, xmlBuilder); // TODO: create an N3 Builder
ObjectStreamConstructor jsonObjBuilder = new ObjectStreamConstructor() {
public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlJSONObject(o, s); }
@@ -70,9 +71,10 @@
ObjectStreamConstructor xmlObjBuilder = new ObjectStreamConstructor() {
public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlXMLObject(o, s); }
};
- objectStreamBuilders.put(OUTPUT_JSON, jsonObjBuilder);
- objectStreamBuilders.put(OUTPUT_XML, xmlObjBuilder);
- objectStreamBuilders.put(null, xmlObjBuilder);
+ objectStreamBuilders.put(Output.JSON, jsonObjBuilder);
+ objectStreamBuilders.put(Output.XML, xmlObjBuilder);
+ objectStreamBuilders.put(Output.RDFXML, xmlObjBuilder); // TODO: create an RDF/XML Object Builder
+ objectStreamBuilders.put(Output.N3, xmlObjBuilder); // TODO: create an N3 Builder
}
Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/TqlServlet.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -62,9 +62,10 @@
AnswerStreamConstructor xmlBuilder = new AnswerStreamConstructor() {
public StreamedAnswer fn(Answer ans, OutputStream s) { return new StreamedTqlXMLAnswer(ans, s); }
};
- streamBuilders.put(OUTPUT_JSON, jsonBuilder);
- streamBuilders.put(OUTPUT_XML, xmlBuilder);
- streamBuilders.put(null, xmlBuilder);
+ streamBuilders.put(Output.JSON, jsonBuilder);
+ streamBuilders.put(Output.XML, xmlBuilder);
+ streamBuilders.put(Output.RDFXML, xmlBuilder); // TODO: create an RDF/XML builder
+ streamBuilders.put(Output.N3, xmlBuilder); // TODO: create an N3 builder
ObjectStreamConstructor jsonObjBuilder = new ObjectStreamConstructor() {
public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlJSONObject(o, s); }
@@ -72,9 +73,10 @@
ObjectStreamConstructor xmlObjBuilder = new ObjectStreamConstructor() {
public StreamedAnswer fn(Object o, OutputStream s) { return new StreamedSparqlXMLObject(o, s); }
};
- objectStreamBuilders.put(OUTPUT_JSON, jsonObjBuilder);
- objectStreamBuilders.put(OUTPUT_XML, xmlObjBuilder);
- objectStreamBuilders.put(null, xmlObjBuilder);
+ objectStreamBuilders.put(Output.JSON, jsonObjBuilder);
+ objectStreamBuilders.put(Output.XML, xmlObjBuilder);
+ objectStreamBuilders.put(Output.RDFXML, xmlObjBuilder); // TODO: create an RDF/XML object builder
+ objectStreamBuilders.put(Output.N3, xmlObjBuilder); // TODO: create an N3 object builder
}
Modified: trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/java/org/mulgara/sparql/IdentityTransformer.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -32,7 +32,6 @@
import org.mulgara.query.ConstraintImpl;
import org.mulgara.query.ConstraintIn;
import org.mulgara.query.ConstraintIs;
-import org.mulgara.query.ConstraintNegation;
import org.mulgara.query.ConstraintNotOccurs;
import org.mulgara.query.ConstraintOccurs;
import org.mulgara.query.ConstraintOccursLessThan;
@@ -60,7 +59,7 @@
* Builds a transformer, with identity constructors.
*/
public IdentityTransformer() {
- initialize(new ConsImpl(), new ConsIs(), new ConsNegation(),
+ initialize(new ConsImpl(), new ConsIs(),
new ConsNotOccurs(), new ConsOccurs(), new ConsOccursLessThan(),
new ConsOccursMoreThan(), new ConsSingleTransitive(),
new ConsTransitive(), new ConsWalk());
@@ -267,11 +266,6 @@
public Class<ConstraintIs> getType() { return ConstraintIs.class; }
}
- protected class ConsNegation implements ConstraintTypeCons<ConstraintNegation> {
- public ConstraintNegation newConstraint(Constraint c) { throw new IllegalStateException("Negations are no longer supported"); }
- public Class<ConstraintNegation> getType() { return ConstraintNegation.class; }
- }
-
protected class ConsSingleTransitive implements ConstraintTypeCons<SingleTransitiveConstraint> {
public SingleTransitiveConstraint newConstraint(Constraint c) throws SymbolicTransformationException {
SingleTransitiveConstraint s = (SingleTransitiveConstraint)c;
Modified: trunk/src/jar/querylang/sablecc/itql.grammar
===================================================================
--- trunk/src/jar/querylang/sablecc/itql.grammar 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/querylang/sablecc/itql.grammar 2009-01-24 07:03:51 UTC (rev 1457)
@@ -47,7 +47,6 @@
{def} drop = 'drop';
{def} echo = 'echo';
{def} execute = 'execute';
- {def} exclude = 'exclude';
{def} export = 'export';
{def} from = 'from';
{def} help = 'help';
@@ -253,10 +252,10 @@
{minus} [minuend]:constraint_dterm minus [subtrahend]:constraint_factor ;
constraint_factor =
- {constraint} exclude? constraint |
+ {constraint} constraint |
{compound} lbrace [subject]:element exists_expression in_clause? rbrace |
{existential} lbracket exists_expression in_clause? rbracket |
- {expression} exclude? lpar constraint_expression rpar |
+ {expression} lpar constraint_expression rpar |
{transitive} transitive_clause |
{walk} walk_clause ;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BackupOperation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -163,22 +163,19 @@
StatementStore.VARIABLES[3]));
assert tuples != null;
try {
- assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
- assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
- assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
- assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+ int[] colMap = mapColumnsToStd(tuples.getVariables());
writer.write("TRIPLES\n");
long preallocationModelNode = metadata.getPreallocationModelNode();
for (tuples.beforeFirst(); tuples.next(); ) {
// Suppress output of the preallocation model.
- long modelNode = tuples.getColumnValue(3);
+ long modelNode = tuples.getColumnValue(colMap[3]);
if (modelNode != preallocationModelNode) {
- writer.write(Long.toString(tuples.getColumnValue(0)));
+ writer.write(Long.toString(tuples.getColumnValue(colMap[0])));
writer.write(' ');
- writer.write(Long.toString(tuples.getColumnValue(1)));
+ writer.write(Long.toString(tuples.getColumnValue(colMap[1])));
writer.write(' ');
- writer.write(Long.toString(tuples.getColumnValue(2)));
+ writer.write(Long.toString(tuples.getColumnValue(colMap[2])));
writer.write(' ');
writer.write(Long.toString(modelNode));
writer.write('\n');
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -38,18 +38,22 @@
public void execute(OperationContext operationContext,
SystemResolver systemResolver,
DatabaseMetadata metadata) throws Exception {
+ if (logger.isDebugEnabled()) logger.debug("Creating bootstrap nodes");
// Find the local node identifying the model
- long model = systemResolver.localizePersistent(
+ long graph = systemResolver.localizePersistent(
new URIReferenceImpl(databaseMetadata.getSystemModelURI()));
long rdfType = systemResolver.localizePersistent(
new URIReferenceImpl(databaseMetadata.getRdfTypeURI()));
- long modelType = systemResolver.localizePersistent(
+ long graphType = systemResolver.localizePersistent(
new URIReferenceImpl(databaseMetadata.getSystemModelTypeURI()));
+ // set up the system resolver to understand the system graph
+ systemResolver.initializeSystemNodes(graph, rdfType, graphType);
+
+ if (logger.isDebugEnabled()) logger.debug("Creating bootstrap statements");
// Use the session to create the model
- systemResolver.modifyModel(model, new SingletonStatements(model, rdfType,
- modelType), true);
- databaseMetadata.initializeSystemNodes(model, rdfType, modelType);
+ systemResolver.modifyModel(graph, new SingletonStatements(graph, rdfType, graphType), true);
+ databaseMetadata.initializeSystemNodes(graph, rdfType, graphType);
long preSubject = systemResolver.localizePersistent(
new URIReferenceImpl(databaseMetadata.getPreallocationSubjectURI()));
@@ -60,13 +64,13 @@
// Every node cached by DatabaseMetadata must be preallocated
systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, model),
+ new SingletonStatements(preSubject, prePredicate, graph),
true);
systemResolver.modifyModel(preModel,
new SingletonStatements(preSubject, prePredicate, rdfType),
true);
systemResolver.modifyModel(preModel,
- new SingletonStatements(preSubject, prePredicate, modelType),
+ new SingletonStatements(preSubject, prePredicate, graphType),
true);
systemResolver.modifyModel(preModel,
new SingletonStatements(preSubject, prePredicate, preSubject),
@@ -80,7 +84,7 @@
databaseMetadata.initializePreallocationNodes(preSubject, prePredicate, preModel);
- result = model;
+ result = graph;
}
public boolean isWriteOperation()
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -30,6 +30,7 @@
// Java 2 standard packages
import gnu.trove.TIntHashSet;
import gnu.trove.TIntIterator;
+import gnu.trove.TIntProcedure;
import java.beans.Beans;
import java.io.File;
@@ -1144,7 +1145,14 @@
} else {
TIntHashSet phaseSet = intersectPhaseSets(phaseSets);
if (phaseSet.isEmpty()) {
- throw new SimpleXAResourceException("No matching phases between Resource Handlers.");
+ final StringBuilder s = new StringBuilder("[");
+ for (TIntHashSet p: phaseSets) {
+ s.append(" { ");
+ p.forEach(new TIntProcedure() {public boolean execute(int i) { s.append(i).append(" "); return true; }});
+ s.append("}");
+ }
+ s.append(" ]");
+ throw new SimpleXAResourceException("No matching phases between Resource Handlers. Recovery sets: " + s);
}
selectCommonPhase(highestCommonPhaseNumber(phaseSet), handlers);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/OutputOperation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,7 +27,7 @@
* @copyright © 2008 <a href="http://www.revelytix.com">Revelytix, Inc.</a>
* @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
*/
-public abstract class OutputOperation implements Operation {
+public abstract class OutputOperation extends TuplesBasedOperation implements Operation {
protected final OutputStream outputStream;
protected final URI destinationURI;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/RestoreOperation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -80,8 +80,7 @@
* Technology, Inc</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-class RestoreOperation implements BackupConstants, Operation
-{
+class RestoreOperation extends TuplesBasedOperation implements BackupConstants, Operation {
/** Logger. */
private static final Logger logger =
@@ -221,23 +220,20 @@
StatementStore.VARIABLES[1],
StatementStore.VARIABLES[2],
StatementStore.VARIABLES[3]));
- assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
- assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
- assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
- assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+ int[] colMap = mapColumnsToStd(tuples.getVariables());
try {
tuples.beforeFirst();
long preallocationModelNode = metadata.getPreallocationModelNode();
while (tuples.next()) {
- long modelNode = tuples.getColumnValue(3);
+ long modelNode = tuples.getColumnValue(colMap[3]);
if (modelNode != preallocationModelNode) {
resolver.modifyModel(
modelNode,
- new SingletonStatements(tuples.getColumnValue(0),
- tuples.getColumnValue(1),
- tuples.getColumnValue(2)),
+ new SingletonStatements(tuples.getColumnValue(colMap[0]),
+ tuples.getColumnValue(colMap[1]),
+ tuples.getColumnValue(colMap[2])),
DatabaseSession.DENY_STATEMENTS
);
}
@@ -541,23 +537,20 @@
StatementStore.VARIABLES[1],
StatementStore.VARIABLES[2],
StatementStore.VARIABLES[3]));
- assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
- assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
- assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
- assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
+ int[] colMap = mapColumnsToStd(tuples.getVariables());
try {
tuples.beforeFirst();
long preallocationModelNode = metadata.getPreallocationModelNode();
while (tuples.next()) {
- long modelNode = tuples.getColumnValue(3);
+ long modelNode = tuples.getColumnValue(colMap[3]);
if (modelNode != preallocationModelNode) {
resolver.modifyModel(
modelNode,
- new SingletonStatements(tuples.getColumnValue(0),
- tuples.getColumnValue(1),
- tuples.getColumnValue(2)),
+ new SingletonStatements(tuples.getColumnValue(colMap[0]),
+ tuples.getColumnValue(colMap[1]),
+ tuples.getColumnValue(colMap[2])),
DatabaseSession.DENY_STATEMENTS
);
}
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java (from rev 1456, branches/xa11/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java)
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java (rev 0)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TuplesBasedOperation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,52 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.resolver;
+
+import java.util.Arrays;
+
+import org.mulgara.query.Variable;
+import org.mulgara.store.statement.StatementStore;
+
+/**
+ * Handles mapping of Tuples to expected columns, when necessary.
+ *
+ * @created Jan 23, 2009
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public abstract class TuplesBasedOperation {
+
+ /**
+ * Check a variable array to see if it is in SPOG or GSPO order, and return a mapping array
+ * to allow the columns to be accessed in SPOG order. If assertions are enabled, then the
+ * entire structure is tested, otherwise the first column is all that is tested.
+ * @param vars The variables to test for order.
+ * @return A mapping array used to access variables in SPOG order.
+ */
+ protected static final int[] mapColumnsToStd(Variable[] vars) {
+ assert vars.length == 4 : "Wrong number of variables. Expected {Subject,Predicate,Object,Meta} got " + Arrays.toString(vars);
+ if (vars[0] == StatementStore.VARIABLES[0]) {
+ assert vars[1] == StatementStore.VARIABLES[1] : "Expected '" + StatementStore.VARIABLES[1] + "' got '" + vars[1];
+ assert vars[2] == StatementStore.VARIABLES[2] : "Expected '" + StatementStore.VARIABLES[2] + "' got '" + vars[2];
+ assert vars[3] == StatementStore.VARIABLES[3] : "Expected '" + StatementStore.VARIABLES[3] + "' got '" + vars[3];
+ return new int[] { 0, 1, 2, 3 };
+ } else {
+ assert vars[0] == StatementStore.VARIABLES[3] : "Expected '" + StatementStore.VARIABLES[3] + "' got '" + vars[0];
+ assert vars[1] == StatementStore.VARIABLES[0] : "Expected '" + StatementStore.VARIABLES[0] + "' got '" + vars[1];
+ assert vars[2] == StatementStore.VARIABLES[1] : "Expected '" + StatementStore.VARIABLES[1] + "' got '" + vars[2];
+ assert vars[3] == StatementStore.VARIABLES[2] : "Expected '" + StatementStore.VARIABLES[2] + "' got '" + vars[3];
+ return new int[] { 1, 2, 3, 0 };
+ }
+ }
+}
Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -378,7 +378,7 @@
return false;
}
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends org.mulgara.store.tuples.Annotation> annotationClass) throws TuplesException {
// the object (lucene query string) is required when a score is requested
if (annotationClass.equals(MandatoryBindingAnnotation.class) &&
objectElement instanceof Variable && constraint.getScoreVar() != null) {
Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneTransformer.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -138,6 +138,7 @@
cumulative.add(lc);
} else {
cumulative.iterator().next().conjoinWith(lc);
+ if (logger.isTraceEnabled()) logger.trace("Updated LC with: " + cumulative.iterator().next() + "; result: " + lc);
transformed = true;
}
Modified: trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java
===================================================================
--- trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-memory/java/org/mulgara/resolver/memory/MemoryResolver.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -385,4 +385,11 @@
public LongMapper getRestoreMapper() throws Exception {
return new MemLongMapper();
}
+
+ /**
+ * Ignored in this implementation
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ // do nothing
+ }
}
Modified: trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java
===================================================================
--- trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-nodetype/java/org/mulgara/resolver/nodetype/TuplesWrapperResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -368,7 +368,7 @@
/**
* Copied from AbstractTuples
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
Modified: trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java
===================================================================
--- trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-null/java/org/mulgara/resolver/nullres/NullResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -75,7 +75,7 @@
* @see org.mulgara.store.tuples.Tuples#getAnnotation(java.lang.Class)
* @return Always <code>null</code>.
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
Modified: trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java
===================================================================
--- trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-prefix/java/org/mulgara/resolver/prefix/TuplesWrapperResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -352,7 +352,7 @@
/**
* Copied from AbstractTuples
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/ReresolvableResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -29,6 +29,7 @@
import java.util.Map;
+import org.mulgara.query.ConstraintElement;
import org.mulgara.query.TuplesException;
/**
@@ -60,5 +61,5 @@
* @return null if resolution was not able to be simplified using bindings otherwise a new
* ReresolvableResolution with any variables bound in the reresolution removed.
*/
- public ReresolvableResolution reresolve(Map bindings) throws TuplesException;
+ public ReresolvableResolution reresolve(Map<? extends ConstraintElement,Long> bindings) throws TuplesException;
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/resolver/spi/SystemResolver.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,7 +27,6 @@
package org.mulgara.resolver.spi;
-import java.net.URI;
/**
* A {@link Resolver} that is currently hosting the System Graph.
@@ -50,4 +49,12 @@
public void createSystemModel(long model, long modelTypeURI) throws ResolverException, LocalizeException;
public boolean modelExists(long model) throws ResolverException, LocalizeException;
+
+ /**
+ * Informs the system resolver of the metadata it uses for managing data.
+ * @param systemGraphNode The node for the system graph.
+ * @param rdfTypeNode The node representing <rdf:type>.
+ * @param systemGraphTypeNode The node used for the SystemResolver graph type.
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode);
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStore.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,9 +27,6 @@
package org.mulgara.store.statement;
-// Java 2 standard packages
-import java.util.*;
-
// Locally written packages
import org.mulgara.query.Variable;
import org.mulgara.store.tuples.StoreTuples;
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreAbstractUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -27,10 +27,9 @@
package org.mulgara.store.statement;
-// Java 2 standard packages
-import java.util.*;
-
// third party packages
+import java.util.Arrays;
+
import junit.framework.*;
import org.apache.log4j.Logger;
@@ -39,6 +38,7 @@
import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.tuples.TestTuples;
import org.mulgara.store.tuples.Tuples;
+import org.mulgara.store.tuples.TuplesOperations;
import org.mulgara.store.xa.XAStatementStore;
/**
@@ -69,6 +69,10 @@
private static Logger log =
Logger.getLogger(StatementStoreAbstractUnitTest.class.getName());
+ static final protected long SYSTEM_GRAPH = 100;
+ static final protected long RDF_TYPE = 101;
+ static final protected long GRAPH_TYPE = 102;
+
/**
* Subclasses must initialize this field.
*/
@@ -100,8 +104,6 @@
/**
* Test {@link StatementStore#isEmpty}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testIsEmpty() throws Exception {
@@ -113,23 +115,22 @@
store.removeTriples(1, 2, 3, 1);
store.removeTriples(1, 2, 4, 2);
store.removeTriples(2, 5, 6, 2);
+ store.removeTriples(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+ store.removeTriples(1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+ store.removeTriples(2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
assertTrue(!store.isEmpty());
store.removeTriples(1, 2, 3, 9);
assertTrue(store.isEmpty());
- }
- catch (UnsupportedOperationException e) {
-
+ } catch (UnsupportedOperationException e) {
log.warn("IsEmpty method unsupported", e);
}
}
/**
* Test {@link StatementStore#existsTriples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testExists() throws Exception {
@@ -137,63 +138,57 @@
long n = NodePool.NONE;
- assertTrue(store.existsTriples(1, 2, 3, n));
- assertTrue(store.existsTriples(1, 2, 4, n));
- assertTrue(store.existsTriples(2, 5, 6, n));
- assertTrue(!store.existsTriples(1, 3, 2, n));
- assertTrue(!store.existsTriples(9, 9, 9, n));
+ assertTrue(store.existsTriples(n, 2, 3, 1));
+ assertTrue(store.existsTriples(n, 2, 4, 2));
+ assertTrue(store.existsTriples(n, 5, 6, 2));
+ assertTrue(!store.existsTriples(n, 3, 2, 1));
+ assertTrue(!store.existsTriples(n, 9, 9, 9));
- assertTrue(store.existsTriples(1, 2, n, n));
- assertTrue(store.existsTriples(2, 5, n, n));
- assertTrue(!store.existsTriples(1, 3, n, n));
- assertTrue(!store.existsTriples(2, 9, n, n));
+ assertTrue(store.existsTriples(1, n, 3, 1));
+ assertTrue(store.existsTriples(2, n, 6, 2));
+ assertTrue(!store.existsTriples(2, n, 4, 2));
+ assertTrue(!store.existsTriples(9, n, 3, 1));
- assertTrue(store.existsTriples(n, 2, 3, n));
- assertTrue(store.existsTriples(n, 2, 4, n));
- assertTrue(!store.existsTriples(n, 1, 3, n));
- assertTrue(!store.existsTriples(n, 2, 9, n));
+ assertTrue(store.existsTriples(n, n, 3, 1));
+ assertTrue(store.existsTriples(n, n, 4, 2));
+ assertTrue(!store.existsTriples(n, n, 3, 2));
+ assertTrue(!store.existsTriples(n, n, 9, 2));
- assertTrue(store.existsTriples(1, n, 3, n));
- assertTrue(store.existsTriples(2, n, 6, n));
- assertTrue(!store.existsTriples(2, n, 4, n));
- assertTrue(!store.existsTriples(9, n, 3, n));
+ assertTrue(store.existsTriples(1, 2, n, 1));
+ assertTrue(store.existsTriples(2, 5, n, 2));
+ assertTrue(!store.existsTriples(1, 3, n, 1));
+ assertTrue(!store.existsTriples(2, 9, n, 2));
- assertTrue(store.existsTriples(1, n, n, n));
- assertTrue(store.existsTriples(2, n, n, n));
- assertTrue(!store.existsTriples(3, n, n, n));
+ assertTrue(store.existsTriples(n, 2, n, 1));
+ assertTrue(store.existsTriples(n, 5, n, 2));
+ assertTrue(!store.existsTriples(n, 3, n, 1));
+ assertTrue(!store.existsTriples(n, 9, n, 2));
- assertTrue(store.existsTriples(n, 2, n, n));
- assertTrue(store.existsTriples(n, 5, n, n));
- assertTrue(!store.existsTriples(n, 1, n, n));
+ assertTrue(store.existsTriples(1, n, n, 1));
+ assertTrue(store.existsTriples(1, n, n, 2));
+ assertTrue(store.existsTriples(2, n, n, 2));
+ assertTrue(!store.existsTriples(3, n, n, 2));
- assertTrue(store.existsTriples(n, n, 3, n));
- assertTrue(store.existsTriples(n, n, 6, n));
- assertTrue(!store.existsTriples(n, n, 5, n));
- }
- catch (UnsupportedOperationException e) {
-
+ assertTrue(store.existsTriples(n, n, n, 1));
+ assertTrue(store.existsTriples(n, n, n, 2));
+ assertTrue(!store.existsTriples(n, n, n, 3));
+ } catch (UnsupportedOperationException e) {
log.warn("Exists method unsupported", e);
}
}
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testDump() throws Exception {
- TestTuples expected = new TestTuples();
- add(expected, store.VARIABLES, new long[] {
- 1, 2, 3, 1});
- add(expected, store.VARIABLES, new long[] {
- 1, 2, 4, 2});
- add(expected, store.VARIABLES, new long[] {
- 2, 5, 6, 2});
+ TestTuples expected = getDump();
Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, NodePool.NONE);
- assertEquals(expected, t);
+ Tuples r = TuplesOperations.project(t, Arrays.asList(StatementStore.VARIABLES));
+ assertEquals(expected, r);
t.close();
+ r.close();
expected.close();
}
@@ -217,37 +212,39 @@
store.removeTriples(2, 5, 6, 2);
store.removeTriples(1, 2, 4, 2);
- assertTrue(!store.existsTriples(1, 2, 3, NodePool.NONE));
- assertTrue(!store.existsTriples(1, 2, 4, NodePool.NONE));
- assertTrue(!store.existsTriples(2, 5, 6, NodePool.NONE));
+ assertTrue(!store.existsTriples(NodePool.NONE, 2, 3, 1));
+ assertTrue(!store.existsTriples(NodePool.NONE, 2, 4, 2));
+ assertTrue(!store.existsTriples(NodePool.NONE, 5, 6, 2));
}
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode0() throws Exception {
TestTuples expected = new TestTuples();
Variable[] vars =
- new Variable[] {
- store.VARIABLES[1], store.VARIABLES[2], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 2, 3, 1});
- add(expected, vars, new long[] {
- 2, 4, 2});
+ new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[2], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {2, 3, 1});
+ add(expected, vars, new long[] {2, 4, 2});
+ add(expected, vars, new long[] {RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
- Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
- expected.close();
+ try {
+ Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ return;
+ } finally {
+ expected.close();
+ }
expected = new TestTuples();
- add(expected, vars, new long[] {
- 5, 6, 2});
+ add(expected, vars, new long[] {5, 6, 2});
- t = store.findTuples(2, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+ Tuples t = store.findTuples(2, NodePool.NONE, NodePool.NONE, NodePool.NONE);
+ add(expected, vars, new long[] {RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
assertEquals(expected, t);
t.close();
expected.close();
@@ -261,17 +258,17 @@
public void testFindTriplesByNode1() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars =
- new Variable[] {
- store.VARIABLES[2], store.VARIABLES[0], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 3, 1, 1});
- add(expected, vars, new long[] {
- 4, 1, 2});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[0], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {3, 1, 1});
+ add(expected, vars, new long[] {4, 1, 2});
- Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
+ try {
+ Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ }
expected.close();
}
@@ -283,15 +280,16 @@
public void testFindTriplesByNode2() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars =
- new Variable[] {
- store.VARIABLES[0], store.VARIABLES[1], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 1, 2, 1});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {1, 2, 1});
- Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 3, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
+ try {
+ Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 3, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ }
expected.close();
}
@@ -303,13 +301,9 @@
public void testFindTriplesByNode3() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars =
- new Variable[] {
- store.VARIABLES[0], store.VARIABLES[1], store.VARIABLES[2]};
- add(expected, vars, new long[] {
- 1, 2, 4});
- add(expected, vars, new long[] {
- 2, 5, 6});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1], StatementStore.VARIABLES[2]};
+ add(expected, vars, new long[] {1, 2, 4});
+ add(expected, vars, new long[] {2, 5, 6});
Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, 2);
assertEquals(expected, t);
@@ -319,64 +313,59 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode01() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[2], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 3, 1});
- add(expected, vars, new long[] {
- 4, 2});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {3, 1});
+ add(expected, vars, new long[] {4, 2});
- Tuples t = store.findTuples(1, 2, NodePool.NONE, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
-
- t = store.findTuples(1, 3, NodePool.NONE, NodePool.NONE);
- assertTrue(!expected.equals(t));
- t.close();
+ try {
+ Tuples t = store.findTuples(1, 2, NodePool.NONE, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+
+ t = store.findTuples(1, 3, NodePool.NONE, NodePool.NONE);
+ assertTrue(!expected.equals(t));
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ }
expected.close();
}
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode02() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[1], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 2, 1});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {2, 1});
- Tuples t = store.findTuples(1, NodePool.NONE, 3, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
-
- t = store.findTuples(1, NodePool.NONE, 4, NodePool.NONE);
- assertTrue(!expected.equals(t));
- t.close();
+ try {
+ Tuples t = store.findTuples(1, NodePool.NONE, 3, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+
+ t = store.findTuples(1, NodePool.NONE, 4, NodePool.NONE);
+ assertTrue(!expected.equals(t));
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ }
expected.close();
}
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode03() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[1], store.VARIABLES[2]};
- add(expected, vars, new long[] {
- 2, 4});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[1], StatementStore.VARIABLES[2]};
+ add(expected, vars, new long[] {2, 4});
Tuples t = store.findTuples(1, NodePool.NONE, NodePool.NONE, 2);
assertEquals(expected, t);
@@ -386,39 +375,35 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode12() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[0], store.VARIABLES[3]};
- add(expected, vars, new long[] {
- 1, 1});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[3]};
+ add(expected, vars, new long[] {1, 1});
- Tuples t = store.findTuples(NodePool.NONE, 2, 3, NodePool.NONE);
- assertEquals(expected, t);
- t.close();
-
- t = store.findTuples(NodePool.NONE, 2, 4, NodePool.NONE);
- assertTrue(!expected.equals(t));
- t.close();
+ try {
+ Tuples t = store.findTuples(NodePool.NONE, 2, 3, NodePool.NONE);
+ assertEquals(expected, t);
+ t.close();
+
+ t = store.findTuples(NodePool.NONE, 2, 4, NodePool.NONE);
+ assertTrue(!expected.equals(t));
+ t.close();
+ } catch (IllegalArgumentException e) {
+ // not supported
+ }
expected.close();
}
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode13() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[2], store.VARIABLES[0]};
- add(expected, vars, new long[] {
- 4, 1});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[2], StatementStore.VARIABLES[0]};
+ add(expected, vars, new long[] {4, 1});
Tuples t = store.findTuples(NodePool.NONE, 2, NodePool.NONE, 2);
assertEquals(expected, t);
@@ -428,16 +413,12 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode23() throws Exception {
TestTuples expected = new TestTuples();
- Variable[] vars = new Variable[] {
- store.VARIABLES[0], store.VARIABLES[1]};
- add(expected, vars, new long[] {
- 2, 5});
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[0], StatementStore.VARIABLES[1]};
+ add(expected, vars, new long[] {2, 5});
Tuples t = store.findTuples(NodePool.NONE, NodePool.NONE, 6, 2);
assertEquals(expected, t);
@@ -447,14 +428,11 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode013() throws Exception {
- TestTuples expected = new TestTuples(store.VARIABLES[2]);
- Variable[] vars = new Variable[] {
- store.VARIABLES[2]};
+ TestTuples expected = new TestTuples(StatementStore.VARIABLES[2]);
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[2]};
Tuples t = store.findTuples(2, 6, NodePool.NONE, 1);
assertEquals(expected, t);
t.close();
@@ -463,8 +441,7 @@
assertEquals(expected, t);
t.close();
- add(expected, vars, new long[] {
- 4});
+ add(expected, vars, new long[] {4});
t = store.findTuples(1, 2, NodePool.NONE, 2);
assertEquals(expected, t);
t.close();
@@ -473,20 +450,16 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode023() throws Exception {
- TestTuples expected = new TestTuples(store.VARIABLES[1]);
- Variable[] vars = new Variable[] {
- store.VARIABLES[1]};
+ TestTuples expected = new TestTuples(StatementStore.VARIABLES[1]);
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[1]};
Tuples t = store.findTuples(1, NodePool.NONE, 3, 4);
assertEquals(expected, t);
t.close();
- add(expected, vars, new long[] {
- 5});
+ add(expected, vars, new long[] {5});
t = store.findTuples(2, NodePool.NONE, 6, 2);
assertEquals(expected, t);
t.close();
@@ -495,20 +468,16 @@
/**
* Test {@link StatementStore#findTuples}.
- *
- * @throws Exception EXCEPTION TO DO
*/
public void testFindTriplesByNode123() throws Exception {
- TestTuples expected = new TestTuples(store.VARIABLES[0]);
- Variable[] vars = new Variable[] {
- store.VARIABLES[0]};
+ TestTuples expected = new TestTuples(StatementStore.VARIABLES[0]);
+ Variable[] vars = new Variable[] {StatementStore.VARIABLES[0]};
Tuples t = store.findTuples(NodePool.NONE, 2, 3, 4);
assertEquals(expected, t);
t.close();
- add(expected, vars, new long[] {
- 1});
+ add(expected, vars, new long[] {1});
t = store.findTuples(NodePool.NONE, 2, 3, 1);
assertEquals(expected, t);
t.close();
@@ -517,58 +486,53 @@
/**
* Populate the test store.
- *
- * @throws Exception EXCEPTION TO DO
*/
protected void setUp() throws Exception {
+ store.initializeSystemNodes(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE);
+ // set up the graph instances
+ store.addTriple(SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+ store.addTriple(1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+ store.addTriple(2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH);
+
store.addTriple(1, 2, 3, 1);
store.addTriple(1, 2, 4, 2);
store.addTriple(2, 5, 6, 2);
}
/**
+ * Return a dump of all tuples, sorted by the primary index.
+ * @return a new TestTuples containing all the {@link #setUp()} triples, according to the natural ordering of the store.
+ */
+ protected abstract TestTuples getDump();
+
+ /**
* Close the test store.
- *
- * @throws Exception EXCEPTION TO DO
*/
protected void tearDown() throws Exception {
-
if (store != null) {
-
try {
-
store.close();
- }
- finally {
-
+ } finally {
store = null;
}
}
}
/**
- * METHOD TO DO
- *
- * @param tt PARAMETER TO DO
- * @param vars PARAMETER TO DO
- * @param nodes PARAMETER TO DO
+ * Add a row to a tuples
+ * @param tt The tuples to add to
+ * @param vars The column names in the tuples
+ * @param nodes The values to bind to
*/
protected void add(TestTuples tt, Variable[] vars, long[] nodes) {
- if (vars.length != nodes.length) {
+ if (vars.length != nodes.length) throw new AssertionError();
- throw new AssertionError();
- }
-
for (int i = 0; i < vars.length; ++i) {
-
if (i == 0) {
-
tt.or(vars[i], nodes[i]);
- }
- else {
-
+ } else {
tt.and(vars[i], nodes[i]);
}
}
Modified: trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java
===================================================================
--- trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-spi/java/org/mulgara/store/statement/StatementStoreException.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -43,6 +43,9 @@
*/
public class StatementStoreException extends StoreException {
+ /** Version ID for serialization. */
+ private static final long serialVersionUID = -2415826145039347120L;
+
/**
* Get line separator.
*/
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,615 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- * getModel() contributed by Netymon Pty Ltd on behalf of
- * The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Standard Java packages
-import java.util.*;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.tuples.AbstractTuples;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.Tuples;
-import org.mulgara.store.tuples.TuplesOperations;
-
-/**
- * Tuples backed by the graph, corresponding to a particular constraint.
- *
- * It differs from {@link StatementStoreResolution} in that it handles
- * constraints with duplicate variable bindings. That is,
- * <code>$x $x $x</code> which will return all the statements that have the
- * same value in all three places. The class retains the original constraint
- * so that the graph index it's resolved against can be resolved anew as its
- * variables are bound.
- *
- * TO DO: Support <code>mulgara:is</code> re-binding.
- *
- * @created 2004-08-26
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.10 $
- *
- * @modified $Date: 2005/05/02 20:07:58 $ by $Author: raboczi $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <a href="mailto:info at PIsoftware.com">Plugged In Software</a>
- *
- * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
- * Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-class StatementStoreDuplicateResolution extends AbstractTuples implements Resolution {
-
- protected static Logger logger = Logger.getLogger(StatementStoreDuplicateResolution.class);
-
- /** Indicates ordering by subject */
- private final static int MASK0 = 1;
-
- /** Indicates ordering by predicate */
- private final static int MASK1 = 2;
-
- /** Indicates ordering by object */
- private final static int MASK2 = 4;
-
- /** Indicates ordering by graph */
- private final static int MASK3 = 8;
-
- /**
- * The constraint these tuples were generated to satisfy.
- */
- protected Constraint constraint;
-
- /**
- * The graph from which these tuples were generated.
- */
- protected StatementStore store;
-
- /**
- * The tuples.
- */
- private Tuples baseTuples, uniqueTuples;
-
- /**
- * Which columns s, p, o are the same.
- */
- private boolean[] sameColumns;
-
- /**
- * Whether we've calculated the rows.
- */
- private boolean calculatedRowCount;
-
- /**
- * An array that contains the position in the tuples. Elements 0, 1, 2, 3
- * map to subject, predicate, object and meta and the value in the array is
- * the column position.
- */
- private int[] columnOrder;
-
- /** A mapping between the virtual column numbers and the internal column numbers. */
- private int[] columnMap;
-
- private boolean hasNext = false;
-
- private List variableList;
-
- private TuplesEvaluator tuplesEvaluator;
-
- /**
- * Construct a tuples with node numbers and local tuples objects.
- *
- * @param newTuples a local tuples representing a graph.
- */
- StatementStoreDuplicateResolution(boolean[] newSameColumns, Tuples newTuples,
- int[] newColumnOrder) {
-
- baseTuples = newTuples;
- sameColumns = newSameColumns;
- columnOrder = newColumnOrder;
-
- // Get variable list.
- variableList = new LinkedList();
- Variable[] baseVars = baseTuples.getVariables();
- for (int index = 0; index < sameColumns.length; index++) {
- if (sameColumns[index]) variableList.add(baseVars[index]);
- }
- // do 1:1 mapping as this is expected in the tests - variable names are not duplicated
- columnMap = new int[baseVars.length];
- for (int i = 0; i < columnMap.length; i++) columnMap[i] = i;
-
- // Project for unique variables.
- try {
- uniqueTuples = TuplesOperations.project(baseTuples, variableList);
- }
- catch (TuplesException te) {
- logger.error("Failed to get unique tuples", te);
- }
-
- columnOrder = newColumnOrder;
- setVariables(newTuples.getVariables());
- setTuplesEvaluator();
- }
-
- /**
- * Find a graph index that satisfies a constraint.
- *
- * @param newConstraint the constraint to satisfy
- * @param newStore the store to resolve against
- * @throws IllegalArgumentException if <var>constraint</var> or <var>graph
- * </var> is <code>null</code>
- * @throws TuplesException EXCEPTION TO DO
- */
- StatementStoreDuplicateResolution(Constraint newConstraint, StatementStore newStore)
- throws TuplesException {
-
- try {
- constraint = newConstraint;
- store = newStore;
-
- // Setup which columns are duplicates.
- boolean equalSubject = constraint.getElement(0).equals(constraint.getElement(1)) ||
- constraint.getElement(0).equals(constraint.getElement(2));
- boolean equalPredicate = constraint.getElement(1).equals(constraint.getElement(0)) ||
- constraint.getElement(1).equals(constraint.getElement(2));
- boolean equalObject = constraint.getElement(2).equals(constraint.getElement(0)) ||
- constraint.getElement(2).equals(constraint.getElement(1));
- sameColumns = new boolean[] { equalSubject, equalPredicate,
- equalObject };
-
- // Setup which are the constants and which are the variables.
- long subject = toGraphTuplesIndex(constraint.getElement(0));
- long predicate = toGraphTuplesIndex(constraint.getElement(1));
- long object = toGraphTuplesIndex(constraint.getElement(2));
- long meta = toGraphTuplesIndex(constraint.getModel());
-
- final long VAR = NodePool.NONE;
- if (meta != VAR && subject == VAR && predicate == VAR && object == VAR) {
- // all variables except the graph. Select explicit ordering.
- int mask = MASK3;
- if (equalSubject) mask |= MASK0;
- if (equalPredicate) mask |= MASK1;
- if (equalObject) mask |= MASK2;
- baseTuples = store.findTuples(mask, subject, predicate, object, meta);
- } else {
- // Return the tuples using the s, p, o hints.
- baseTuples = store.findTuples(subject, predicate, object, meta);
- }
-
- // Get the unique values for the multiply constrained column.
- variableList = new LinkedList();
- for (int index = 0; index < sameColumns.length; index++) {
- if (sameColumns[index]) {
- variableList.add(StatementStore.VARIABLES[index]);
- }
- }
- uniqueTuples = TuplesOperations.project(baseTuples, variableList);
-
- // Create column map.
- columnOrder = new int[4];
- int[] inverseColumnOrder = ((StoreTuples)baseTuples).getColumnOrder();
- for (int index = 0; index < inverseColumnOrder.length; index++) {
- columnOrder[inverseColumnOrder[index]] = index;
- }
-
- // Set the variables. Using an ordered set.
- Set uniqueVariables = new LinkedHashSet();
- columnMap = new int[2];
- for (int index = 0; index < baseTuples.getVariables().length; index++) {
- Object obj = constraint.getElement(index);
- if (obj instanceof Variable) {
- if (!((Variable) obj).equals(Variable.FROM)) {
- if (!uniqueVariables.contains(obj)) columnMap[uniqueVariables.size()] = columnOrder[index];
- uniqueVariables.add(obj);
- }
- }
- }
- setVariables((Variable[]) uniqueVariables.toArray(new Variable[uniqueVariables.size()]));
-
- // Set up the tuples evaluator.
- setTuplesEvaluator();
- }
- catch (StatementStoreException se) {
- throw new TuplesException("Failed to set-up tuples", se);
- }
- }
-
- /**
- * Create a new tuples evaluator depending on how many columns to bind.
- */
- public void setTuplesEvaluator() {
- if (variableList.size() == 2) {
- tuplesEvaluator = new TwoConstrainedTuplesEvaluator();
- }
- else {
- tuplesEvaluator = new ThreeConstrainedTuplesEvaluator();
- }
- }
-
- public long getRowCount() throws TuplesException {
- return tuplesEvaluator.getRowCount();
- }
-
- public boolean hasNoDuplicates() throws TuplesException {
- return baseTuples.hasNoDuplicates();
- }
-
- public List getOperands() {
- return new ArrayList();
- }
-
- public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
- if (prefix.length > 4) {
- throw new TuplesException("Prefix too long");
- }
- tuplesEvaluator.beforeFirst(prefix, suffixTruncation);
- }
-
- public void close() throws TuplesException {
- try {
- if (baseTuples != null) {
- baseTuples.close();
- }
- }
- finally {
- if (uniqueTuples != null) {
- uniqueTuples.close();
- }
- }
- }
-
- /**
- * METHOD TO DO
- *
- * @return RETURNED VALUE TO DO
- */
- public Object clone() {
- StatementStoreDuplicateResolution cloned = (StatementStoreDuplicateResolution) super.clone();
- cloned.baseTuples = (Tuples) baseTuples.clone();
- cloned.uniqueTuples = (Tuples) uniqueTuples.clone();
- cloned.setVariables(getVariables());
- cloned.setTuplesEvaluator();
-// cloned.constraint = constraint;
- return cloned;
- }
-
-
- public long getRowUpperBound() throws TuplesException {
- return getRowCount();
- }
-
- public int getRowCardinality() throws TuplesException {
- long count = getRowCount();
- if (count > 1) {
- return Cursor.MANY;
- }
- switch ((int) count) {
- case 0:
- return Cursor.ZERO;
- case 1:
- return Cursor.ONE;
- default:
- throw new TuplesException("Illegal row count: " + count);
- }
- }
-
- public Constraint getConstraint() {
- return constraint;
- }
-
- public long getColumnValue(int column) throws TuplesException {
- return baseTuples.getColumnValue(columnMap[column]);
- }
-
- public boolean isColumnEverUnbound(int column) throws TuplesException {
- return baseTuples.isColumnEverUnbound(columnMap[column]);
- }
-
- public boolean isUnconstrained() throws TuplesException {
- return baseTuples.isUnconstrained();
- }
-
- public boolean isMaterialized() {
- return baseTuples.isMaterialized();
- }
-
- public boolean next() throws TuplesException {
- return tuplesEvaluator.next();
- }
-
- public boolean isComplete() {
- return true;
- }
-
-
- /**
- * A decorator around the getRowCount(), next() and beforeFirst() methods on
- * a tuples correctly sets the searching tuples and performs the correct next
- * operation.
- */
- private interface TuplesEvaluator {
-
- /**
- * Returns the row count.
- *
- * @return the row count.
- * @throws TuplesException if there was an error accessing the tuples.
- */
- public long getRowCount() throws TuplesException;
-
- /**
- * Calls before first using a given prefix.
- *
- * @param prefix long[] the prefix to jump to.
- * @param suffixTruncation the suffixes to truncate.
- * @throws TuplesException if there was a problem accessing the tuples.
- */
- public void beforeFirst(long[] prefix, int suffixTruncation)
- throws TuplesException;
-
- /**
- * Returns true if there is another tuples.
- *
- * @throws TuplesException if there was a problem accessing the tuples.
- * @return true if there is another tuples.
- */
- public boolean next() throws TuplesException;
- }
-
- /**
- * Operates on a tuples where two of the constraints are equal.
- */
- private class TwoConstrainedTuplesEvaluator implements TuplesEvaluator {
-
- public long getRowCount() throws TuplesException {
-
- // Only calculate rows once.
- if (!calculatedRowCount) {
-
- // Start with total number of tuples.
- Tuples tmpUniqueTuples = (Tuples) uniqueTuples.clone();
- Tuples tmpTuples = (Tuples) baseTuples.clone();
- tmpUniqueTuples.beforeFirst();
- tmpTuples.beforeFirst();
-
- rowCount = 0;
-
- while (tmpUniqueTuples.next()) {
- if (tmpUniqueTuples.getColumnValue(0) == tmpUniqueTuples.getColumnValue(1)) {
- tmpTuples.beforeFirst(new long[] {
- tmpUniqueTuples.getColumnValue(0),
- tmpUniqueTuples.getColumnValue(1) }, 0);
- while (tmpTuples.next()) {
- rowCount++;
- }
- }
- }
-
- // Ensure we don't calculate the rows again.
- calculatedRowCount = true;
- }
- return rowCount;
- }
-
- public void beforeFirst(long[] prefix, int suffixTruncation)
- throws TuplesException {
-
- // create a new prefix for uniqueTuples
- // this only includes columns from the initial prefix that represented duplicate variables
- // takes advantage of the fact that variables came out in the same order as the initial constraint
- // also, sameColumns offsets are same as baseTuples offsets
- long[] duplicatesPrefix = new long[] {};
- for (int i = 0; i < prefix.length; i++) {
- // i is an index into the virtual tuples. Map it to the original columns
- if (sameColumns[columnMap[i]]) {
- // only the first of the duplicated columns was mapped
- duplicatesPrefix = new long[] { prefix[i], prefix[i] };
- break;
- }
- }
-
- // Get the subject/predicate before first.
- uniqueTuples.beforeFirst(duplicatesPrefix, suffixTruncation);
-
- hasNext = uniqueTuples.next();
- while (hasNext && (uniqueTuples.getColumnValue(0) != uniqueTuples.getColumnValue(1))) {
- hasNext = uniqueTuples.next();
- }
-
- // Go to the first tuples. Ignoring suffix truncation.
- if (hasNext) {
- if (prefix.length <= 1) {
- baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0), uniqueTuples.getColumnValue(1) }, 0);
- } else {
- assert prefix.length == 2;
- baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0), uniqueTuples.getColumnValue(1), prefix[1] }, 0);
- }
- }
- }
-
- public boolean next() throws TuplesException {
-
- // Check that there are more tuples - assume tuples are in order.
- if (hasNext) {
-
- boolean hasNextBase = baseTuples.next();
-
- // Check if we still have a match, if not get the next match.
- if (!hasNextBase ||
- !((uniqueTuples.getColumnValue(0) == baseTuples.getColumnValue(0)) &&
- (uniqueTuples.getColumnValue(1) == baseTuples.getColumnValue(1)))) {
-
- // Get the next item to search.
- while (uniqueTuples.next()) {
-
- // Check to see that there is a next value. There will be at least
- // one value as the items to search are based on the original tuples.
- if (uniqueTuples.getColumnValue(0) == uniqueTuples.getColumnValue(1)) {
- baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
- uniqueTuples.getColumnValue(1) }, 0);
- hasNextBase = baseTuples.next();
- if (hasNextBase) {
- break;
- }
- }
- }
- }
- hasNext = hasNextBase;
- }
- return hasNext;
- }
- }
-
- /**
- * Operates on a tuples where all three of the constraints are equal.
- */
- private class ThreeConstrainedTuplesEvaluator implements TuplesEvaluator {
-
- public long getRowCount() throws TuplesException {
-
- // Only calculate rows once.
- if (!calculatedRowCount) {
-
- // Start with total number of tuples.
- Tuples tmpSubjPredTuples = (Tuples) uniqueTuples.clone();
- Tuples tmpTuples = (Tuples) baseTuples.clone();
- tmpSubjPredTuples.beforeFirst();
- tmpTuples.beforeFirst();
-
- rowCount = 0;
-
- while (tmpSubjPredTuples.next()) {
- if ((tmpSubjPredTuples.getColumnValue(0) == tmpSubjPredTuples.getColumnValue(1)) &&
- (tmpSubjPredTuples.getColumnValue(1) == tmpSubjPredTuples.getColumnValue(2))) {
- tmpTuples.beforeFirst(new long[] {
- tmpSubjPredTuples.getColumnValue(0),
- tmpSubjPredTuples.getColumnValue(1),
- tmpSubjPredTuples.getColumnValue(2) }, 0);
- while (tmpTuples.next()) {
- rowCount++;
- }
- }
- }
-
- // Ensure we don't calculate the rows again.
- calculatedRowCount = true;
- }
- return rowCount;
- }
-
- public void beforeFirst(long[] prefix, int suffixTruncation)
- throws TuplesException {
-
- // Get the subject/predicate before first.
- uniqueTuples.beforeFirst(prefix, suffixTruncation);
- baseTuples.beforeFirst(prefix, suffixTruncation);
- hasNext = uniqueTuples.next();
-
- while (hasNext &&
- ((uniqueTuples.getColumnValue(0) != uniqueTuples.getColumnValue(1)) ||
- (uniqueTuples.getColumnValue(1) != uniqueTuples.getColumnValue(2)))) {
- hasNext = uniqueTuples.next();
- }
-
- // Go to the first tuples.
- if (hasNext) {
- baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
- uniqueTuples.getColumnValue(1), uniqueTuples.getColumnValue(2) },
- 0);
- }
- }
-
- public boolean next() throws TuplesException {
-
- // Check that there are more tuples - assume tuples are in order.
- if (hasNext) {
-
- boolean hasNextBase = baseTuples.next();
-
- // Check if we still have a match, if not get the next match.
- if (!hasNextBase ||
- !((uniqueTuples.getColumnValue(0) == baseTuples.getColumnValue(0)) &&
- (uniqueTuples.getColumnValue(1) == baseTuples.getColumnValue(1)) &&
- (uniqueTuples.getColumnValue(2) == baseTuples.getColumnValue(2)))) {
-
- // Get the next item to search.
- while (uniqueTuples.next()) {
-
- // Check to see that there is a next value. There will be at least
- // one value as the items to search are based on the original tuples.
- if ((uniqueTuples.getColumnValue(0) == uniqueTuples.getColumnValue(1)) &&
- (uniqueTuples.getColumnValue(1) == uniqueTuples.getColumnValue(2))) {
- baseTuples.beforeFirst(new long[] { uniqueTuples.getColumnValue(0),
- uniqueTuples.getColumnValue(1),
- uniqueTuples.getColumnValue(2) }, 0);
- hasNextBase = baseTuples.next();
- if (hasNextBase) {
- break;
- }
- }
- }
- }
- hasNext = hasNextBase;
- }
- return hasNext;
- }
- }
-
- /**
- * Returns the long representation of the constraint element or
- * NodePool.NONE if a variable.
- *
- * @param constraintElement the constraint element to resolve.
- * @throws TuplesException if the constraint element is not supported.
- * @return long the long representation of the constraint element.
- */
- protected static long toGraphTuplesIndex(ConstraintElement constraintElement)
- throws TuplesException {
- if (constraintElement instanceof Variable) {
- return NodePool.NONE;
- }
- if (constraintElement instanceof LocalNode) {
- return ((LocalNode) constraintElement).getValue();
- }
-
- throw new TuplesException("Unsupported constraint element: " +
- constraintElement + " (" + constraintElement.getClass() + ")");
- }
-}
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreDuplicateResolutionUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,405 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-import java.util.*;
-
-// JUnit
-import junit.framework.*;
-
-// Log4J
-import org.apache.log4j.Logger;
-
-// Local packages
-import org.mulgara.store.statement.*;
-import org.mulgara.store.tuples.LiteralTuples;
-import org.mulgara.store.tuples.Tuples;
-
-/**
- * Test case for {@link StatementStoreDuplicateResolution}.
- *
- * @created 2004-06-15
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.3 $
- *
- * @modified $Date: 2005/01/05 04:58:55 $
- *
- * @maintenanceAuthor $Author: newmana $
- *
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
- * Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class StatementStoreDuplicateResolutionUnitTest extends TestCase {
-
- /**
- * Logger.
- */
- private Logger logger =
- Logger.getLogger(StatementStoreDuplicateResolutionUnitTest.class.getName());
-
- /**
- * Tuples for testing with.
- */
- private LiteralTuples t1, t2, t3, t4;
-
- /**
- * Constrained negation test tuples.
- */
- private StatementStoreDuplicateResolution tuples;
-
- /**
- * Constructs a new test with the given name.
- *
- * @param name the name of the test
- */
- public StatementStoreDuplicateResolutionUnitTest(String name) {
- super(name);
- }
-
- /**
- * Hook for test runner to obtain a test suite from.
- *
- * @return The test suite
- */
- public static Test suite() {
-
- TestSuite suite = new TestSuite();
-
- suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectPredicate"));
- suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectObject"));
- suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testPredicateObject"));
- suite.addTest(new StatementStoreDuplicateResolutionUnitTest("testSubjectPredicateObject"));
-
- return suite;
- }
-
- /**
- * Create test instance.
- *
- * @throws Exception EXCEPTION TO DO
- */
- public void setUp() throws Exception {
-
- String[] var1 = new String[] { "x", "y", "z" };
- t1 = new LiteralTuples(var1);
- long[][] subjectTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 1, 3, 1 },
- new long[] { 1, 3, 4 },
- new long[] { 1, 4, 1 },
- new long[] { 2, 1, 4 },
- new long[] { 2, 2, 2 },
- new long[] { 2, 2, 3 },
- new long[] { 2, 2, 4 },
- new long[] { 2, 2, 5 },
- new long[] { 2, 3, 1 },
- new long[] { 3, 1, 1 },
- new long[] { 3, 1, 3 },
- new long[] { 3, 3, 3 },
- new long[] { 3, 2, 4 },
- new long[] { 4, 1, 1 },
- new long[] { 4, 4, 1 },
- new long[] { 4, 5, 4 },
- new long[] { 4, 5, 6 },
- new long[] { 4, 5, 7 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- new long[] { 7, 8, 1 },
- };
-
- for (int i = 0; i < subjectTuples.length; i++) {
- ((LiteralTuples) t1).appendTuple(subjectTuples[i]);
- }
-
- String[] var2 = new String[] { "y", "z", "x" };
- t2 = new LiteralTuples(var2);
- long[][] predicateTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 1, 1, 3 },
- new long[] { 1, 1, 4 },
- new long[] { 1, 3, 3 },
- new long[] { 1, 4, 2 },
- new long[] { 2, 2, 2 },
- new long[] { 2, 3, 2 },
- new long[] { 2, 4, 2 },
- new long[] { 2, 4, 3 },
- new long[] { 2, 5, 2 },
- new long[] { 3, 1, 1 },
- new long[] { 3, 1, 2 },
- new long[] { 3, 3, 3 },
- new long[] { 3, 4, 1 },
- new long[] { 4, 1, 1 },
- new long[] { 4, 1, 4 },
- new long[] { 5, 4, 4 },
- new long[] { 5, 6, 4 },
- new long[] { 5, 7, 4 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- new long[] { 8, 1, 7 },
- };
-
- for (int i = 0; i < predicateTuples.length; i++) {
- ((LiteralTuples) t2).appendTuple(predicateTuples[i]);
- }
-
- String[] var4 = new String[] { "x", "z", "y" };
- t4 = new LiteralTuples(var4);
- long[][] subjectObjectTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 1, 1, 3 },
- new long[] { 1, 1, 4 },
- new long[] { 1, 4, 3 },
- new long[] { 2, 1, 3 },
- new long[] { 2, 2, 2 },
- new long[] { 2, 3, 2 },
- new long[] { 2, 4, 1 },
- new long[] { 2, 4, 2 },
- new long[] { 2, 5, 2 },
- new long[] { 3, 1, 1 },
- new long[] { 3, 3, 1 },
- new long[] { 3, 3, 3 },
- new long[] { 3, 4, 2 },
- new long[] { 4, 1, 1 },
- new long[] { 4, 1, 4 },
- new long[] { 4, 4, 5 },
- new long[] { 4, 6, 5 },
- new long[] { 4, 7, 5 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 1, 8 },
- new long[] { 7, 7, 7 },
- };
-
- for (int i = 0; i < subjectObjectTuples.length; i++) {
- ((LiteralTuples) t4).appendTuple(subjectObjectTuples[i]);
- }
- }
-
- /**
- * Default text runner.
- *
- * @param args The command line arguments
- */
- public static void main(String[] args) {
-
- junit.textui.TestRunner.run(suite());
- }
-
- //
- // Test cases
- //
-
- /**
- * Test a constraint where the subject and predicate are the same.
- *
- * @throws Exception if query fails when it should have succeeded
- */
- public void testSubjectPredicate() throws Exception {
-
- // Not subject = 1.
- tuples = new StatementStoreDuplicateResolution(
- new boolean[] { true, true, false }, t1, new int[] { 0, 1, 2, 3});
-
- // Expected results
- long[][] expectedTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 2, 2, 2 },
- new long[] { 2, 2, 3 },
- new long[] { 2, 2, 4 },
- new long[] { 2, 2, 5 },
- new long[] { 3, 3, 3 },
- new long[] { 4, 4, 1 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- };
-
- testTuples(expectedTuples, tuples);
- }
-
- /**
- * Test a constraint where the predicate and object are the same.
- *
- * @throws Exception if query fails when it should have succeeded
- */
- public void testPredicateObject() throws Exception {
-
- // Not subject = 1.
- tuples = new StatementStoreDuplicateResolution(
- new boolean[] { false, true, true }, t2, new int[] { 1, 2, 0, 3});
-
- // Expected results
- long[][] expectedTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 1, 1, 3 },
- new long[] { 1, 1, 4 },
- new long[] { 2, 2, 2 },
- new long[] { 3, 3, 3 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- };
-
- testTuples(expectedTuples, tuples);
- }
-
- /**
- * Test a constraint where the subject and object are the same.
- *
- * @throws Exception if query fails when it should have succeeded
- */
- public void testSubjectObject() throws Exception {
-
- // Not subject = 1.
- tuples = new StatementStoreDuplicateResolution(
- new boolean[] { true, false, true }, t4, new int[] { 0, 2, 1, 3});
-
- // Expected results
- long[][] expectedTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 1, 1, 3 },
- new long[] { 1, 1, 4 },
- new long[] { 2, 2, 2 },
- new long[] { 3, 3, 1 },
- new long[] { 3, 3, 3 },
- new long[] { 4, 4, 5 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- };
-
- testTuples(expectedTuples, tuples);
- }
-
- /**
- * Test a constraint where the subject, predicate and object are the same.
- *
- * @throws Exception if query fails when it should have succeeded
- */
- public void testSubjectPredicateObject() throws Exception {
-
- // Not subject = 1.
- tuples = new StatementStoreDuplicateResolution(
- new boolean[] { true, true, true }, t1, new int[] { 0, 1, 2, 3});
-
- // Expected results
- long[][] expectedTuples = new long[][] {
- new long[] { 1, 1, 1 },
- new long[] { 2, 2, 2 },
- new long[] { 3, 3, 3 },
- new long[] { 5, 5, 5 },
- new long[] { 6, 6, 6 },
- new long[] { 7, 7, 7 },
- };
-
- testTuples(expectedTuples, tuples);
-
- String[] vars1a = new String[] { "x", "y", "z" };
- Tuples t1a = new LiteralTuples(vars1a);
- long[][] t1aTuples = new long[][] {
- new long[] { 3897, 3906, 3906 },
- new long[] { 3897, 3908, 3908 },
- new long[] { 3899, 3892, 3900 },
- new long[] { 3900, 3892, 3894 },
- new long[] { 3906, 3892, 3894 },
- new long[] { 3906, 3892, 3907 },
- new long[] { 3906, 3906, 3906 },
- new long[] { 3908, 3892, 3896 },
- new long[] { 3908, 3892, 3908 },
- new long[] { 3908, 3908, 3894 },
- new long[] { 3908, 3908, 3908 },
- new long[] { 3910, 3892, 3902 },
- new long[] { 3910, 3910, 3910 },
- new long[] { 3911, 3892, 3904 },
- new long[] { 3911, 3892, 3911 },
- };
-
- for (int i = 0; i < t1aTuples.length; i++) {
- ((LiteralTuples) t1a).appendTuple(t1aTuples[i]);
- }
-
- tuples = new StatementStoreDuplicateResolution(new boolean[] { true, true, true},
- t1a, new int[] { 0, 1, 2, 3});
-
- expectedTuples = new long[][] {
- new long[] { 3906, 3906, 3906 },
- new long[] { 3908, 3908, 3908 },
- new long[] { 3910, 3910, 3910 },
- };
-
- testTuples(expectedTuples, tuples);
- }
-
- /**
- * Test that we have the expected number and values of Tuples.
- *
- * @throws Exception if query fails when it should have succeeded
- */
- public void testTuples(long[][] expectedTuples, Tuples result)
- throws Exception {
-
- assertTrue("Expected: " + expectedTuples.length + ", " +
- result.getRowCount(), expectedTuples.length == result.getRowCount());
-
- if (result.getRowCount() > 0) {
- result.beforeFirst();
- result.next();
-
- int index = 0;
- do {
-
- long tuple[] = new long[] {
- result.getColumnValue(0),
- result.getColumnValue(1),
- result.getColumnValue(2)
- };
-
- assertTrue("Expected tuple result: " + expectedTuples[index][0] + "," +
- expectedTuples[index][1] + "," +
- expectedTuples[index][2] + " but was: " + tuple[0] + "," + tuple[1] +
- "," + tuple[2],
- expectedTuples[index][0] == tuple[0] &&
- expectedTuples[index][1] == tuple[1] &&
- expectedTuples[index][2] == tuple[2]);
- index++;
- tuples.next();
- }
- while (index < expectedTuples.length);
-
- assertFalse("Should be no more result tuples", tuples.next());
- }
- }
-}
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreInverseResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,670 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s):
- * getModel() contributed by Netymon Pty Ltd on behalf of
- * The Australian Commonwealth Government under contract 4500507038.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-
-package org.mulgara.resolver.store;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Standard Java packages
-import java.util.*;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.tuples.AbstractTuples;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.Tuples;
-
-/**
- * Tuples backed by the graph, corresponding the tuples that don't match
- * a particular constraint. This class retains the original constraint so that
- * the graph index it's resolved against can be resolved anew as its variables
- * are bound.
- *
- * @created 2004-08-04
- *
- * @author Andrew Newman
- *
- * @version $Revision: 1.10 $
- *
- * @modified $Date: 2005/05/02 20:07:58 $ by $Author: raboczi $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
- * @company <a href="mailto:info at PIsoftware.com">Plugged In Software</a>
- *
- * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
- * Software Pty Ltd</A>
- *
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-class StatementStoreInverseResolution extends AbstractTuples implements Resolution {
-
- protected static final Logger logger = Logger.getLogger(StatementStoreInverseResolution.class);
-
- /**
- * The constraint these tuples were generated to satisfy.
- */
- protected Constraint constraint;
-
- /**
- * The graph from which these tuples were generated.
- */
- protected StatementStore store;
-
- /**
- * The tuples.
- */
- private Tuples tuples;
-
- /**
- * The long representation of the subject node or NodePool.NONE
- */
- private long subject;
-
- /**
- * The long representation of the predicate node or NodePool.NONE
- */
- private long predicate;
-
- /**
- * The long representation of the object node or NodePool.NONE
- */
- private long object;
-
- /**
- * The long representation of the meta node or NodePool.NONE
- */
- private long metanode;
-
- /**
- * Prefix. The prefix into the tuples to the section to exclude.
- */
- private long[] excludePrefix;
-
- /**
- * The not evaluator for a given tuples.
- */
- private TuplesEvaluator tuplesEvaluator;
-
- /**
- * Whether we've calculated the rows.
- */
- private boolean calculatedRowCount;
-
- /**
- * An array that contains the position in the tuples. Elements 0, 1, 2, 3
- * map to subject, predicate, object and meta and the value in the array is
- * the column position.
- */
- private int[] columnOrder;
-
- /**
- * True when we have skipped over the block in the store.
- */
- private boolean skipped = false;
-
- /**
- * True if all constraints are fixed.
- */
- private boolean allFixedConstraints;
-
- /**
- * True if a single statement given by the constraints exists.
- */
- private boolean singleStatementExists;
-
- /**
- * Used to force the tuples to act empty, used if beforeFirst is used with a bad prefix.
- */
- private boolean forceEmpty;
-
- /**
- * Find a graph index that satisfies a constraint.
- *
- * @param newConstraint the constraint to satisfy
- * @param newStore the store to resolve against
- * @throws IllegalArgumentException if <var>constraint</var> or <var>graph
- * </var> is <code>null</code>
- * @throws TuplesException EXCEPTION TO DO
- */
- StatementStoreInverseResolution(Constraint newConstraint, StatementStore newStore)
- throws TuplesException {
-
- if (newStore == null) {
- throw new IllegalArgumentException("Cannot give null statementstore");
- }
-
- constraint = newConstraint;
- store = newStore;
-
- subject = toGraphTuplesIndex(constraint.getElement(0));
- predicate = toGraphTuplesIndex(constraint.getElement(1));
- object = toGraphTuplesIndex(constraint.getElement(2));
- metanode = toGraphTuplesIndex(constraint.getModel());
-
- allFixedConstraints = (subject != NodePool.NONE) &&
- (predicate != NodePool.NONE) && (object != NodePool.NONE);
-
- forceEmpty = false;
-
- try {
-
- if (allFixedConstraints) {
- singleStatementExists = store.existsTriples(subject, predicate, object, metanode);
-
- // Return the tuples for a single model
- tuples = store.findTuples(false, false, false, true);
- tuples.beforeFirst(new long[] {metanode}, 0);
-
- } else {
-
- // Return the tuples using the s, p, o hints.
- tuples = store.findTuples(subject != NodePool.NONE,
- predicate != NodePool.NONE,
- object != NodePool.NONE,
- metanode != NodePool.NONE);
-
- if (metanode != NodePool.NONE) {
- // go to the beginning of the fixed model
- tuples.beforeFirst(new long[] {metanode}, 0);
- } else {
- // go to the beginning of all models
- tuples.beforeFirst();
- }
- }
-
- // Get the column order - this is column index -> tuples index we want
- // tuple index -> column index
- int[] inverseColumnOrder = ((StoreTuples) tuples).getColumnOrder();
-
- columnOrder = new int[4];
-
- // Create column map.
- for (int index = 0; index < inverseColumnOrder.length; index++) {
- columnOrder[inverseColumnOrder[index]] = index;
- }
-
- // Prepopulate variable list.
- List variableList = new ArrayList(Arrays.asList(StatementStore.VARIABLES));
- boolean changedList = false;
-
- // Create correct variable bindings in order.
- for (int index = 0; index < 4; index++) {
- if (constraint.getElement(index) instanceof Variable) {
- Variable var = (Variable) constraint.getElement(index);
- if (!var.equals(Variable.FROM)) {
-
- // Remove it from it's position in the list and re-add it with the
- // correct value.
- changedList = true;
- variableList.remove(columnOrder[index]);
- variableList.add(columnOrder[index], var);
- }
- }
- }
-
- setTuplesEvaluator();
- setVariables(variableList);
- }
- catch (StatementStoreException se) {
- throw new TuplesException("Failed to set-up tuples", se);
- }
-
- }
-
- /**
- * Create the appropriate tuples evaluator.
- */
- private void setTuplesEvaluator() {
-
- if (((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) ||
- ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) ||
- ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE))) {
- tuplesEvaluator = new SPOTuplesEvaluator();
-
- if ((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) {
- excludePrefix = new long[] { subject };
- }
- else if ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) {
- excludePrefix = new long[] { subject, predicate };
- }
- else if ((subject != NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE)) {
- excludePrefix = new long[] { subject, predicate, object };
- }
- }
- else if (((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) ||
- ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE))) {
- tuplesEvaluator = new POSTuplesEvaluator();
- if ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object == NodePool.NONE)) {
- excludePrefix = new long[] { predicate };
- }
- else if ((subject == NodePool.NONE) && (predicate != NodePool.NONE) && (object != NodePool.NONE)) {
- excludePrefix = new long[] { predicate, object };
- }
- }
- else if ((subject == NodePool.NONE) && (predicate == NodePool.NONE) && (object != NodePool.NONE)) {
- tuplesEvaluator = new OSPTuplesEvaluator();
- excludePrefix = new long[] { object };
- }
- else if ((subject != NodePool.NONE) && (predicate == NodePool.NONE) && (object != NodePool.NONE)) {
- tuplesEvaluator = new SOPTuplesEvaluator();
- excludePrefix = new long[] { subject, object };
- }
- else if ((subject == NodePool.NONE) && (predicate == NodePool.NONE) && (object == NodePool.NONE)) {
- tuplesEvaluator = new UnconstrainedTuplesEvaluator();
- excludePrefix = new long[] {};
- }
-
- // prepend the metanode if it is set
- if (metanode != NodePool.NONE) {
- long[] newPrefix = new long[excludePrefix.length + 1];
- newPrefix[0] = metanode;
- for (int i = 0; i < excludePrefix.length; i++) {
- newPrefix[i + 1] = excludePrefix[i];
- }
- excludePrefix = newPrefix;
- }
- }
-
- public long getRowCount() throws TuplesException {
-
- // Only calculate rows once.
- if (!calculatedRowCount) {
-
- // If the exclude prefix is more than just the model then calculate otherwise we've asked
- // for a NOT ($s $p $o) which is 0.
- if (excludePrefix.length > 1) {
-
- Tuples modelTuples = null;
- Tuples excludedTuples = null;
-
- try {
- // get all tuples in the model
- modelTuples = store.findTuples(NodePool.NONE, NodePool.NONE, NodePool.NONE, metanode);
-
- // get excluded tuples in the model
- excludedTuples = store.findTuples(subject, predicate, object, metanode);
-
- // Calculated the excluded set from the model.
- rowCount = modelTuples.getRowCount() - excludedTuples.getRowCount();
-
- } catch (StatementStoreException e) {
- throw new TuplesException("Unable to count data", e);
- } finally {
- try {
- if (modelTuples != null) {
- modelTuples.close();
- }
- } finally {
- if (excludedTuples != null) {
- excludedTuples.close();
- }
- }
- }
-
- } else {
- rowCount = 0;
- }
-
- // Ensure we don't calculate the rows again.
- calculatedRowCount = true;
- }
- return rowCount;
- }
-
- public boolean hasNoDuplicates() throws TuplesException {
- return tuples.hasNoDuplicates();
- }
-
- public List getOperands() {
- return new ArrayList();
- }
-
- public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
- if (prefix.length > 4) {
- throw new TuplesException("Prefix too long");
- }
-
- // Reset skipped.
- skipped = false;
- // Reset the forceEmpty flag
- forceEmpty = false;
-
- if (metanode != NodePool.NONE) {
- if (prefix.length > 0) {
- if (prefix[0] != metanode) {
- // no matching tuples
- forceEmpty = true;
- }
- } else {
- prefix = new long[] {metanode};
- }
- }
-
- // Move to the
- tuples.beforeFirst(prefix, suffixTruncation);
- }
-
- public void close() throws TuplesException {
- if (tuples != null) {
- tuples.close();
- }
- }
-
- /**
- * METHOD TO DO
- *
- * @return RETURNED VALUE TO DO
- */
- public Object clone() {
- StatementStoreInverseResolution cloned = (StatementStoreInverseResolution) super.clone();
- cloned.tuples = (Tuples) tuples.clone();
- cloned.setVariables(getVariables());
-
- // Create a new tuples evaluator.
- cloned.setTuplesEvaluator();
- return cloned;
- }
-
-
- public long getRowUpperBound() throws TuplesException {
- return getRowCount();
- }
-
- public int getRowCardinality() throws TuplesException {
- long count = getRowCount();
- if (count > 1) {
- return Cursor.MANY;
- }
- switch ((int) count) {
- case 0:
- return Cursor.ZERO;
- case 1:
- return Cursor.ONE;
- default:
- throw new TuplesException("Illegal row count: " + count);
- }
- }
-
- public long getColumnValue(int column) throws TuplesException {
- return tuples.getColumnValue(column);
- }
-
- public boolean isColumnEverUnbound(int column) throws TuplesException {
- return tuples.isColumnEverUnbound(column);
- }
-
- public boolean isUnconstrained() throws TuplesException {
-
- // If we have a least one variable return the tuples isUnconstrainedValue.
- if (!allFixedConstraints) {
- return tuples.isUnconstrained();
- }
- else {
-
- // If the statement exists we are constrained.
- if (singleStatementExists) {
- return false;
- }
- else {
- return true;
- }
- }
- }
-
- public boolean isMaterialized() {
- return tuples.isMaterialized();
- }
-
- public boolean next() throws TuplesException {
- boolean hasNext = false;
- if (!forceEmpty) {
- hasNext = tuplesEvaluator.next();
- }
- return hasNext;
- }
-
- /**
- * @return the original {@link Constraint} passed to the
- * {@link Resolver#resolve} method to generate this {@link Resolution}
- */
- public Constraint getConstraint() {
- return constraint;
- }
-
-
- /**
- * If a {@link Resolver} represents a closed world, it may assert that the
- * {@link Resolution} contains every possible solution.
- *
- * @return whether this {@link Resolution} includes every solution to the constraint
- */
- public boolean isComplete() {
- return true;
- }
-
-
- public String toString() {
- return "not " + tuples.toString() + " from constraint " + constraint;
- }
-
- /**
- * Returns the long representation of the constraint element or
- * NodePool.NONE if a variable.
- *
- * @param constraintElement the constraint element to resolve.
- * @throws TuplesException if the constraint element is not supported.
- * @return long the long representation of the constraint element.
- */
- protected static long toGraphTuplesIndex(ConstraintElement constraintElement)
- throws TuplesException {
- if (constraintElement instanceof Variable) {
- return NodePool.NONE;
- }
- if (constraintElement instanceof LocalNode) {
- return ((LocalNode) constraintElement).getValue();
- }
-
- throw new TuplesException("Unsupported constraint element: " +
- constraintElement + " (" + constraintElement.getClass() + ")");
- }
-
- /**
- * A decorator around the next() method on a tuples that skips a set of
- * statements if they are given in the constraint.
- */
- private interface TuplesEvaluator {
-
- /**
- * Returns true if there is another tuples. Calling next may skip a set
- * of tuples based on the constraint.
- *
- * @throws TuplesException if there was a problem accessing the tuples.
- * @return true if there is another tuples.
- */
- public boolean next() throws TuplesException;
- }
-
- /**
- * The evaluator for the S, P, O constrained tuples.
- */
- private class SPOTuplesEvaluator implements TuplesEvaluator {
-
- public boolean next() throws TuplesException {
-
- // Iterate forward one.
- boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
- // If we've skipped over the tuples then just call the normal tuples.next.
- if (!skipped) {
-
- // Assume that the subject is always bound - otherwise wouldn't be used.
- // If the predicate is also constrained iterate through these.
- if (predicate != NodePool.NONE) {
-
- // If the predicate is also constrained iterate through these.
- if (object != NodePool.NONE) {
-
- // If we match then skip over the totally constrained tuple.
- if ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[0]) == subject) &&
- (tuples.getColumnValue(columnOrder[1]) == predicate) &&
- (tuples.getColumnValue(columnOrder[2]) == object)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- else {
-
- // Skip over all the objects for the given subject, predicate.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[0]) == subject) &&
- (tuples.getColumnValue(columnOrder[1]) == predicate)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- }
- else {
-
- // Skip over all the predicate, objects for the given subject.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[0]) == subject)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- }
- return moreTuples;
- }
- }
-
- /**
- * The evaluator for the P, O, S constrained tuples.
- */
- private class POSTuplesEvaluator implements TuplesEvaluator {
-
- public boolean next() throws TuplesException {
-
- // Iterate forward one.
- boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
- // If we've skipped over the tuples then just call the normal tuples.next.
- if (!skipped) {
-
- // If the object is also constrained iterate through these.
- if (object != NodePool.NONE) {
-
- // Skip over all the subjects for the given predicate, objects.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[1]) == predicate) &&
- (tuples.getColumnValue(columnOrder[2]) == object)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- else {
-
- // Skip over all the object, subjects for the given predicate.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[1]) == predicate)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- }
- return moreTuples;
- }
- }
-
- /**
- * The evaluator for the O, S, P constrained tuples.
- */
- private class OSPTuplesEvaluator implements TuplesEvaluator {
-
- public boolean next() throws TuplesException {
-
- // Iterate forward one.
- boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
- // If we've skipped over the tuples then just call the normal tuples.next.
- if (!skipped) {
-
- // Skip over all the subject, predicates for the given object.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[2]) == object)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- return moreTuples;
- }
- }
-
- /**
- * The evaluator for the S, O, P constrained tuples.
- */
- private class SOPTuplesEvaluator implements TuplesEvaluator {
-
- public boolean next() throws TuplesException {
-
- // Iterate forward one.
- boolean moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
-
- // If we've skipped over the tuples then just call the normal tuples.next.
- if (!skipped) {
-
- // Skip over all the subject, predicates for the given object.
- while ((moreTuples) &&
- (tuples.getColumnValue(columnOrder[0]) == subject) &&
- (tuples.getColumnValue(columnOrder[2]) == object)) {
- moreTuples = tuples.next() && tuples.getColumnValue(columnOrder[3]) == metanode;
- skipped = true;
- }
- }
- return moreTuples;
- }
- }
-
- /**
- * The evaluator when none of the tuples are constrained.
- */
- private class UnconstrainedTuplesEvaluator implements TuplesEvaluator {
-
- public boolean next() throws TuplesException {
- return false;
- }
- }
-}
Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolution.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -40,8 +40,6 @@
// Locally written packages
import org.mulgara.query.*;
import org.mulgara.resolver.spi.ReresolvableResolution;
-import org.mulgara.resolver.spi.Resolution;
-import org.mulgara.resolver.spi.Resolver;
import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.statement.StatementStore;
import org.mulgara.store.statement.StatementStoreException;
@@ -241,6 +239,7 @@
/**
* @param bound constraints to be bound post-beforeFirst. In constraint-order.
*/
+ @SuppressWarnings("unchecked")
protected void defineIndex(boolean[] bound) throws TuplesException {
assert bound.length == 4;
@@ -254,8 +253,7 @@
if (indexedTuples != null) {
if (logger.isDebugEnabled()) {
- logger.debug("Orig indexedTuples.variables = " +
- toString(indexedTuples.getVariables()));
+ logger.debug("Orig indexedTuples.variables = " + toString(indexedTuples.getVariables()));
}
indexedTuples.close();
}
@@ -352,14 +350,14 @@
}
- public ReresolvableResolution reresolve(final Map bindings) throws TuplesException {
+ public ReresolvableResolution reresolve(final Map<? extends ConstraintElement, Long> bindings) throws TuplesException {
boolean reconstrain = false;
ConstraintElement[] e = new ConstraintElement[4];
for (int i = 0; i < 4; i++) {
e[i] = constraint.getElement(i);
if (e[i] instanceof Variable) {
- Long value = (Long)bindings.get(e[i]);
+ Long value = bindings.get(e[i]);
if (value != null) {
e[i] = new LocalNode(value.longValue());
reconstrain = true;
@@ -445,8 +443,8 @@
}
- public List getOperands() {
- return Collections.EMPTY_LIST;
+ public List<Tuples> getOperands() {
+ return Collections.emptyList();
}
@@ -557,17 +555,17 @@
return this;
}
- public Annotation getAnnotation(Class annotation) {
+ public Annotation getAnnotation(Class<? extends Annotation> annotation) {
if (annotation.equals(DefinablePrefixAnnotation.class)) {
return new DefinablePrefixAnnotation() {
- public void definePrefix(Set boundVars) throws TuplesException {
+ public void definePrefix(Set<Variable> boundVars) throws TuplesException {
boolean[] bound = new boolean[4];
Constraint constraint = getConstraint();
for (int i = 0; i < 4; i++) {
ConstraintElement elem = constraint.getElement(i);
if (elem instanceof LocalNode) {
bound[i] = true;
- } else if (boundVars.contains((Variable)elem)) {
+ } else if (boundVars.contains(elem)) {
bound[i] = true;
} else {
bound[i] = false;
Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolver.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -355,7 +355,7 @@
if (occurs) {
// statement is asserted to be true
- logger.debug("Inserting statement: [" + subject + " "
+ if (logger.isDebugEnabled()) logger.debug("Inserting statement: [" + subject + " "
+ predicate + " "
+ object + "] in " + model);
@@ -391,8 +391,6 @@
if (!constraint.isRepeating()) {
if (constraint instanceof ConstraintImpl) {
return new StatementStoreResolution(constraint, statementStore);
- } else if (constraint instanceof ConstraintNegation) {
- return new StatementStoreInverseResolution(constraint, statementStore);
} else {
throw new QueryException("Unable to resolve constraint " + constraint + " unknown type");
}
@@ -526,4 +524,11 @@
}
}
+ /**
+ * @see org.mulgara.resolver.spi.SystemResolver#initializeSystemNodes(long, long, long)
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ statementStore.initializeSystemNodes(systemGraphNode, rdfTypeNode, systemGraphTypeNode);
+ }
+
}
Modified: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/StatementStoreResolverFactory.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -71,9 +71,9 @@
private long rdfType;
/** The underlying transactional graph that backs the generated resolvers. */
- private final XAStatementStore statementStore;
+ protected final XAStatementStore statementStore;
- private XAResolverSessionFactory resolverSessionFactory;
+ protected XAResolverSessionFactory resolverSessionFactory;
//
// Constructors
@@ -86,7 +86,7 @@
* @throws IllegalArgumentException {@inheritDoc}
* @throws ResolverException {@inheritDoc}
*/
- private StatementStoreResolverFactory(FactoryInitializer initializer,
+ protected StatementStoreResolverFactory(FactoryInitializer initializer,
XAResolverSessionFactory resolverSessionFactory) throws
InitializerException {
// Validate parameters
@@ -96,7 +96,7 @@
try {
File filePrefix = new File(initializer.getDirectory(), "xa");
- statementStore = new XAStatementStoreImpl(filePrefix.toString());
+ statementStore = createStore(filePrefix.toString());
resolverSessionFactory.registerStatementStore(statementStore);
} catch (Exception e) {
throw new InitializerException("Couldn't initialize XA store", e);
@@ -238,4 +238,15 @@
"Failed to obtain a new ResolverSession", er);
}
}
+
+
+ /**
+ * Creates the required type of store
+ * @param filePrefix The base for the files being used for storage.
+ * @return a new instance of an XAStatementStore
+ * @throws IOException Error accessing the filesystem
+ */
+ protected XAStatementStore createStore(String filePrefix) throws IOException {
+ return new XAStatementStoreImpl(filePrefix.toString());
+ }
}
Copied: trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/resolver/store/XA11StatementStoreResolverFactory.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,64 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.resolver.store;
+
+import java.io.IOException;
+
+import org.mulgara.resolver.spi.FactoryInitializer;
+import org.mulgara.resolver.spi.InitializerException;
+import org.mulgara.resolver.spi.ResolverFactory;
+import org.mulgara.store.statement.xa11.XA11StatementStoreImpl;
+import org.mulgara.store.xa.XAResolverSessionFactory;
+import org.mulgara.store.xa.XAStatementStore;
+
+/**
+ * An extension of StatementStoreResolverFactory which instantiates an XA 1.1 statement store.
+ *
+ * @created Oct 1, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class XA11StatementStoreResolverFactory extends StatementStoreResolverFactory {
+
+ /**
+ * Internal construction of a resolver factory.
+ * @throws InitializerException Unable to initialize.
+ */
+ protected XA11StatementStoreResolverFactory(FactoryInitializer initializer,
+ XAResolverSessionFactory resolverSessionFactory) throws InitializerException {
+ super(initializer, resolverSessionFactory);
+ }
+
+ /**
+ * Factory method for instances of this factory
+ * @param initializer Configuration object for this factory.
+ * @param resolverSessionFactory A factory that this factory can proxy for getting sessions.
+ * @return A new factory for resolver sessions.
+ * @throws InitializerException The factory could not be initialized.
+ */
+ public static ResolverFactory newInstance(FactoryInitializer initializer,
+ XAResolverSessionFactory resolverSessionFactory) throws InitializerException {
+ return new XA11StatementStoreResolverFactory(initializer, resolverSessionFactory);
+ }
+
+ /**
+ * Creates the required type of store
+ * @param filePrefix The base for the files being used for storage.
+ * @return a new instance of an XAStatementStore
+ * @throws IOException Error accessing the filesystem
+ */
+ protected XAStatementStore createStore(String filePrefix) throws IOException {
+ return new XA11StatementStoreImpl(filePrefix.toString());
+ }
+}
Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/TripleAVLFile.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -413,7 +413,7 @@
* Inner class to compare two triples in an int buffer, using a given ordering
* for each of the node columns.
*/
- private final static class TripleComparator implements Comparator {
+ private final static class TripleComparator implements Comparator<Object> {
private int offset;
@@ -539,6 +539,7 @@
HEADER_SIZE + AVLFile.Phase.RECORD_SIZE +
ManagedBlockFile.Phase.RECORD_SIZE;
+ @SuppressWarnings("unused")
private final static int IDX_NR_FILE_TRIPLES = 0;
private long nrFileTriples;
@@ -977,7 +978,7 @@
node, node.getNextNode()
};
}
- int li = avlFile.leafIndex(findResult);
+ int li = AVLFile.leafIndex(findResult);
findResult[li].insert(newNode, 1 - li);
if (index == MAX_TRIPLES || index > splitPoint) {
@@ -1189,6 +1190,39 @@
}
+ public StoreTuples findTuplesForMeta(long graph) throws IOException {
+ long[] startTriple = new long[SIZEOF_TRIPLE];
+ long[] endTriple = new long[SIZEOF_TRIPLE];
+ startTriple[order0] = graph;
+ endTriple[order0] = graph + 1;
+ return new MetaTuplesImpl(startTriple, endTriple, 1);
+ }
+
+
+ public StoreTuples findTuplesForMeta(long graph, long node1) throws IOException {
+ long[] startTriple = new long[SIZEOF_TRIPLE];
+ long[] endTriple = new long[SIZEOF_TRIPLE];
+ startTriple[order0] = graph;
+ startTriple[order1] = node1;
+ endTriple[order0] = graph;
+ endTriple[order1] = node1 + 1;
+ return new MetaTuplesImpl(startTriple, endTriple, 2);
+ }
+
+
+ public StoreTuples findTuplesForMeta(long graph, long node1, long node2) throws IOException {
+ long[] startTriple = new long[SIZEOF_TRIPLE];
+ long[] endTriple = new long[SIZEOF_TRIPLE];
+ startTriple[order0] = graph;
+ startTriple[order1] = node1;
+ startTriple[order2] = node2;
+ endTriple[order0] = graph;
+ endTriple[order1] = node1;
+ endTriple[order2] = node2 + 1;
+ return new MetaTuplesImpl(startTriple, endTriple, 3);
+ }
+
+
public StoreTuples allTuples() {
return new TuplesImpl();
}
@@ -1386,7 +1420,7 @@
}
- long checkIntegrity() {
+ public long checkIntegrity() {
if (this == currentPhase && tripleWriteThread != null)
tripleWriteThread.drain();
@@ -1661,12 +1695,11 @@
}
- private final class TuplesImpl implements StoreTuples {
+ private abstract class AbstractStoreTuples implements StoreTuples {
// keep a stack trace of the instantiation of this object
- @SuppressWarnings("unused")
- private StackTrace stack = logger.isDebugEnabled() ? new StackTrace() : null;
- private List<Integer> objectIds = new ArrayList<Integer>();
+ protected StackTrace stack = logger.isDebugEnabled() ? new StackTrace() : null;
+ protected List<Integer> objectIds = new ArrayList<Integer>();
private long[] startTriple;
@@ -1676,7 +1709,7 @@
private TripleLocation end;
- private Token token;
+ protected Token token;
private long nrTriples;
@@ -1685,21 +1718,21 @@
@SuppressWarnings("unused")
private int prefixLength;
- private int[] columnMap;
+ protected int[] columnMap;
- private Variable[] variables;
+ protected Variable[] variables;
private long[] tmpTriple = new long[SIZEOF_TRIPLE];
- private AVLNode node;
+ protected AVLNode node;
- private boolean beforeStart;
+ protected boolean beforeStart;
private int nrBlockTriples = 0;
- private Block tripleBlock = null;
+ protected Block tripleBlock = null;
- private int offset;
+ protected int offset;
private long endBlockId = Block.INVALID_BLOCK_ID;
@@ -1717,7 +1750,7 @@
* @param prefixLength PARAMETER TO DO
* @throws IOException EXCEPTION TO DO
*/
- TuplesImpl(
+ AbstractStoreTuples(
long[] startTriple, long[] endTriple,
int prefixLength
) throws IOException {
@@ -1729,19 +1762,6 @@
this.endTriple = endTriple;
this.prefixLength = prefixLength;
- int nrColumns = SIZEOF_TRIPLE - prefixLength;
-
- // Set up a column order which moves the prefix columns to the end.
- columnMap = new int[nrColumns];
- for (int i = 0; i < nrColumns; ++i) {
- columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
- }
-
- variables = new Variable[nrColumns];
- for (int i = 0; i < nrColumns; ++i) {
- variables[i] = StatementStore.VARIABLES[columnMap[i]];
- }
-
start = findTriple(startTriple);
end = findTriple(endTriple);
@@ -1761,7 +1781,7 @@
/**
* CONSTRUCTOR TuplesImpl TO DO
*/
- TuplesImpl() {
+ AbstractStoreTuples() {
if (Phase.this == currentPhase && tripleWriteThread != null) tripleWriteThread.drain();
this.nrTriples = Phase.this.nrFileTriples;
@@ -1898,8 +1918,8 @@
}
- public List getOperands() {
- return new ArrayList(0);
+ public List<Tuples> getOperands() {
+ return Collections.emptyList();
}
@@ -2057,7 +2077,7 @@
public Object clone() {
try {
- TuplesImpl copy = (TuplesImpl) super.clone();
+ AbstractStoreTuples copy = (AbstractStoreTuples) super.clone();
tmpTriple = new long[SIZEOF_TRIPLE];
if (start != null) {
start.node.incRefCount();
@@ -2220,11 +2240,100 @@
/**
* Copied from AbstractTuples
*/
- public Annotation getAnnotation(Class annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
+ /**
+ * The standard implementation of the StoreTuples for this phase.
+ */
+ private final class TuplesImpl extends AbstractStoreTuples {
+ TuplesImpl(long[] startTriple, long[] endTriple, int prefixLength) throws IOException {
+ super(startTriple, endTriple, prefixLength);
+ int nrColumns = SIZEOF_TRIPLE - prefixLength;
+
+ variables = new Variable[nrColumns];
+ // Set up a column order which moves the prefix columns to the end.
+ columnMap = new int[nrColumns];
+
+ for (int i = 0; i < nrColumns; ++i) {
+ columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
+ variables[i] = StatementStore.VARIABLES[columnMap[i]];
+ }
+
+ }
+
+ TuplesImpl() {
+ super();
+ }
+ }
+
+ /**
+ * A version of StoreTuples which is designed to set the Meta variable to a requested value.
+ *
+ * @created Dec 22, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+ private final class MetaTuplesImpl extends AbstractStoreTuples {
+
+ /** The meta node this tuples comes from. */
+ private final long metaNode;
+
+ /**
+ * Constructs the Tuples to come from the store.
+ * @param startTriple The first triple for this tuples.
+ * @param endTriple The first triple pattern that is NOT part of this tuples.
+ * This may not appear in the store, but if anything is <= this triple
+ * then it is NOT in the tuples.
+ * @param prefixLength The number of elements used to identify the requires triples.
+ * @throws IOException If there was an I/O error accessing the triples data in the store.
+ */
+ MetaTuplesImpl(long[] startTriple, long[] endTriple, int prefixLength) throws IOException {
+ super(startTriple, endTriple, prefixLength);
+ int nrColumns = SIZEOF_TRIPLE - prefixLength;
+ variables = new Variable[nrColumns + 1];
+
+ // Set up a column order which moves the prefix columns to the end.
+ columnMap = new int[nrColumns + 1];
+
+ for (int i = 0; i < nrColumns; ++i) {
+ columnMap[i] = sortOrder[(i + prefixLength) % SIZEOF_TRIPLE];
+ variables[i] = StatementStore.VARIABLES[columnMap[i]];
+ }
+ // make the last variable "Meta"
+ columnMap[nrColumns] = nrColumns;
+ variables[nrColumns] = StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1];
+ metaNode = startTriple[order0];
+ }
+
+ /**
+ * Get the value from the given column on the current row.
+ * @param column The column to get the value of the binding from.
+ * @return The binding for the given column on the current row.
+ * @throws TuplesException If the current state is wrong, or if the column requested is invalid.
+ */
+ public long getColumnValue(int column) throws TuplesException {
+ if (column == variables.length - 1) return metaNode;
+ // inlining rather than calling to super
+ try {
+ return tripleBlock.getLong(offset * SIZEOF_TRIPLE + columnMap[column]);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ if (column < 0 || column >= variables.length) {
+ throw new TuplesException("Column index out of range: " + column);
+ }
+ throw ex;
+ } catch (NullPointerException ex) {
+ if (beforeStart || node == null) {
+ throw new TuplesException("No current row. Before start: " + beforeStart + " node: " + node);
+ }
+ throw ex;
+ }
+ }
+
+ }
}
}
Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImpl.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -37,7 +37,6 @@
// Locally written packages
import org.mulgara.query.*;
-import org.mulgara.store.*;
import org.mulgara.store.nodepool.*;
import org.mulgara.store.statement.*;
import org.mulgara.store.tuples.StoreTuples;
@@ -293,7 +292,7 @@
/**
* Description of the Field
*/
- private List releaseNodeListeners = new ArrayList();
+ private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
//private XANodePoolImpl nodePool = null;
@@ -1148,11 +1147,7 @@
* @throws Exception EXCEPTION TO DO
*/
private void notifyReleaseNodeListeners(long node) throws Exception {
- Iterator it = releaseNodeListeners.iterator();
- while (it.hasNext()) {
- ReleaseNodeListener l = (ReleaseNodeListener) it.next();
- l.releaseNode(node);
- }
+ for (ReleaseNodeListener l: releaseNodeListeners) l.releaseNode(node);
}
@@ -1463,6 +1458,14 @@
public int getPhaseNumber() {
return phaseNumber;
}
+
+
+ /**
+ * Ignored for this implementation.
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ // do nothing
+ }
}
@@ -1967,4 +1970,12 @@
}
+
+ /**
+ * Ignored for this implementation.
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ // do nothing
+ }
+
}
Modified: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa/XAStatementStoreImplUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -39,6 +39,7 @@
// locally written packages
import org.mulgara.store.nodepool.*;
import org.mulgara.store.statement.*;
+import org.mulgara.store.tuples.TestTuples;
import org.mulgara.util.*;
@@ -195,4 +196,21 @@
}
super.tearDown();
}
+
+
+ /**
+ * Return a dump of all tuples, sorted by the primary index: 0123.
+ * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
+ */
+ protected TestTuples getDump() {
+ TestTuples expected = new TestTuples();
+ add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
+ add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
+ add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
+ add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ return expected;
+ }
+
}
Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11 (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11)
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,61 +0,0 @@
-/*
- * The contents of this file are subject to the Open Software License
- * Version 3.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.opensource.org/licenses/osl-3.0.txt
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- */
-
-package org.mulgara.store.statement.xa11;
-
-import org.mulgara.query.TuplesException;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.tuples.LiteralTuples;
-import org.mulgara.store.tuples.StoreTuples;
-
-/**
- * A Tuples for representing a specified Graph.
- *
- * @created Jan 14, 2009
- * @author Paul Gearon
- * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
- * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
- */
-public class LiteralGraphTuples extends LiteralTuples implements StoreTuples {
-
- static final String[] META_NAMES = new String[] { StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1].getName() };
-
- /**
- * Creates a new literal tuples containing graphs.
- * @param sorted
- */
- public LiteralGraphTuples(boolean sorted) {
- super(META_NAMES, sorted);
- }
-
- /**
- * Creates a new literal tuples containing graphs.
- * @param sorted
- */
- public LiteralGraphTuples(long graph) {
- super(META_NAMES, true);
- try {
- appendTuple(new long[] { graph });
- } catch (TuplesException te) {
- // should not happen
- throw new AssertionError("Unable to add an element to an array");
- }
- }
-
- /**
- * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
- */
- public int[] getColumnOrder() {
- return new int[] { 0 };
- }
-
-}
Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/LiteralGraphTuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,61 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.store.statement.xa11;
+
+import org.mulgara.query.TuplesException;
+import org.mulgara.store.statement.StatementStore;
+import org.mulgara.store.tuples.LiteralTuples;
+import org.mulgara.store.tuples.StoreTuples;
+
+/**
+ * A Tuples for representing a specified Graph.
+ *
+ * @created Jan 14, 2009
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class LiteralGraphTuples extends LiteralTuples implements StoreTuples {
+
+ static final String[] META_NAMES = new String[] { StatementStore.VARIABLES[StatementStore.VARIABLES.length - 1].getName() };
+
+ /**
+ * Creates a new literal tuples containing graphs.
+ * @param sorted
+ */
+ public LiteralGraphTuples(boolean sorted) {
+ super(META_NAMES, sorted);
+ }
+
+ /**
+ * Creates a new literal tuples containing graphs.
+ * @param sorted
+ */
+ public LiteralGraphTuples(long graph) {
+ super(META_NAMES, true);
+ try {
+ appendTuple(new long[] { graph });
+ } catch (TuplesException te) {
+ // should not happen
+ throw new AssertionError("Unable to add an element to an array");
+ }
+ }
+
+ /**
+ * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
+ */
+ public int[] getColumnOrder() {
+ return new int[] { 0 };
+ }
+
+}
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,1796 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-package org.mulgara.store.statement.xa11;
-
-import java.io.*;
-import java.nio.*;
-
-// Java 2 standard packages
-import java.util.*;
-
-// Third party packages
-import org.apache.log4j.Logger;
-
-// Locally written packages
-import org.mulgara.query.*;
-import org.mulgara.store.nodepool.*;
-import org.mulgara.store.statement.*;
-import org.mulgara.store.statement.xa.TripleAVLFile;
-import org.mulgara.store.tuples.StoreTuples;
-import org.mulgara.store.tuples.TuplesOperations;
-import org.mulgara.store.xa.AbstractBlockFile;
-import org.mulgara.store.xa.Block;
-import org.mulgara.store.xa.BlockFile;
-import org.mulgara.store.xa.LockFile;
-import org.mulgara.store.xa.PersistableMetaRoot;
-import org.mulgara.store.xa.SimpleXAResourceException;
-import org.mulgara.store.xa.XAStatementStore;
-import org.mulgara.store.xa.XAUtils;
-import org.mulgara.util.Constants;
-
-/**
- * An implementation of {@link StatementStore}.
- *
- * @created 2008-09-30
- * @author Paul Gearon
- * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- * @copyright ©2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public final class XA11StatementStoreImpl implements XAStatementStore {
-
- /** Logger. */
- private final static Logger logger = Logger.getLogger(XA11StatementStoreImpl.class);
-
- /** The value of the invalid gNode */
- final static long NONE = NodePool.NONE;
-
- /** The subject/predicate/object index */
- final static int TI_3012 = 0;
-
- /** The predicate/object/subject index */
- final static int TI_3120 = 1;
-
- /** The object/subject/predicate index */
- final static int TI_3201 = 2;
-
- /** The number of indexes */
- final static int NR_INDEXES = 3;
-
- /** The ordering of indexes, as indexed by the TI_ values */
- private final static int[][] orders = {
- {3, 0, 1, 2}, // TI_3012
- {3, 1, 2, 0}, // TI_3120
- {3, 2, 0, 1} // TI_3201
- };
-
- private final static int[] selectIndex = {
- /* 3XXX */ TI_3012,
- /* 3XX0 */ TI_3012,
- /* 3X1X */ TI_3120,
- /* 3X10 */ TI_3012,
- /* 32XX */ TI_3201,
- /* 32X0 */ TI_3201,
- /* 321X */ TI_3120,
- /* 3210 */ TI_3012
- };
-
- /** A number to identify the correct file type */
- private final static int FILE_MAGIC = 0xa5e7f21e;
-
- /** The version of file format */
- private final static int FILE_VERSION = 9;
-
- /** Index of the file magic number within each of the two on-disk metaroots. */
- private final static int IDX_MAGIC = 0;
-
- /** Index of the file version number within each of the two on-disk metaroots. */
- private final static int IDX_VERSION = 1;
-
- /** Index of the valid flag (in ints) within each of the two on-disk metaroots. */
- private final static int IDX_VALID = 2;
-
- /** The index of the phase number in the on-disk phase. */
- private final static int IDX_PHASE_NUMBER = 3;
-
- /** The size of the header of a metaroot in ints. */
- private final static int HEADER_SIZE_INTS = 4;
-
- /** The size of the header of a metaroot in longs. */
- private final static int HEADER_SIZE_LONGS = (HEADER_SIZE_INTS + 1) / 2;
-
- /** The size of a metaroot in longs. */
- private final static int METAROOT_SIZE = HEADER_SIZE_LONGS + Phase.RECORD_SIZE;
-
- /** The number of metaroots in the metaroot file. */
- private final static int NR_METAROOTS = 2;
-
- /** The mask for a bound Subject */
- private final static int MASK0 = 1;
-
- /** The mask for a bound Predicate */
- private final static int MASK1 = 2;
-
- /** The mask for a bound Object */
- private final static int MASK2 = 4;
-
- /** The mask for a bound Graph. This must always be set. */
- private final static int MASK3 = 8;
-
- /** The node number for the system graph. Globalized to <#>. */
- private long systemGraphNode = NONE;
-
- /** The node number for <rdf:type>. */
- private long rdfTypeNode = NONE;
-
- /** The node number for the graph class <mulgara:ModelType>. */
- private long graphTypeNode = NONE;
-
- /** The name of the triple store which forms the base name for the graph files. */
- private String fileName;
-
- /** The LockFile that protects the graph from being opened twice. */
- private LockFile lockFile;
-
- /** The BlockFile for the node pool metaroot file. */
- private BlockFile metarootFile = null;
-
- /** The metaroot blocks of the metaroot file. */
- private Block[] metarootBlocks = new Block[NR_METAROOTS];
-
- /** An error flag that is set during file initialization if the file version is incorrect */
- private boolean wrongFileVersion = false;
-
- /** The files containing indexed triples */
- private TripleAVLFile[] tripleAVLFiles = new TripleAVLFile[NR_INDEXES];
-
- /** The current read/write phase. Only the latest phase can write. */
- private Phase currentPhase = null;
-
- /**
- * Determines if modifications can be performed without creating a new
- * (in-memory) phase. If dirty is false and the current phase is in use (by
- * unclosed Tupleses) then a new phase must be created to protect the existing
- * Tupleses before any further modifications are made.
- */
- private boolean dirty = true;
-
- /**
- * The index of the phase in the metaroot. May be 0 or 1 as the commited phase swaps
- * between the two metaroots.
- */
- private int phaseIndex = 0;
-
- /** The number of the current phase */
- private int phaseNumber = 0;
-
- /** A reference token for keeping the commited phase available until we no longer need it */
- private Phase.Token committedPhaseToken = null;
-
- /** A synchronization object for locking access to the committed phase */
- private Object committedPhaseLock = new Object();
-
- /** A reference token for keeping the recording phase available until we no longer need it */
- private Phase.Token recordingPhaseToken = null;
-
- /** The list of graphs known to this statement store. */
- private List<Long> committedGraphNodes;
-
- /**
- * This flag indicates that the current object has been fully written, and may be considered
- * as committed when the rest of the system is ready.
- */
- private boolean prepared = false;
-
- /** A set of objects to be informed when nodes are released. */
- private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
-
-
- /**
- * Creates a statement store using a base filename.
- *
- * @param fileName The base filename to operate from.
- * @throws IOException The mass storage could not be accessed.
- */
- public XA11StatementStoreImpl(String fileName) throws IOException {
- this.fileName = fileName;
-
- lockFile = LockFile.createLockFile(fileName + ".g.lock");
-
- try {
- // Check that the metaroot file was created with a compatible version of the triplestore.
- RandomAccessFile metarootRAF = null;
- try {
- metarootRAF = new RandomAccessFile(fileName + ".g", "r");
- if (metarootRAF.length() >= 2 * Constants.SIZEOF_INT) {
- int fileMagic = metarootRAF.readInt();
- int fileVersion = metarootRAF.readInt();
- if (AbstractBlockFile.byteOrder != ByteOrder.BIG_ENDIAN) {
- fileMagic = XAUtils.bswap(fileMagic);
- fileVersion = XAUtils.bswap(fileVersion);
- }
- wrongFileVersion = fileMagic != FILE_MAGIC || fileVersion != FILE_VERSION;
- } else {
- wrongFileVersion = false;
- }
- } catch (FileNotFoundException ex) {
- wrongFileVersion = false;
- } finally {
- if (metarootRAF != null) metarootRAF.close();
- }
-
- for (int i = 0; i < NR_INDEXES; ++i) {
- String suffix = ".g_" + orders[i][0] + orders[i][1] + orders[i][2] + orders[i][3];
- tripleAVLFiles[i] = new TripleAVLFile(fileName + suffix, orders[i]);
- }
- } catch (IOException ex) {
- try {
- close();
- } catch (StatementStoreException ex2) { /* no-op */ }
- throw ex;
- }
- }
-
-
- /**
- * Returns <code>true</code> if there are no triples in the graph
- * @return <code>true</code> if there are no triples in the graph
- */
- public synchronized boolean isEmpty() {
- checkInitialized();
- return currentPhase.isEmpty();
- }
-
-
- /**
- * Returns a count of the number of triples in the graph
- * @return a count of the number of triples in the graph
- */
- public synchronized long getNrTriples() {
- checkInitialized();
- return currentPhase.getNrTriples();
- }
-
-
- /**
- * Gets the PhaseNumber attribute of the XAGraphImpl object
- * @return The PhaseNumber value
- */
- public synchronized int getPhaseNumber() {
- checkInitialized();
- return phaseNumber;
- }
-
-
- /**
- * Adds a feature to the ReleaseNodeListener attribute of the XAGraphImpl object
- * @param l The feature to be added to the ReleaseNodeListener attribute
- */
- public synchronized void addReleaseNodeListener(ReleaseNodeListener l) {
- if (!releaseNodeListeners.contains(l)) releaseNodeListeners.add(l);
- }
-
-
- /**
- * Removes a release node listener.
- * @param l The listener to remove.
- */
- public synchronized void removeReleaseNodeListener(ReleaseNodeListener l) {
- releaseNodeListeners.remove(l);
- }
-
-
- /**
- * Adds a new triple to the graph if it doesn't already exist.
- * @param node0 the first element of the new triple
- * @param node1 the second element of the new triple
- * @param node2 the third element of the new triple
- * @param node3 the fourth element of the new triple
- * @throws StatementStoreException Due to structural or IO errors.
- */
- public synchronized void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
- checkInitialized();
- if (
- node0 < NodePool.MIN_NODE ||
- node1 < NodePool.MIN_NODE ||
- node2 < NodePool.MIN_NODE ||
- node3 < NodePool.MIN_NODE
- ) {
- throw new StatementStoreException(
- "Attempt to add a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3
- );
- }
-
- if (!dirty && currentPhase.isInUse()) {
- try {
- new Phase();
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
- currentPhase.addTriple(node0, node1, node2, node3);
- }
-
-
- /**
- * Removes all triples matching the given specification.
- * @param node0 the value for the first element of the triples
- * @param node1 the value for the second element of the triples
- * @param node2 the value for the third element of the triples
- * @param node3 the value for the fourth element of the triples
- * @throws StatementStoreException if something exceptional happens
- */
- public synchronized void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- checkInitialized();
- if (node0 != NONE && node1 != NONE && node2 != NONE && node3 != NONE) {
- if (!dirty && currentPhase.isInUse()) {
- try {
- new Phase();
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
- // Remove the triple.
- currentPhase.removeTriple(node0, node1, node2, node3);
- } else {
- // Find all the tuples matching the specification and remove them.
- StoreTuples tuples = currentPhase.findTuples(node0, node1, node2, node3);
- try {
- try {
- if (!tuples.isEmpty()) {
- // There is at least one triple to remove so protect the
- // Tuples as we make changes to the triplestore.
- try {
- new Phase();
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
-
- long[] triple = new long[] { node0, node1, node2, node3 };
- int[] columnMap = tuples.getColumnOrder();
- int nrColumns = columnMap.length;
- tuples.beforeFirst();
- while (tuples.next()) {
- // Copy the row data over to the triple.
- for (int col = 0; col < nrColumns; ++col) {
- triple[columnMap[col]] = tuples.getColumnValue(col);
- }
-
- currentPhase.removeTriple(triple[0], triple[1], triple[2], triple[3]);
- }
- }
- } finally {
- tuples.close();
- }
- } catch (TuplesException ex) {
- throw new StatementStoreException("Exception while iterating over temporary Tuples.", ex);
- }
- }
- }
-
-
- /**
- * Finds triples matching the given specification.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A set of all the triples which match the search.
- * @throws StatementStoreException Due to a structural or IO error.
- */
- public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- checkInitialized();
- dirty = false;
- return currentPhase.findTuples(node0, node1, node2, node3);
- }
-
-
- /**
- * Finds triples matching the given specification and index mask.
- * @param mask The mask of the index to use. This is only allowable for 3 variables
- * and a given graph.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A set of all the triples which match the search.
- * @throws StatementStoreException Due to a structural or IO error.
- */
- public synchronized StoreTuples findTuples(
- int mask, long node0, long node1, long node2, long node3
- ) throws StatementStoreException {
- checkInitialized();
- dirty = false;
- if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
- return currentPhase.findTuples(mask, node0, node1, node2, node3);
- }
-
-
- /**
- * Tests a mask for consistency against the nodes it will be used to find.
- * @param mask The mask to test.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find. Must not be NONE.
- * @return <code>true</code> if the mask is consistent with the given nodes.
- */
- private static boolean checkMask(int mask, long node0, long node1, long node2, long node3) {
- // The graph must be bound
- if (node3 != NONE) return false;
- if (node0 != NONE && 0 == (mask & MASK0)) return false;
- if (node1 != NONE && 0 == (mask & MASK1)) return false;
- if (node2 != NONE && 0 == (mask & MASK2)) return false;
- return true;
- }
-
-
- /**
- * Returns a StoreTuples which contains all triples in the store. The
- * parameters provide a hint about how the StoreTuples will be used. This
- * information is used to select the index from which the StoreTuples will be
- * obtained.
- * @param node0Bound specifies that node0 will be bound
- * @param node1Bound specifies that node1 will be bound
- * @param node2Bound specifies that node2 will be bound
- * @return the {@link StoreTuples}
- * @throws StatementStoreException if something exceptional happens
- */
- public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
- checkInitialized();
- dirty = false;
- return currentPhase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
- }
-
-
- /**
- * Returns <code>true</code> if any triples match the given specification.
- * Allows wild cards StatementStore.NONE for any of the node numbers except node3.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return <code>true</code> if any matching triples exist in the graph.
- * @throws StatementStoreException Due to a structural or IO error.
- */
- public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- checkInitialized();
- return currentPhase.existsTriples(node0, node1, node2, node3);
- }
-
-
- public XAStatementStore newReadOnlyStatementStore() {
- return new ReadOnlyGraph();
- }
-
-
- public XAStatementStore newWritableStatementStore() {
- return this;
- }
-
-
- /**
- * Close all files, removing empty space from the ends as required.
- * @throws StatementStoreException if an error occurs while truncating,
- * flushing or closing one of the three files.
- */
- public synchronized void close() throws StatementStoreException {
- try {
- unmap();
- } finally {
- try {
- IOException savedEx = null;
-
- for (int i = 0; i < NR_INDEXES; ++i) {
- try {
- if (tripleAVLFiles[i] != null) tripleAVLFiles[i].close();
- } catch (IOException ex) {
- savedEx = ex;
- }
- }
-
- if (metarootFile != null) {
- try {
- metarootFile.close();
- } catch (IOException ex) {
- savedEx = ex;
- }
- }
-
- if (savedEx != null) throw new StatementStoreException("I/O error closing graph.", savedEx);
- } finally {
- if (lockFile != null) {
- lockFile.release();
- lockFile = null;
- }
- }
- }
- }
-
-
- /**
- * Close this graph, if it is currently open, and remove all files associated with it.
- * @throws StatementStoreException Due to an IO error.
- */
- public synchronized void delete() throws StatementStoreException {
- currentPhase = null;
- try {
- unmap();
- } finally {
- try {
- IOException savedEx = null;
-
- for (int i = 0; i < NR_INDEXES; ++i) {
- try {
- if (tripleAVLFiles[i] != null) tripleAVLFiles[i].delete();
- } catch (IOException ex) {
- savedEx = ex;
- }
- }
-
- if (metarootFile != null) {
- try {
- metarootFile.delete();
- } catch (IOException ex) {
- savedEx = ex;
- }
- }
-
- if (savedEx != null) throw new StatementStoreException("I/O error deleting graph.", savedEx);
- } finally {
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i] = null;
- metarootFile = null;
- if (lockFile != null) {
- lockFile.release();
- lockFile = null;
- }
- }
- }
- }
-
-
- /**
- * Try to safely close the store if this was not done explicitly.
- */
- protected void finalize() {
- try {
- close();
- } catch (Throwable t) {
- logger.warn("Exception in finalize while trying to close the statement store.", t);
- }
- }
-
-
- /**
- * A manually tracked reference to this object was released. Does nothing.
- */
- public void release() {
- if (logger.isDebugEnabled()) logger.debug("Release " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
-
- /**
- * This in called in response to the resource being manually refreshed.
- * This implementation does nothing here.
- */
- public void refresh() {
- if (logger.isDebugEnabled()) {
- logger.debug("Refresh " + this.getClass() + ":" + System.identityHashCode(this));
- }
- }
-
-
- //
- // Methods from SimpleXAResource.
- //
-
- /**
- * Clears this store to a fresh state.
- * @param phaseNumber The phase number to set to.
- * @throws IOException Error with file access
- * @throws SimpleXAResourceException Error with the data structures.
- */
- public synchronized void clear(int phaseNumber) throws IOException, SimpleXAResourceException {
- if (logger.isDebugEnabled()) {
- logger.debug("Clear(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
- }
- if (currentPhase != null) throw new IllegalStateException("Graph already has a current phase.");
-
- openMetarootFile(true);
-
- synchronized (committedPhaseLock) {
- committedPhaseToken = new Phase().use();
- }
- this.phaseNumber = phaseNumber;
- phaseIndex = 1;
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].clear();
-
- new Phase();
- }
-
-
- /**
- * Clear the state of the database.
- * @throws IOException Filesystem error
- * @throws SimpleXAResourceException Error in the data structures.
- */
- public synchronized void clear() throws IOException, SimpleXAResourceException {
- if (logger.isDebugEnabled()) logger.debug("Clear " + this.getClass() + ":" + System.identityHashCode(this));
- if (currentPhase == null) clear(0);
-
- // could throw an exception if clear() is called after any other
- // operations are performed. Calling clear() multiple times should be
- // permitted.
- }
-
-
- /**
- * Perform all the operations for a commit and return when all the data structures are in place.
- * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error while preparing.
- */
- public synchronized void prepare() throws SimpleXAResourceException {
- if (logger.isDebugEnabled()) logger.debug("Prepare " + this.getClass() + ":" + System.identityHashCode(this));
- checkInitialized();
-
- // check that prepare() was not caleld twice
- if (prepared) throw new SimpleXAResourceException("prepare() called twice.");
-
- try {
- // Perform a prepare.
- recordingPhaseToken = currentPhase.use();
- Phase recordingPhase = currentPhase;
- new Phase();
-
- // Ensure that all data associated with the phase is on disk.
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].force();
-
- // Write the metaroot.
- int newPhaseIndex = 1 - phaseIndex;
- int newPhaseNumber = phaseNumber + 1;
-
- Block block = metarootBlocks[newPhaseIndex];
- block.putInt(IDX_VALID, 0); // should already be invalid.
- block.putInt(IDX_PHASE_NUMBER, newPhaseNumber);
- logger.debug("Writing graph metaroot for phase: " + newPhaseNumber);
- recordingPhase.writeToBlock(block, HEADER_SIZE_LONGS);
- block.write();
- metarootFile.force();
- block.putInt(IDX_VALID, 1);
- block.write();
- metarootFile.force();
-
- phaseIndex = newPhaseIndex;
- phaseNumber = newPhaseNumber;
- prepared = true;
- } catch (IOException ex) {
- logger.error("I/O error while performing prepare.", ex);
- throw new SimpleXAResourceException("I/O error while performing prepare.", ex);
- } finally {
- if (!prepared) {
- // Something went wrong. An exception is on its way out
- logger.error("Prepare failed.");
- if (recordingPhaseToken != null) {
- recordingPhaseToken.release();
- recordingPhaseToken = null;
- }
- }
- }
- }
-
-
- /**
- * Update the metadata to point to the prepared data structures.
- * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error.
- */
- public synchronized void commit() throws SimpleXAResourceException {
- if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
-
- // check that prepare has been called
- if (!prepared) throw new SimpleXAResourceException("commit() called without previous prepare().");
-
- // Perform a commit.
- try {
- // Invalidate the metaroot of the old phase.
- Block block = metarootBlocks[1 - phaseIndex];
- block.putInt(IDX_VALID, 0);
- block.write();
- metarootFile.force();
-
- // Release the token for the previously committed phase.
- synchronized (committedPhaseLock) {
- if (committedPhaseToken != null) committedPhaseToken.release();
- committedPhaseToken = recordingPhaseToken;
- committedGraphNodes = currentPhase.graphNodes;
- }
- recordingPhaseToken = null;
- } catch (IOException ex) {
- logger.fatal("I/O error while performing commit.", ex);
- throw new SimpleXAResourceException("I/O error while performing commit.", ex);
- } finally {
- prepared = false;
- if (recordingPhaseToken != null) {
- // Something went wrong! An exception is on its way out
- recordingPhaseToken.release();
- recordingPhaseToken = null;
-
- logger.error("Commit failed. Calling close().");
- try {
- close();
- } catch (Throwable t) {
- logger.error("Exception on forced close()", t);
- }
- }
- }
- }
-
-
- /**
- * Read the state from the metaroot file and use it to set up this object
- * @return An array of 0, 1, or 2 valid phases that can be selected as the last committed phase.
- * @throws SimpleXAResourceException Due to an IO error, or a data error in the metaroot file.
- */
- public synchronized int[] recover() throws SimpleXAResourceException {
- if (logger.isDebugEnabled()) logger.debug("Recover " + this.getClass() + ":" + System.identityHashCode(this));
- if (currentPhase != null) return new int[0];
- if (wrongFileVersion) throw new SimpleXAResourceException("Wrong metaroot file version.");
-
- try {
- openMetarootFile(false);
- } catch (IOException ex) {
- throw new SimpleXAResourceException("I/O error", ex);
- }
-
- // Count the number of valid phases.
- int phaseCount = 0;
- if (metarootBlocks[0].getInt(IDX_VALID) != 0) ++phaseCount;
- if (metarootBlocks[1].getInt(IDX_VALID) != 0) ++phaseCount;
-
- // Read the phase numbers.
- int[] phaseNumbers = new int[phaseCount];
- int index = 0;
- if (metarootBlocks[0].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[0].getInt(IDX_PHASE_NUMBER);
- if (metarootBlocks[1].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[1].getInt(IDX_PHASE_NUMBER);
- return phaseNumbers;
- }
-
-
- /**
- * Choose a phase from the metaroot file to use
- * @param phaseNumber The number of the phase to select. This must be one of the valid
- * phases present in the metaroot file.
- * @throws IOException Due to an error on the filesystem
- * @throws SimpleXAResourceException If the file structures are incorrect.
- */
- public synchronized void selectPhase(int phaseNumber) throws IOException, SimpleXAResourceException {
- if (logger.isDebugEnabled()) {
- logger.debug("SelectPhase(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
- }
- if (currentPhase != null) throw new SimpleXAResourceException("selectPhase() called on initialized Graph.");
- if (metarootFile == null) throw new SimpleXAResourceException("Graph metaroot file is not open.");
-
- // Locate the metaroot corresponding to the given phase number.
- if (
- metarootBlocks[0].getInt(IDX_VALID) != 0 &&
- metarootBlocks[0].getInt(IDX_PHASE_NUMBER) == phaseNumber
- ) {
- phaseIndex = 0;
- // A new phase will be saved in the other metaroot.
- } else if (
- metarootBlocks[1].getInt(IDX_VALID) != 0 &&
- metarootBlocks[1].getInt(IDX_PHASE_NUMBER) == phaseNumber
- ) {
- phaseIndex = 1;
- // A new phase will be saved in the other metaroot.
- } else {
- throw new SimpleXAResourceException("Invalid phase number: " + phaseNumber);
- }
-
- // Load a duplicate of the selected phase. The duplicate will have a
- // phase number which is one higher than the original phase.
- try {
- synchronized (committedPhaseLock) {
- committedPhaseToken = new Phase(metarootBlocks[phaseIndex], HEADER_SIZE_LONGS).use();
- }
- this.phaseNumber = phaseNumber;
- } catch (IllegalStateException ex) {
- throw new SimpleXAResourceException("Cannot construct initial phase.", ex);
- }
- new Phase();
-
- // Invalidate the on-disk metaroot that the new phase will be saved to.
- Block block = metarootBlocks[1 - phaseIndex];
- block.putInt(IDX_VALID, 0);
- block.write();
- metarootFile.force();
- }
-
-
- /**
- * Return to the data structure state from the beginning of the transaction.
- * @throws SimpleXAResourceException Due to an IO error.
- */
- public synchronized void rollback() throws SimpleXAResourceException {
- if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
- checkInitialized();
- try {
- if (prepared) {
- // Restore phaseIndex and phaseNumber to their previous values.
- phaseIndex = 1 - phaseIndex;
- --phaseNumber;
- recordingPhaseToken = null;
- prepared = false;
-
- // Invalidate the metaroot of the other phase.
- Block block = metarootBlocks[1 - phaseIndex];
- block.putInt(IDX_VALID, 0);
- block.write();
- metarootFile.force();
- }
- } catch (IOException ex) {
- throw new SimpleXAResourceException("I/O error while performing rollback (invalidating metaroot)", ex);
- } finally {
- try {
- new Phase(committedPhaseToken.getPhase());
- } catch (IOException ex) {
- throw new SimpleXAResourceException("I/O error while performing rollback (new committed phase)", ex);
- }
- }
- }
-
-
- /**
- * Get a string representation of the current state of the graph.
- * @return A string representing the current state
- */
- public synchronized String toString() {
- if (currentPhase == null) return "Uninitialized Graph.";
- return currentPhase.toString();
- }
-
-
- /**
- * Attempt to cleanly close all mapped files.
- */
- public synchronized void unmap() {
- if (committedPhaseToken != null) {
- recordingPhaseToken = null;
- prepared = false;
-
- try {
- new Phase(committedPhaseToken.getPhase());
- } catch (Throwable t) {
- logger.warn("Exception while rolling back in unmap()", t);
- }
- currentPhase = null;
-
- synchronized (committedPhaseLock) {
- committedPhaseToken.release();
- committedPhaseToken = null;
- }
- }
-
- if (tripleAVLFiles != null) {
- for (int i = 0; i < NR_INDEXES; ++i) {
- if (tripleAVLFiles[i] != null) tripleAVLFiles[i].unmap();
- }
- }
-
- if (metarootFile != null) {
- if (metarootBlocks[0] != null) metarootBlocks[0] = null;
- if (metarootBlocks[1] != null) metarootBlocks[1] = null;
- metarootFile.unmap();
- }
- }
-
-
- /**
- * Check that the data structures are valid
- * @return The number of triples in the database
- */
- synchronized long checkIntegrity() {
- checkInitialized();
- return currentPhase.checkIntegrity();
- }
-
-
- /**
- * Open the metaroot file and read in the contents
- * @param clear If <code>true</code> then the file will be reset to empty.
- * @throws IOException Due to a filesystem error.
- * @throws SimpleXAResourceException If the data structures are inconsistent.
- */
- private void openMetarootFile(boolean clear) throws IOException, SimpleXAResourceException {
- if (metarootFile == null) {
- metarootFile = AbstractBlockFile.openBlockFile(fileName + ".g", METAROOT_SIZE * Constants.SIZEOF_LONG, BlockFile.IOType.EXPLICIT);
-
- long nrBlocks = metarootFile.getNrBlocks();
- if (nrBlocks != NR_METAROOTS) {
- if (nrBlocks > 0) {
- logger.info("Graph metaroot file for triple store \"" + fileName + "\" has invalid number of blocks: " + nrBlocks);
- if (nrBlocks < NR_METAROOTS) {
- clear = true;
- metarootFile.clear();
- }
- } else {
- // Perform initialization on empty file.
- clear = true;
- }
- metarootFile.setNrBlocks(NR_METAROOTS);
- }
-
- metarootBlocks[0] = metarootFile.readBlock(0);
- metarootBlocks[1] = metarootFile.readBlock(1);
- }
-
- if (clear) {
- // Invalidate the metaroots on disk.
- metarootBlocks[0].putInt(IDX_MAGIC, FILE_MAGIC);
- metarootBlocks[0].putInt(IDX_VERSION, FILE_VERSION);
- metarootBlocks[0].putInt(IDX_VALID, 0);
- metarootBlocks[0].write();
- metarootBlocks[1].putInt(IDX_MAGIC, 0);
- metarootBlocks[1].putInt(IDX_VERSION, 0);
- metarootBlocks[1].putInt(IDX_VALID, 0);
- metarootBlocks[1].write();
- metarootFile.force();
- }
- }
-
-
- /**
- * Tests that the current object has been initialized.
- * @throws IllegalStateException Throws this unchecked exception if the object is not initialized.
- */
- private void checkInitialized() {
- if (currentPhase == null) throw new IllegalStateException("No current phase. Graph has not been initialized or has been closed.");
- }
-
-
- final class ReadOnlyGraph implements XAStatementStore {
-
- private Phase phase = null;
-
- private Phase.Token token = null;
-
-
- /**
- * Create a read-only graph attached to the current outer database
- */
- ReadOnlyGraph() {
- synchronized (committedPhaseLock) {
- if (committedPhaseToken == null) {
- throw new IllegalStateException("Cannot create read only view of uninitialized Graph.");
- }
- }
- }
-
-
- public synchronized boolean isEmpty() {
- return phase.isEmpty();
- }
-
-
- /**
- * Returns a count of the number of triples in the graph
- * @return a count of the number of triples in the graph
- */
- public synchronized long getNrTriples() {
- return phase.getNrTriples();
- }
-
-
- /**
- * Adds a triple to the graph.
- * @param node0 The 0 node of the triple.
- * @param node1 The 1 node of the triple.
- * @param node2 The 2 node of the triple.
- * @param node3 The 3 node of the triple.
- */
- public void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
- throw new UnsupportedOperationException("Trying to modify a read-only graph.");
- }
-
-
- /**
- * Removes all triples matching the given specification.
- * @param node0 the value for the first element of the triples
- * @param node1 the value for the second element of the triples
- * @param node2 the value for the third element of the triples
- * @param node3 the value for the fourth element of the triples
- */
- public void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- throw new UnsupportedOperationException("Trying to modify a read-only graph.");
- }
-
-
- /**
- * Finds triples matching the given specification.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A StoreTuples which contains the triples which match the search.
- */
- public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- return phase.findTuples(node0, node1, node2, node3);
- }
-
- /**
- * Finds triples matching the given specification.
- * @param mask The mask of the index to use. This is only allowable for 3 variables
- * and a given graph.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A StoreTuples which contains the triples which match the search.
- * @throws StatementStoreException A structural or IO error
- */
- public synchronized StoreTuples findTuples(int mask, long node0, long node1, long node2, long node3) throws StatementStoreException {
- if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
- return phase.findTuples(mask, node0, node1, node2, node3);
- }
-
-
- /**
- * Returns a StoreTuples which contains all triples in the store. The
- * parameters provide a hint about how the StoreTuples will be used. This
- * information is used to select the index from which the StoreTuples will
- * be obtained.
- * @param node0Bound specifies that node0 will be bound
- * @param node1Bound specifies that node1 will be bound
- * @param node2Bound specifies that node2 will be bound
- * @return the {@link StoreTuples}
- * @throws StatementStoreException if something exceptional happens
- */
- public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
- return phase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
- }
-
-
- public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- return phase.existsTriples(node0, node1, node2, node3);
- }
-
-
- public XAStatementStore newReadOnlyStatementStore() {
- throw new UnsupportedOperationException();
- }
-
-
- public XAStatementStore newWritableStatementStore() {
- throw new UnsupportedOperationException();
- }
-
-
- public void close() {
- throw new UnsupportedOperationException("Trying to close a read-only graph.");
- }
-
-
- public void delete() {
- throw new UnsupportedOperationException("Trying to delete a read-only graph.");
- }
-
-
- /**
- * Release the phase.
- */
- public synchronized void release() {
- if (logger.isDebugEnabled()) logger.debug("Releasing " + this.getClass() + ":" + System.identityHashCode(this));
- try {
- if (token != null) token.release();
- } finally {
- phase = null;
- token = null;
- }
- }
-
-
- public synchronized void refresh() {
- if (logger.isDebugEnabled()) logger.debug("Refreshing " + this.getClass() + ":" + System.identityHashCode(this));
-
- synchronized (committedPhaseLock) {
- Phase committedPhase = committedPhaseToken.getPhase();
- if (phase != committedPhase) {
- if (token != null) token.release();
- phase = committedPhase;
- token = phase.use();
- }
- }
- }
-
- public void addReleaseNodeListener(ReleaseNodeListener l) {
- throw new UnsupportedOperationException();
- }
-
- public void removeReleaseNodeListener(ReleaseNodeListener l) {
- throw new UnsupportedOperationException();
- }
-
- public void prepare() {
- if (logger.isDebugEnabled()) logger.debug("Preparing " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
- public void commit() {
- if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
- public void rollback() {
- if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
- public void clear() {
- if (logger.isDebugEnabled()) logger.debug("Clearing " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
- public void clear(int phaseNumber) {
- if (logger.isDebugEnabled()) logger.debug("Clearing (" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
- }
-
- public int[] recover() {
- if (logger.isDebugEnabled()) logger.debug("Recovering " + this.getClass() + ":" + System.identityHashCode(this));
- throw new UnsupportedOperationException("Attempting to recover ReadOnlyGraph");
- }
-
- public void selectPhase(int phaseNumber) {
- if (logger.isDebugEnabled()) logger.debug("Selecting Phase " + this.getClass() + ":" + System.identityHashCode(this));
- throw new UnsupportedOperationException("Attempting to selectPhase of ReadOnlyGraph");
- }
-
- public int getPhaseNumber() {
- return phaseNumber;
- }
-
-
- /**
- * Not used on a read-only graph
- */
- public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
- // do nothing
- }
- }
-
-
- /**
- * This class represents the state of the the database at a particular time. Only the most
- * recent phase can be written to.
- */
- final class Phase implements PersistableMetaRoot {
-
- /** The size of the data this object stores in the metaroot */
- final static int RECORD_SIZE = TripleAVLFile.Phase.RECORD_SIZE * NR_INDEXES;
-
- /** Maintaines parallel structural phases between all of the parallel tree data structures */
- private TripleAVLFile.Phase[] tripleAVLFilePhases = new TripleAVLFile.Phase[NR_INDEXES];
-
- /** The list of graphs valid in this phase. */
- private List<Long> graphNodes = null;
-
-
- /**
- * Creates a new phase based on the current state of the database.
- * This sets the latest phase on the outer statement store.
- * @throws IOException Error on the filesystem.
- */
- Phase() throws IOException {
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase();
- currentPhase = this;
- dirty = true;
- try {
- graphNodes = committedGraphNodes == null ? scanForGraphs() : new ArrayList<Long>(committedGraphNodes);
- } catch (StatementStoreException e) {
- throw new IOException("Unable to get metadata for phase: " + e.getMessage());
- }
- }
-
-
- /**
- * A copy constructor for duplicating a phase structure. This sets the latest phase
- * on the outer statement store.
- * @throws IOException Error on the filesystem.
- */
- Phase(Phase p) throws IOException {
- assert p != null;
-
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(p.tripleAVLFilePhases[i]);
- currentPhase = this;
- dirty = true;
- graphNodes = new ArrayList<Long>(p.graphNodes);
- }
-
-
- /**
- * Create a phase based on information found in a buffer that came from a metaroot
- * @param b The buffer containing the phase information.
- * @param offset The start of the phase information in the buffer
- * @throws IOException A filesystem error occurred while accessing the buffer.
- */
- Phase(Block b, int offset) throws IOException {
- for (int i = 0; i < NR_INDEXES; ++i) {
- tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(b, offset);
- offset += TripleAVLFile.Phase.RECORD_SIZE;
- }
- currentPhase = this;
- dirty = false;
- try {
- graphNodes = scanForGraphs();
- } catch (StatementStoreException sse) {
- throw new IOException("Error accessing graph data during initialization");
- }
- }
-
-
- /**
- * Writes this PersistableMetaRoot to the specified Block. The ints are
- * written at the specified offset.
- * @param b The metaroot Block to write this object to.
- * @param offset The start within the buffer of where the phase information should be written to.
- */
- public void writeToBlock(Block b, int offset) {
- for (int i = 0; i < NR_INDEXES; ++i) {
- tripleAVLFilePhases[i].writeToBlock(b, offset);
- offset += TripleAVLFile.Phase.RECORD_SIZE;
- }
- }
-
-
- /**
- * Create a string representation of the current phase.
- * @return A string representing this phase
- */
- public String toString() {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < NR_INDEXES; ++i) {
- StoreTuples ts = tripleAVLFilePhases[i].allTuples();
- try {
- sb.append(ts).append('\n');
- } finally {
- try {
- ts.close();
- } catch (TuplesException ex) {
- logger.warn("TuplesException while closing Tuples", ex);
- return ex.toString();
- }
- }
- }
- return sb.toString();
- }
-
-
- /**
- * Tests if any part of this phase has a reference being kept to it
- * @return <code>true</code> if any part of this phase is being used.
- */
- boolean isInUse() {
- for (int i = 0; i < NR_INDEXES; ++i) {
- if (tripleAVLFilePhases[i].isInUse()) return true;
- }
- return false;
- }
-
-
- /**
- * Tests if the phase contains any triples
- * @return <code>true</code> if the phase contains 1 or more triples
- */
- boolean isEmpty() {
- return tripleAVLFilePhases[TI_3012].isEmpty();
- }
-
-
- /**
- * Gets the number of triples in the phase
- * @return The number of triples in this phase
- */
- long getNrTriples() {
- return tripleAVLFilePhases[TI_3012].getNrTriples();
- }
-
-
- /**
- * Adds a new triple to the graph if it doesn't already exist.
- * @param node0 the first element of the new triple
- * @param node1 the second element of the new triple
- * @param node2 the third element of the new triple
- * @param node3 the fourth element of the new triple
- * @throws StatementStoreException An IO or data structure error
- */
- void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
- assert node0 >= NodePool.MIN_NODE;
- assert node1 >= NodePool.MIN_NODE;
- assert node2 >= NodePool.MIN_NODE;
- assert node3 >= NodePool.MIN_NODE;
-
- //if (
- // DEBUG && nodePool != null &&
- // !nodePool.isValid(node0) && !nodePool.isValid(node1) &&
- // !nodePool.isValid(node2) && !nodePool.isValid(node3)
- //) throw new AssertionError(
- // "Attempt to add a triple with an invalid node"
- //);
-
- long[] triple = new long[]{node0, node1, node2, node3};
-
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].asyncAddTriple(triple);
-
- if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.add(node0);
- }
-
-
- /**
- * Removes the specified triple.
- * @param node0 the value for the first element of the triple
- * @param node1 the value for the second element of the triple
- * @param node2 the value for the third element of the triple
- * @param node3 the value for the fourth element of the triple
- * @throws StatementStoreException An IO or structural error
- */
- void removeTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
- if (
- node0 < NodePool.MIN_NODE ||
- node1 < NodePool.MIN_NODE ||
- node2 < NodePool.MIN_NODE ||
- node3 < NodePool.MIN_NODE
- ) {
- throw new StatementStoreException("Attempt to remove a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3);
- }
-
- try {
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].removeTriple(node0, node1, node2, node3);
- // removeTriple listeners can be informed here
- } catch (IOException e) {
- throw new StatementStoreException("I/O error", e);
- }
- if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.remove(node0);
- }
-
-
- /**
- * Finds triples matching the given specification.
- * @param variableMask the mask used to indicate the desired index.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A StoreTuples containing all the triples which match the search.
- * @throws StatementStoreException An IO or structural error
- */
- StoreTuples findTuples(int variableMask, long node0, long node1, long node2, long node3) throws StatementStoreException {
- if (
- node0 < NodePool.NONE ||
- node1 < NodePool.NONE ||
- node2 < NodePool.NONE ||
- node3 < NodePool.NONE
- ) {
- // There is at least one query node. Return an empty StoreTuples.
- return TuplesOperations.empty();
- }
-
- if (0 == (variableMask & MASK3)) throw new StatementStoreException("This version of find is for re-ordering graphs, based on a given mask.");
- try {
- switch (variableMask) {
- case MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3);
- case MASK0 | MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3);
- case MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3120].findTuples(node3);
- case MASK0 | MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3);
- case MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].findTuples(node3);
- case MASK0 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].findTuples(node3);
- case MASK1 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3120].findTuples(node3);
- case MASK0 | MASK1 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3);
- default:
- throw new AssertionError();
- }
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
-
- /**
- * Finds triples matching the given specification.
- * @param node0 The 0 node of the triple to find.
- * @param node1 The 1 node of the triple to find.
- * @param node2 The 2 node of the triple to find.
- * @param node3 The 3 node of the triple to find.
- * @return A StoreTuples containing all the triples which match the search.
- * @throws StatementStoreException An IO or structural error
- */
- StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- if (
- node0 < NodePool.NONE ||
- node1 < NodePool.NONE ||
- node2 < NodePool.NONE ||
- node3 < NodePool.NONE
- ) {
- // There is at least one query node. Return an empty StoreTuples.
- return TuplesOperations.empty();
- }
-
- int variableMask =
- (node0 != NONE ? MASK0 : 0) |
- (node1 != NONE ? MASK1 : 0) |
- (node2 != NONE ? MASK2 : 0) |
- (node3 != NONE ? MASK3 : 0);
-
- if (node3 == NONE && variableMask != 0) {
- return joinGraphedTuples(variableMask, node0, node1, node2);
- }
-
-
- try {
- switch (variableMask) {
- case 0:
- return tripleAVLFilePhases[TI_3012].allTuples();
- case MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3);
- case MASK0 | MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3, node0);
- case MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3120].findTuples(node3, node1);
- case MASK0 | MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3012].findTuples(node3, node0, node1);
- case MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].findTuples(node3, node2);
- case MASK0 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].findTuples(node3, node2, node0);
- case MASK1 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3120].findTuples(node3, node1, node2);
- case MASK0 | MASK1 | MASK2 | MASK3:
- if (tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2)) {
- return TuplesOperations.unconstrained();
- }
- return TuplesOperations.empty();
- default:
- throw new AssertionError("Search structure incorrectly calculated");
- }
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
-
- StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
- // The variable mask does not need MASK3, as this has been taken into account in selectIndex[]
- int variableMask =
- (node0Bound ? MASK0 : 0) |
- (node1Bound ? MASK1 : 0) |
- (node2Bound ? MASK2 : 0);
- if (variableMask == 0 || node3Bound) {
- return tripleAVLFilePhases[selectIndex[variableMask]].allTuples();
- } else {
- return joinGraphedTuples(variableMask);
- }
- }
-
-
- /**
- * Iterates over all graphs, finding requested tuples, and joining all the results together into a single tuples.
- * @param variableMask Pre-calculated from the bound node parameters.
- * @param node0 The bound value for node0, or < 0 if not bound.
- * @param node1 The bound value for node1, or < 0 if not bound.
- * @param node2 The bound value for node2, or < 0 if not bound.
- * @return A StoreTuples with all the intermediate tuples appended.
- * @throws StatementStoreException On an error accessing the store.
- */
- StoreTuples joinGraphedTuples(int variableMask, long node0, long node1, long node2) throws StatementStoreException {
- try {
- assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
-
- // get the graphNodes if not already configured
- if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
-
- if (variableMask == (MASK0 | MASK1 | MASK2)) {
- LiteralGraphTuples result = new LiteralGraphTuples(false);
- for (long graphNode: graphNodes) {
- if (tripleAVLFilePhases[TI_3012].existsTriple(node0, node1, node2, graphNode)) {
- result.appendTuple(new long[] { graphNode });
- }
- }
- return result;
- }
-
- ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
- for (long graphNode: graphNodes) {
- StoreTuples partialResult = null;
- switch (variableMask) {
- case 0:
- partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode);
- break;
- case MASK0:
- partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0);
- break;
- case MASK1:
- partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1);
- break;
- case MASK0 | MASK1:
- partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0, node1);
- break;
- case MASK2:
- partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2);
- break;
- case MASK0 | MASK2:
- partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2, node0);
- break;
- case MASK1 | MASK2:
- partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1, node2);
- break;
- default:
- throw new AssertionError("Search structure incorrectly calculated");
- }
- graphedTuples.add(partialResult);
- }
- return TuplesOperations.appendCompatible(graphedTuples);
- } catch (TuplesException te) {
- throw new StatementStoreException("Error accessing Tuples", te);
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
-
- /**
- * Iterates over all graphs, getting all tuples in the requested order,
- * and joining all the results together into a single tuples.
- * @param variableMask Determines the required ordering of the data.
- * @return A StoreTuples with all the intermediate tuples appended.
- * @throws StatementStoreException On an error accessing the store.
- */
- StoreTuples joinGraphedTuples(int variableMask) throws StatementStoreException {
- try {
- assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
-
- // get the graphNodes if not already configured
- if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
-
- ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
- for (long graphNode: graphNodes) {
- int phaseIndex;
- switch (variableMask) {
- case 0:
- case MASK0:
- case MASK0 | MASK1:
- case MASK0 | MASK1 | MASK2:
- phaseIndex = TI_3012;
- break;
- case MASK1:
- case MASK1 | MASK2:
- phaseIndex = TI_3120;
- break;
- case MASK2:
- case MASK0 | MASK2:
- phaseIndex = TI_3201;
- break;
- default:
- throw new AssertionError("Search structure incorrectly calculated");
- }
- StoreTuples partialResult = tripleAVLFilePhases[phaseIndex].findTuplesForMeta(graphNode);
- graphedTuples.add(partialResult);
- }
- return TuplesOperations.appendCompatible(graphedTuples);
- } catch (TuplesException te) {
- throw new StatementStoreException("Error accessing Tuples", te);
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
-
- /**
- * Test is there exist triples according to a given pattern
- * @param node0 A subject gNode, or NONE
- * @param node1 A predicate gNode, or NONE
- * @param node2 A object gNode, or NONE
- * @param node3 A subject gNode. May not be NONE
- * @return <code>true</code> if there exist triples that match the pattern
- * @throws StatementStoreException A structural or IO exception
- */
- boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
- if (node3 == NONE) throw new IllegalStateException("Graph must be specified");
-
- if (
- node0 < NodePool.NONE ||
- node1 < NodePool.NONE ||
- node2 < NodePool.NONE ||
- node3 < NodePool.NONE
- ) {
- // There is at least one query node (comes from the query, but not in the data pool).
- // Return an empty StoreTuples.
- return false;
- }
-
- int variableMask =
- (node0 != NONE ? MASK0 : 0) |
- (node1 != NONE ? MASK1 : 0) |
- (node2 != NONE ? MASK2 : 0) |
- MASK3;
-
- try {
- switch (variableMask) {
- case MASK3:
- return tripleAVLFilePhases[TI_3012].existsTriples(node3);
- case MASK0 | MASK3:
- return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0);
- case MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1);
- case MASK0 | MASK1 | MASK3:
- return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0, node1);
- case MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2);
- case MASK0 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2, node0);
- case MASK1 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1, node2);
- case MASK0 | MASK1 | MASK2 | MASK3:
- return tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2);
- default:
- throw new AssertionError("Search structure incorrectly calculated");
- }
- } catch (IOException ex) {
- throw new StatementStoreException("I/O error", ex);
- }
- }
-
-
- /**
- * Check that each index contains the same number of triples
- * @throws AssertionError if the indexes contain a differing number of triples
- */
- long checkIntegrity() {
- long nrTriples[] = new long[NR_INDEXES];
-
- for (int i = 0; i < NR_INDEXES; ++i) nrTriples[i] = tripleAVLFilePhases[i].checkIntegrity();
-
- for (int i = 1; i < NR_INDEXES; ++i) {
- if (nrTriples[0] != nrTriples[i]) {
- StringBuffer sb = new StringBuffer("tripleAVLFiles disagree on the number of triples:");
- for (int j = 0; j < NR_INDEXES; ++j) sb.append(' ').append(nrTriples[j]);
- throw new AssertionError(sb.toString());
- }
- }
-
- return nrTriples[0];
- }
-
-
- /**
- * Ask the system for all the known graphs.
- * @return All the known graph nodes.
- */
- List<Long> scanForGraphs() throws StatementStoreException, IOException {
- List<Long> nodeList = new ArrayList<Long>();
-
- if (systemGraphNode == NONE || rdfTypeNode == NONE || graphTypeNode == NONE) return nodeList;
-
- StoreTuples graphTuples = tripleAVLFilePhases[TI_3120].findTuples(systemGraphNode, rdfTypeNode, graphTypeNode);
- assert graphTuples.getNumberOfVariables() == 1;
-
- try {
- graphTuples.beforeFirst();
- while (graphTuples.next()) nodeList.add(graphTuples.getColumnValue(0));
- } catch (TuplesException e) {
- throw new StatementStoreException("Unable to construct a result containing all graphs.", e);
- }
-
- return nodeList;
- }
-
-
- /**
- * Increment the reference count on this object.
- * @return A new token representing the reference.
- */
- Token use() {
- return new Token();
- }
-
-
- /**
- * A token to reference the phase, incrementing the reference count from the perpective
- * of the garbage collector.
- */
- final class Token {
-
- /** A list of tokens from the underlying indexes */
- private TripleAVLFile.Phase.Token[] tripleAVLFileTokens = new TripleAVLFile.Phase.Token[NR_INDEXES];
-
- /** The phase being referenced */
- private Phase phase = Phase.this;
-
-
- /**
- * Creates a token. This creates tokens for the underlying objects as well.
- */
- Token() {
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i] = tripleAVLFilePhases[i].use();
- }
-
-
- /**
- * Get the phase that this token represents.
- * @return The phase referenced by this token.
- */
- public Phase getPhase() {
- assert tripleAVLFileTokens != null : "Invalid Token";
- return phase;
- }
-
-
- /**
- * Reduce the reference count on the referenced phase by releasing this token.
- * The token may not be used after being released.
- */
- public void release() {
- assert tripleAVLFileTokens != null : "Invalid Token";
- for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i].release();
- tripleAVLFileTokens = null;
- phase = null;
- }
-
- }
-
- }
-
-
- /**
- * @see org.mulgara.store.xa.XAStatementStore#initializeSystemNodes(long, long, long)
- * Set the various system graph nodes. These may only be set once, but will allow duplicate calls if the values are the same.
- * @param systemGraphNode The new system graph node.
- * @param rdfTypeNode The node for <rdf:graph>.
- * @param systemGraphTypeNode The node for the system graph type.
- */
- public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
- if (this.systemGraphNode != NONE && systemGraphNode != this.systemGraphNode) {
- throw new IllegalStateException("Cannot set system graph again. Was: " + this.systemGraphNode + ", now: " + systemGraphNode);
- }
- if (systemGraphNode < 0) throw new IllegalArgumentException("Attempt to set invalid system graph node");
- this.systemGraphNode = systemGraphNode;
-
- if (this.rdfTypeNode != NONE && rdfTypeNode != this.rdfTypeNode) {
- throw new IllegalStateException("Cannot set the rdf:type node again. Was: " + this.rdfTypeNode + ", now: " + rdfTypeNode);
- }
- if (rdfTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid rdf:type node");
- this.rdfTypeNode = rdfTypeNode;
-
- if (this.graphTypeNode != NONE && systemGraphTypeNode != this.graphTypeNode) {
- throw new IllegalStateException("Cannot set graph type again. Was: " + this.graphTypeNode + ", now: " + systemGraphTypeNode);
- }
- if (systemGraphTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid graph type node");
- this.graphTypeNode = systemGraphTypeNode;
- }
-
-}
Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImpl.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,1796 @@
+/*
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is the Kowari Metadata Store.
+ *
+ * The Initial Developer of the Original Code is Plugged In Software Pty
+ * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
+ * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
+ * Plugged In Software Pty Ltd. All Rights Reserved.
+ *
+ * Contributor(s): N/A.
+ *
+ * [NOTE: The text of this Exhibit A may differ slightly from the text
+ * of the notices in the Source Code files of the Original Code. You
+ * should use the text of this Exhibit A rather than the text found in the
+ * Original Code Source Code for Your Modifications.]
+ *
+ */
+package org.mulgara.store.statement.xa11;
+
+import java.io.*;
+import java.nio.*;
+
+// Java 2 standard packages
+import java.util.*;
+
+// Third party packages
+import org.apache.log4j.Logger;
+
+// Locally written packages
+import org.mulgara.query.*;
+import org.mulgara.store.nodepool.*;
+import org.mulgara.store.statement.*;
+import org.mulgara.store.statement.xa.TripleAVLFile;
+import org.mulgara.store.tuples.StoreTuples;
+import org.mulgara.store.tuples.TuplesOperations;
+import org.mulgara.store.xa.AbstractBlockFile;
+import org.mulgara.store.xa.Block;
+import org.mulgara.store.xa.BlockFile;
+import org.mulgara.store.xa.LockFile;
+import org.mulgara.store.xa.PersistableMetaRoot;
+import org.mulgara.store.xa.SimpleXAResourceException;
+import org.mulgara.store.xa.XAStatementStore;
+import org.mulgara.store.xa.XAUtils;
+import org.mulgara.util.Constants;
+
+/**
+ * An implementation of {@link StatementStore}.
+ *
+ * @created 2008-09-30
+ * @author Paul Gearon
+ * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
+ * @copyright ©2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
+ * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
+ */
+public final class XA11StatementStoreImpl implements XAStatementStore {
+
+ /** Logger. */
+ private final static Logger logger = Logger.getLogger(XA11StatementStoreImpl.class);
+
+ /** The value of the invalid gNode */
+ final static long NONE = NodePool.NONE;
+
+ /** The subject/predicate/object index */
+ final static int TI_3012 = 0;
+
+ /** The predicate/object/subject index */
+ final static int TI_3120 = 1;
+
+ /** The object/subject/predicate index */
+ final static int TI_3201 = 2;
+
+ /** The number of indexes */
+ final static int NR_INDEXES = 3;
+
+ /** The ordering of indexes, as indexed by the TI_ values */
+ private final static int[][] orders = {
+ {3, 0, 1, 2}, // TI_3012
+ {3, 1, 2, 0}, // TI_3120
+ {3, 2, 0, 1} // TI_3201
+ };
+
+ private final static int[] selectIndex = {
+ /* 3XXX */ TI_3012,
+ /* 3XX0 */ TI_3012,
+ /* 3X1X */ TI_3120,
+ /* 3X10 */ TI_3012,
+ /* 32XX */ TI_3201,
+ /* 32X0 */ TI_3201,
+ /* 321X */ TI_3120,
+ /* 3210 */ TI_3012
+ };
+
+ /** A number to identify the correct file type */
+ private final static int FILE_MAGIC = 0xa5e7f21e;
+
+ /** The version of file format */
+ private final static int FILE_VERSION = 9;
+
+ /** Index of the file magic number within each of the two on-disk metaroots. */
+ private final static int IDX_MAGIC = 0;
+
+ /** Index of the file version number within each of the two on-disk metaroots. */
+ private final static int IDX_VERSION = 1;
+
+ /** Index of the valid flag (in ints) within each of the two on-disk metaroots. */
+ private final static int IDX_VALID = 2;
+
+ /** The index of the phase number in the on-disk phase. */
+ private final static int IDX_PHASE_NUMBER = 3;
+
+ /** The size of the header of a metaroot in ints. */
+ private final static int HEADER_SIZE_INTS = 4;
+
+ /** The size of the header of a metaroot in longs. */
+ private final static int HEADER_SIZE_LONGS = (HEADER_SIZE_INTS + 1) / 2;
+
+ /** The size of a metaroot in longs. */
+ private final static int METAROOT_SIZE = HEADER_SIZE_LONGS + Phase.RECORD_SIZE;
+
+ /** The number of metaroots in the metaroot file. */
+ private final static int NR_METAROOTS = 2;
+
+ /** The mask for a bound Subject */
+ private final static int MASK0 = 1;
+
+ /** The mask for a bound Predicate */
+ private final static int MASK1 = 2;
+
+ /** The mask for a bound Object */
+ private final static int MASK2 = 4;
+
+ /** The mask for a bound Graph. This must always be set. */
+ private final static int MASK3 = 8;
+
+ /** The node number for the system graph. Globalized to <#>. */
+ private long systemGraphNode = NONE;
+
+ /** The node number for <rdf:type>. */
+ private long rdfTypeNode = NONE;
+
+ /** The node number for the graph class <mulgara:ModelType>. */
+ private long graphTypeNode = NONE;
+
+ /** The name of the triple store which forms the base name for the graph files. */
+ private String fileName;
+
+ /** The LockFile that protects the graph from being opened twice. */
+ private LockFile lockFile;
+
+ /** The BlockFile for the node pool metaroot file. */
+ private BlockFile metarootFile = null;
+
+ /** The metaroot blocks of the metaroot file. */
+ private Block[] metarootBlocks = new Block[NR_METAROOTS];
+
+ /** An error flag that is set during file initialization if the file version is incorrect */
+ private boolean wrongFileVersion = false;
+
+ /** The files containing indexed triples */
+ private TripleAVLFile[] tripleAVLFiles = new TripleAVLFile[NR_INDEXES];
+
+ /** The current read/write phase. Only the latest phase can write. */
+ private Phase currentPhase = null;
+
+ /**
+ * Determines if modifications can be performed without creating a new
+ * (in-memory) phase. If dirty is false and the current phase is in use (by
+ * unclosed Tupleses) then a new phase must be created to protect the existing
+ * Tupleses before any further modifications are made.
+ */
+ private boolean dirty = true;
+
+ /**
+ * The index of the phase in the metaroot. May be 0 or 1 as the commited phase swaps
+ * between the two metaroots.
+ */
+ private int phaseIndex = 0;
+
+ /** The number of the current phase */
+ private int phaseNumber = 0;
+
+ /** A reference token for keeping the commited phase available until we no longer need it */
+ private Phase.Token committedPhaseToken = null;
+
+ /** A synchronization object for locking access to the committed phase */
+ private Object committedPhaseLock = new Object();
+
+ /** A reference token for keeping the recording phase available until we no longer need it */
+ private Phase.Token recordingPhaseToken = null;
+
+ /** The list of graphs known to this statement store. */
+ private List<Long> committedGraphNodes;
+
+ /**
+ * This flag indicates that the current object has been fully written, and may be considered
+ * as committed when the rest of the system is ready.
+ */
+ private boolean prepared = false;
+
+ /** A set of objects to be informed when nodes are released. */
+ private List<ReleaseNodeListener> releaseNodeListeners = new ArrayList<ReleaseNodeListener>();
+
+
+ /**
+ * Creates a statement store using a base filename.
+ *
+ * @param fileName The base filename to operate from.
+ * @throws IOException The mass storage could not be accessed.
+ */
+ public XA11StatementStoreImpl(String fileName) throws IOException {
+ this.fileName = fileName;
+
+ lockFile = LockFile.createLockFile(fileName + ".g.lock");
+
+ try {
+ // Check that the metaroot file was created with a compatible version of the triplestore.
+ RandomAccessFile metarootRAF = null;
+ try {
+ metarootRAF = new RandomAccessFile(fileName + ".g", "r");
+ if (metarootRAF.length() >= 2 * Constants.SIZEOF_INT) {
+ int fileMagic = metarootRAF.readInt();
+ int fileVersion = metarootRAF.readInt();
+ if (AbstractBlockFile.byteOrder != ByteOrder.BIG_ENDIAN) {
+ fileMagic = XAUtils.bswap(fileMagic);
+ fileVersion = XAUtils.bswap(fileVersion);
+ }
+ wrongFileVersion = fileMagic != FILE_MAGIC || fileVersion != FILE_VERSION;
+ } else {
+ wrongFileVersion = false;
+ }
+ } catch (FileNotFoundException ex) {
+ wrongFileVersion = false;
+ } finally {
+ if (metarootRAF != null) metarootRAF.close();
+ }
+
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ String suffix = ".g_" + orders[i][0] + orders[i][1] + orders[i][2] + orders[i][3];
+ tripleAVLFiles[i] = new TripleAVLFile(fileName + suffix, orders[i]);
+ }
+ } catch (IOException ex) {
+ try {
+ close();
+ } catch (StatementStoreException ex2) { /* no-op */ }
+ throw ex;
+ }
+ }
+
+
+ /**
+ * Returns <code>true</code> if there are no triples in the graph
+ * @return <code>true</code> if there are no triples in the graph
+ */
+ public synchronized boolean isEmpty() {
+ checkInitialized();
+ return currentPhase.isEmpty();
+ }
+
+
+ /**
+ * Returns a count of the number of triples in the graph
+ * @return a count of the number of triples in the graph
+ */
+ public synchronized long getNrTriples() {
+ checkInitialized();
+ return currentPhase.getNrTriples();
+ }
+
+
+ /**
+ * Gets the PhaseNumber attribute of the XAGraphImpl object
+ * @return The PhaseNumber value
+ */
+ public synchronized int getPhaseNumber() {
+ checkInitialized();
+ return phaseNumber;
+ }
+
+
+ /**
+ * Adds a feature to the ReleaseNodeListener attribute of the XAGraphImpl object
+ * @param l The feature to be added to the ReleaseNodeListener attribute
+ */
+ public synchronized void addReleaseNodeListener(ReleaseNodeListener l) {
+ if (!releaseNodeListeners.contains(l)) releaseNodeListeners.add(l);
+ }
+
+
+ /**
+ * Removes a release node listener.
+ * @param l The listener to remove.
+ */
+ public synchronized void removeReleaseNodeListener(ReleaseNodeListener l) {
+ releaseNodeListeners.remove(l);
+ }
+
+
+ /**
+ * Adds a new triple to the graph if it doesn't already exist.
+ * @param node0 the first element of the new triple
+ * @param node1 the second element of the new triple
+ * @param node2 the third element of the new triple
+ * @param node3 the fourth element of the new triple
+ * @throws StatementStoreException Due to structural or IO errors.
+ */
+ public synchronized void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ checkInitialized();
+ if (
+ node0 < NodePool.MIN_NODE ||
+ node1 < NodePool.MIN_NODE ||
+ node2 < NodePool.MIN_NODE ||
+ node3 < NodePool.MIN_NODE
+ ) {
+ throw new StatementStoreException(
+ "Attempt to add a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3
+ );
+ }
+
+ if (!dirty && currentPhase.isInUse()) {
+ try {
+ new Phase();
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+ currentPhase.addTriple(node0, node1, node2, node3);
+ }
+
+
+ /**
+ * Removes all triples matching the given specification.
+ * @param node0 the value for the first element of the triples
+ * @param node1 the value for the second element of the triples
+ * @param node2 the value for the third element of the triples
+ * @param node3 the value for the fourth element of the triples
+ * @throws StatementStoreException if something exceptional happens
+ */
+ public synchronized void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ checkInitialized();
+ if (node0 != NONE && node1 != NONE && node2 != NONE && node3 != NONE) {
+ if (!dirty && currentPhase.isInUse()) {
+ try {
+ new Phase();
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+ // Remove the triple.
+ currentPhase.removeTriple(node0, node1, node2, node3);
+ } else {
+ // Find all the tuples matching the specification and remove them.
+ StoreTuples tuples = currentPhase.findTuples(node0, node1, node2, node3);
+ try {
+ try {
+ if (!tuples.isEmpty()) {
+ // There is at least one triple to remove so protect the
+ // Tuples as we make changes to the triplestore.
+ try {
+ new Phase();
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+
+ long[] triple = new long[] { node0, node1, node2, node3 };
+ int[] columnMap = tuples.getColumnOrder();
+ int nrColumns = columnMap.length;
+ tuples.beforeFirst();
+ while (tuples.next()) {
+ // Copy the row data over to the triple.
+ for (int col = 0; col < nrColumns; ++col) {
+ triple[columnMap[col]] = tuples.getColumnValue(col);
+ }
+
+ currentPhase.removeTriple(triple[0], triple[1], triple[2], triple[3]);
+ }
+ }
+ } finally {
+ tuples.close();
+ }
+ } catch (TuplesException ex) {
+ throw new StatementStoreException("Exception while iterating over temporary Tuples.", ex);
+ }
+ }
+ }
+
+
+ /**
+ * Finds triples matching the given specification.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A set of all the triples which match the search.
+ * @throws StatementStoreException Due to a structural or IO error.
+ */
+ public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ checkInitialized();
+ dirty = false;
+ return currentPhase.findTuples(node0, node1, node2, node3);
+ }
+
+
+ /**
+ * Finds triples matching the given specification and index mask.
+ * @param mask The mask of the index to use. This is only allowable for 3 variables
+ * and a given graph.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A set of all the triples which match the search.
+ * @throws StatementStoreException Due to a structural or IO error.
+ */
+ public synchronized StoreTuples findTuples(
+ int mask, long node0, long node1, long node2, long node3
+ ) throws StatementStoreException {
+ checkInitialized();
+ dirty = false;
+ if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
+ return currentPhase.findTuples(mask, node0, node1, node2, node3);
+ }
+
+
+ /**
+ * Tests a mask for consistency against the nodes it will be used to find.
+ * @param mask The mask to test.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find. Must not be NONE.
+ * @return <code>true</code> if the mask is consistent with the given nodes.
+ */
+ private static boolean checkMask(int mask, long node0, long node1, long node2, long node3) {
+ // The graph must be bound
+ if (node3 != NONE) return false;
+ if (node0 != NONE && 0 == (mask & MASK0)) return false;
+ if (node1 != NONE && 0 == (mask & MASK1)) return false;
+ if (node2 != NONE && 0 == (mask & MASK2)) return false;
+ return true;
+ }
+
+
+ /**
+ * Returns a StoreTuples which contains all triples in the store. The
+ * parameters provide a hint about how the StoreTuples will be used. This
+ * information is used to select the index from which the StoreTuples will be
+ * obtained.
+ * @param node0Bound specifies that node0 will be bound
+ * @param node1Bound specifies that node1 will be bound
+ * @param node2Bound specifies that node2 will be bound
+ * @return the {@link StoreTuples}
+ * @throws StatementStoreException if something exceptional happens
+ */
+ public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+ checkInitialized();
+ dirty = false;
+ return currentPhase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
+ }
+
+
+ /**
+ * Returns <code>true</code> if any triples match the given specification.
+ * Allows wild cards StatementStore.NONE for any of the node numbers except node3.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return <code>true</code> if any matching triples exist in the graph.
+ * @throws StatementStoreException Due to a structural or IO error.
+ */
+ public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ checkInitialized();
+ return currentPhase.existsTriples(node0, node1, node2, node3);
+ }
+
+
+ public XAStatementStore newReadOnlyStatementStore() {
+ return new ReadOnlyGraph();
+ }
+
+
+ public XAStatementStore newWritableStatementStore() {
+ return this;
+ }
+
+
+ /**
+ * Close all files, removing empty space from the ends as required.
+ * @throws StatementStoreException if an error occurs while truncating,
+ * flushing or closing one of the three files.
+ */
+ public synchronized void close() throws StatementStoreException {
+ try {
+ unmap();
+ } finally {
+ try {
+ IOException savedEx = null;
+
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ try {
+ if (tripleAVLFiles[i] != null) tripleAVLFiles[i].close();
+ } catch (IOException ex) {
+ savedEx = ex;
+ }
+ }
+
+ if (metarootFile != null) {
+ try {
+ metarootFile.close();
+ } catch (IOException ex) {
+ savedEx = ex;
+ }
+ }
+
+ if (savedEx != null) throw new StatementStoreException("I/O error closing graph.", savedEx);
+ } finally {
+ if (lockFile != null) {
+ lockFile.release();
+ lockFile = null;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Close this graph, if it is currently open, and remove all files associated with it.
+ * @throws StatementStoreException Due to an IO error.
+ */
+ public synchronized void delete() throws StatementStoreException {
+ currentPhase = null;
+ try {
+ unmap();
+ } finally {
+ try {
+ IOException savedEx = null;
+
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ try {
+ if (tripleAVLFiles[i] != null) tripleAVLFiles[i].delete();
+ } catch (IOException ex) {
+ savedEx = ex;
+ }
+ }
+
+ if (metarootFile != null) {
+ try {
+ metarootFile.delete();
+ } catch (IOException ex) {
+ savedEx = ex;
+ }
+ }
+
+ if (savedEx != null) throw new StatementStoreException("I/O error deleting graph.", savedEx);
+ } finally {
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i] = null;
+ metarootFile = null;
+ if (lockFile != null) {
+ lockFile.release();
+ lockFile = null;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Try to safely close the store if this was not done explicitly.
+ */
+ protected void finalize() {
+ try {
+ close();
+ } catch (Throwable t) {
+ logger.warn("Exception in finalize while trying to close the statement store.", t);
+ }
+ }
+
+
+ /**
+ * A manually tracked reference to this object was released. Does nothing.
+ */
+ public void release() {
+ if (logger.isDebugEnabled()) logger.debug("Release " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+
+ /**
+ * This in called in response to the resource being manually refreshed.
+ * This implementation does nothing here.
+ */
+ public void refresh() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Refresh " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+ }
+
+
+ //
+ // Methods from SimpleXAResource.
+ //
+
+ /**
+ * Clears this store to a fresh state.
+ * @param phaseNumber The phase number to set to.
+ * @throws IOException Error with file access
+ * @throws SimpleXAResourceException Error with the data structures.
+ */
+ public synchronized void clear(int phaseNumber) throws IOException, SimpleXAResourceException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Clear(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+ if (currentPhase != null) throw new IllegalStateException("Graph already has a current phase.");
+
+ openMetarootFile(true);
+
+ synchronized (committedPhaseLock) {
+ committedPhaseToken = new Phase().use();
+ }
+ this.phaseNumber = phaseNumber;
+ phaseIndex = 1;
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].clear();
+
+ new Phase();
+ }
+
+
+ /**
+ * Clear the state of the database.
+ * @throws IOException Filesystem error
+ * @throws SimpleXAResourceException Error in the data structures.
+ */
+ public synchronized void clear() throws IOException, SimpleXAResourceException {
+ if (logger.isDebugEnabled()) logger.debug("Clear " + this.getClass() + ":" + System.identityHashCode(this));
+ if (currentPhase == null) clear(0);
+
+ // could throw an exception if clear() is called after any other
+ // operations are performed. Calling clear() multiple times should be
+ // permitted.
+ }
+
+
+ /**
+ * Perform all the operations for a commit and return when all the data structures are in place.
+ * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error while preparing.
+ */
+ public synchronized void prepare() throws SimpleXAResourceException {
+ if (logger.isDebugEnabled()) logger.debug("Prepare " + this.getClass() + ":" + System.identityHashCode(this));
+ checkInitialized();
+
+ // check that prepare() was not caleld twice
+ if (prepared) throw new SimpleXAResourceException("prepare() called twice.");
+
+ try {
+ // Perform a prepare.
+ recordingPhaseToken = currentPhase.use();
+ Phase recordingPhase = currentPhase;
+ new Phase();
+
+ // Ensure that all data associated with the phase is on disk.
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFiles[i].force();
+
+ // Write the metaroot.
+ int newPhaseIndex = 1 - phaseIndex;
+ int newPhaseNumber = phaseNumber + 1;
+
+ Block block = metarootBlocks[newPhaseIndex];
+ block.putInt(IDX_VALID, 0); // should already be invalid.
+ block.putInt(IDX_PHASE_NUMBER, newPhaseNumber);
+ logger.debug("Writing graph metaroot for phase: " + newPhaseNumber);
+ recordingPhase.writeToBlock(block, HEADER_SIZE_LONGS);
+ block.write();
+ metarootFile.force();
+ block.putInt(IDX_VALID, 1);
+ block.write();
+ metarootFile.force();
+
+ phaseIndex = newPhaseIndex;
+ phaseNumber = newPhaseNumber;
+ prepared = true;
+ } catch (IOException ex) {
+ logger.error("I/O error while performing prepare.", ex);
+ throw new SimpleXAResourceException("I/O error while performing prepare.", ex);
+ } finally {
+ if (!prepared) {
+ // Something went wrong. An exception is on its way out
+ logger.error("Prepare failed.");
+ if (recordingPhaseToken != null) {
+ recordingPhaseToken.release();
+ recordingPhaseToken = null;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Update the metadata to point to the prepared data structures.
+ * @throws SimpleXAResourceException Due to a bad transaction state, or an IO error.
+ */
+ public synchronized void commit() throws SimpleXAResourceException {
+ if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
+
+ // check that prepare has been called
+ if (!prepared) throw new SimpleXAResourceException("commit() called without previous prepare().");
+
+ // Perform a commit.
+ try {
+ // Invalidate the metaroot of the old phase.
+ Block block = metarootBlocks[1 - phaseIndex];
+ block.putInt(IDX_VALID, 0);
+ block.write();
+ metarootFile.force();
+
+ // Release the token for the previously committed phase.
+ synchronized (committedPhaseLock) {
+ if (committedPhaseToken != null) committedPhaseToken.release();
+ committedPhaseToken = recordingPhaseToken;
+ committedGraphNodes = currentPhase.graphNodes;
+ }
+ recordingPhaseToken = null;
+ } catch (IOException ex) {
+ logger.fatal("I/O error while performing commit.", ex);
+ throw new SimpleXAResourceException("I/O error while performing commit.", ex);
+ } finally {
+ prepared = false;
+ if (recordingPhaseToken != null) {
+ // Something went wrong! An exception is on its way out
+ recordingPhaseToken.release();
+ recordingPhaseToken = null;
+
+ logger.error("Commit failed. Calling close().");
+ try {
+ close();
+ } catch (Throwable t) {
+ logger.error("Exception on forced close()", t);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Read the state from the metaroot file and use it to set up this object
+ * @return An array of 0, 1, or 2 valid phases that can be selected as the last committed phase.
+ * @throws SimpleXAResourceException Due to an IO error, or a data error in the metaroot file.
+ */
+ public synchronized int[] recover() throws SimpleXAResourceException {
+ if (logger.isDebugEnabled()) logger.debug("Recover " + this.getClass() + ":" + System.identityHashCode(this));
+ if (currentPhase != null) return new int[0];
+ if (wrongFileVersion) throw new SimpleXAResourceException("Wrong metaroot file version.");
+
+ try {
+ openMetarootFile(false);
+ } catch (IOException ex) {
+ throw new SimpleXAResourceException("I/O error", ex);
+ }
+
+ // Count the number of valid phases.
+ int phaseCount = 0;
+ if (metarootBlocks[0].getInt(IDX_VALID) != 0) ++phaseCount;
+ if (metarootBlocks[1].getInt(IDX_VALID) != 0) ++phaseCount;
+
+ // Read the phase numbers.
+ int[] phaseNumbers = new int[phaseCount];
+ int index = 0;
+ if (metarootBlocks[0].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[0].getInt(IDX_PHASE_NUMBER);
+ if (metarootBlocks[1].getInt(IDX_VALID) != 0) phaseNumbers[index++] = metarootBlocks[1].getInt(IDX_PHASE_NUMBER);
+ return phaseNumbers;
+ }
+
+
+ /**
+ * Choose a phase from the metaroot file to use
+ * @param phaseNumber The number of the phase to select. This must be one of the valid
+ * phases present in the metaroot file.
+ * @throws IOException Due to an error on the filesystem
+ * @throws SimpleXAResourceException If the file structures are incorrect.
+ */
+ public synchronized void selectPhase(int phaseNumber) throws IOException, SimpleXAResourceException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("SelectPhase(" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+ if (currentPhase != null) throw new SimpleXAResourceException("selectPhase() called on initialized Graph.");
+ if (metarootFile == null) throw new SimpleXAResourceException("Graph metaroot file is not open.");
+
+ // Locate the metaroot corresponding to the given phase number.
+ if (
+ metarootBlocks[0].getInt(IDX_VALID) != 0 &&
+ metarootBlocks[0].getInt(IDX_PHASE_NUMBER) == phaseNumber
+ ) {
+ phaseIndex = 0;
+ // A new phase will be saved in the other metaroot.
+ } else if (
+ metarootBlocks[1].getInt(IDX_VALID) != 0 &&
+ metarootBlocks[1].getInt(IDX_PHASE_NUMBER) == phaseNumber
+ ) {
+ phaseIndex = 1;
+ // A new phase will be saved in the other metaroot.
+ } else {
+ throw new SimpleXAResourceException("Invalid phase number: " + phaseNumber);
+ }
+
+ // Load a duplicate of the selected phase. The duplicate will have a
+ // phase number which is one higher than the original phase.
+ try {
+ synchronized (committedPhaseLock) {
+ committedPhaseToken = new Phase(metarootBlocks[phaseIndex], HEADER_SIZE_LONGS).use();
+ }
+ this.phaseNumber = phaseNumber;
+ } catch (IllegalStateException ex) {
+ throw new SimpleXAResourceException("Cannot construct initial phase.", ex);
+ }
+ new Phase();
+
+ // Invalidate the on-disk metaroot that the new phase will be saved to.
+ Block block = metarootBlocks[1 - phaseIndex];
+ block.putInt(IDX_VALID, 0);
+ block.write();
+ metarootFile.force();
+ }
+
+
+ /**
+ * Return to the data structure state from the beginning of the transaction.
+ * @throws SimpleXAResourceException Due to an IO error.
+ */
+ public synchronized void rollback() throws SimpleXAResourceException {
+ if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
+ checkInitialized();
+ try {
+ if (prepared) {
+ // Restore phaseIndex and phaseNumber to their previous values.
+ phaseIndex = 1 - phaseIndex;
+ --phaseNumber;
+ recordingPhaseToken = null;
+ prepared = false;
+
+ // Invalidate the metaroot of the other phase.
+ Block block = metarootBlocks[1 - phaseIndex];
+ block.putInt(IDX_VALID, 0);
+ block.write();
+ metarootFile.force();
+ }
+ } catch (IOException ex) {
+ throw new SimpleXAResourceException("I/O error while performing rollback (invalidating metaroot)", ex);
+ } finally {
+ try {
+ new Phase(committedPhaseToken.getPhase());
+ } catch (IOException ex) {
+ throw new SimpleXAResourceException("I/O error while performing rollback (new committed phase)", ex);
+ }
+ }
+ }
+
+
+ /**
+ * Get a string representation of the current state of the graph.
+ * @return A string representing the current state
+ */
+ public synchronized String toString() {
+ if (currentPhase == null) return "Uninitialized Graph.";
+ return currentPhase.toString();
+ }
+
+
+ /**
+ * Attempt to cleanly close all mapped files.
+ */
+ public synchronized void unmap() {
+ if (committedPhaseToken != null) {
+ recordingPhaseToken = null;
+ prepared = false;
+
+ try {
+ new Phase(committedPhaseToken.getPhase());
+ } catch (Throwable t) {
+ logger.warn("Exception while rolling back in unmap()", t);
+ }
+ currentPhase = null;
+
+ synchronized (committedPhaseLock) {
+ committedPhaseToken.release();
+ committedPhaseToken = null;
+ }
+ }
+
+ if (tripleAVLFiles != null) {
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ if (tripleAVLFiles[i] != null) tripleAVLFiles[i].unmap();
+ }
+ }
+
+ if (metarootFile != null) {
+ if (metarootBlocks[0] != null) metarootBlocks[0] = null;
+ if (metarootBlocks[1] != null) metarootBlocks[1] = null;
+ metarootFile.unmap();
+ }
+ }
+
+
+ /**
+ * Check that the data structures are valid
+ * @return The number of triples in the database
+ */
+ synchronized long checkIntegrity() {
+ checkInitialized();
+ return currentPhase.checkIntegrity();
+ }
+
+
+ /**
+ * Open the metaroot file and read in the contents
+ * @param clear If <code>true</code> then the file will be reset to empty.
+ * @throws IOException Due to a filesystem error.
+ * @throws SimpleXAResourceException If the data structures are inconsistent.
+ */
+ private void openMetarootFile(boolean clear) throws IOException, SimpleXAResourceException {
+ if (metarootFile == null) {
+ metarootFile = AbstractBlockFile.openBlockFile(fileName + ".g", METAROOT_SIZE * Constants.SIZEOF_LONG, BlockFile.IOType.EXPLICIT);
+
+ long nrBlocks = metarootFile.getNrBlocks();
+ if (nrBlocks != NR_METAROOTS) {
+ if (nrBlocks > 0) {
+ logger.info("Graph metaroot file for triple store \"" + fileName + "\" has invalid number of blocks: " + nrBlocks);
+ if (nrBlocks < NR_METAROOTS) {
+ clear = true;
+ metarootFile.clear();
+ }
+ } else {
+ // Perform initialization on empty file.
+ clear = true;
+ }
+ metarootFile.setNrBlocks(NR_METAROOTS);
+ }
+
+ metarootBlocks[0] = metarootFile.readBlock(0);
+ metarootBlocks[1] = metarootFile.readBlock(1);
+ }
+
+ if (clear) {
+ // Invalidate the metaroots on disk.
+ metarootBlocks[0].putInt(IDX_MAGIC, FILE_MAGIC);
+ metarootBlocks[0].putInt(IDX_VERSION, FILE_VERSION);
+ metarootBlocks[0].putInt(IDX_VALID, 0);
+ metarootBlocks[0].write();
+ metarootBlocks[1].putInt(IDX_MAGIC, 0);
+ metarootBlocks[1].putInt(IDX_VERSION, 0);
+ metarootBlocks[1].putInt(IDX_VALID, 0);
+ metarootBlocks[1].write();
+ metarootFile.force();
+ }
+ }
+
+
+ /**
+ * Tests that the current object has been initialized.
+ * @throws IllegalStateException Throws this unchecked exception if the object is not initialized.
+ */
+ private void checkInitialized() {
+ if (currentPhase == null) throw new IllegalStateException("No current phase. Graph has not been initialized or has been closed.");
+ }
+
+
+ final class ReadOnlyGraph implements XAStatementStore {
+
+ private Phase phase = null;
+
+ private Phase.Token token = null;
+
+
+ /**
+ * Create a read-only graph attached to the current outer database
+ */
+ ReadOnlyGraph() {
+ synchronized (committedPhaseLock) {
+ if (committedPhaseToken == null) {
+ throw new IllegalStateException("Cannot create read only view of uninitialized Graph.");
+ }
+ }
+ }
+
+
+ public synchronized boolean isEmpty() {
+ return phase.isEmpty();
+ }
+
+
+ /**
+ * Returns a count of the number of triples in the graph
+ * @return a count of the number of triples in the graph
+ */
+ public synchronized long getNrTriples() {
+ return phase.getNrTriples();
+ }
+
+
+ /**
+ * Adds a triple to the graph.
+ * @param node0 The 0 node of the triple.
+ * @param node1 The 1 node of the triple.
+ * @param node2 The 2 node of the triple.
+ * @param node3 The 3 node of the triple.
+ */
+ public void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ throw new UnsupportedOperationException("Trying to modify a read-only graph.");
+ }
+
+
+ /**
+ * Removes all triples matching the given specification.
+ * @param node0 the value for the first element of the triples
+ * @param node1 the value for the second element of the triples
+ * @param node2 the value for the third element of the triples
+ * @param node3 the value for the fourth element of the triples
+ */
+ public void removeTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ throw new UnsupportedOperationException("Trying to modify a read-only graph.");
+ }
+
+
+ /**
+ * Finds triples matching the given specification.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A StoreTuples which contains the triples which match the search.
+ */
+ public synchronized StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ return phase.findTuples(node0, node1, node2, node3);
+ }
+
+ /**
+ * Finds triples matching the given specification.
+ * @param mask The mask of the index to use. This is only allowable for 3 variables
+ * and a given graph.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A StoreTuples which contains the triples which match the search.
+ * @throws StatementStoreException A structural or IO error
+ */
+ public synchronized StoreTuples findTuples(int mask, long node0, long node1, long node2, long node3) throws StatementStoreException {
+ if (!checkMask(mask, node0, node1, node2, node3)) throw new StatementStoreException("Bad explicit index selection for given node pattern.");
+ return phase.findTuples(mask, node0, node1, node2, node3);
+ }
+
+
+ /**
+ * Returns a StoreTuples which contains all triples in the store. The
+ * parameters provide a hint about how the StoreTuples will be used. This
+ * information is used to select the index from which the StoreTuples will
+ * be obtained.
+ * @param node0Bound specifies that node0 will be bound
+ * @param node1Bound specifies that node1 will be bound
+ * @param node2Bound specifies that node2 will be bound
+ * @return the {@link StoreTuples}
+ * @throws StatementStoreException if something exceptional happens
+ */
+ public synchronized StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+ return phase.findTuples(node0Bound, node1Bound, node2Bound, node3Bound);
+ }
+
+
+ public synchronized boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ return phase.existsTriples(node0, node1, node2, node3);
+ }
+
+
+ public XAStatementStore newReadOnlyStatementStore() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public XAStatementStore newWritableStatementStore() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public void close() {
+ throw new UnsupportedOperationException("Trying to close a read-only graph.");
+ }
+
+
+ public void delete() {
+ throw new UnsupportedOperationException("Trying to delete a read-only graph.");
+ }
+
+
+ /**
+ * Release the phase.
+ */
+ public synchronized void release() {
+ if (logger.isDebugEnabled()) logger.debug("Releasing " + this.getClass() + ":" + System.identityHashCode(this));
+ try {
+ if (token != null) token.release();
+ } finally {
+ phase = null;
+ token = null;
+ }
+ }
+
+
+ public synchronized void refresh() {
+ if (logger.isDebugEnabled()) logger.debug("Refreshing " + this.getClass() + ":" + System.identityHashCode(this));
+
+ synchronized (committedPhaseLock) {
+ Phase committedPhase = committedPhaseToken.getPhase();
+ if (phase != committedPhase) {
+ if (token != null) token.release();
+ phase = committedPhase;
+ token = phase.use();
+ }
+ }
+ }
+
+ public void addReleaseNodeListener(ReleaseNodeListener l) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeReleaseNodeListener(ReleaseNodeListener l) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void prepare() {
+ if (logger.isDebugEnabled()) logger.debug("Preparing " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+ public void commit() {
+ if (logger.isDebugEnabled()) logger.debug("Commit " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+ public void rollback() {
+ if (logger.isDebugEnabled()) logger.debug("Rollback " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+ public void clear() {
+ if (logger.isDebugEnabled()) logger.debug("Clearing " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+ public void clear(int phaseNumber) {
+ if (logger.isDebugEnabled()) logger.debug("Clearing (" + phaseNumber + ") " + this.getClass() + ":" + System.identityHashCode(this));
+ }
+
+ public int[] recover() {
+ if (logger.isDebugEnabled()) logger.debug("Recovering " + this.getClass() + ":" + System.identityHashCode(this));
+ throw new UnsupportedOperationException("Attempting to recover ReadOnlyGraph");
+ }
+
+ public void selectPhase(int phaseNumber) {
+ if (logger.isDebugEnabled()) logger.debug("Selecting Phase " + this.getClass() + ":" + System.identityHashCode(this));
+ throw new UnsupportedOperationException("Attempting to selectPhase of ReadOnlyGraph");
+ }
+
+ public int getPhaseNumber() {
+ return phaseNumber;
+ }
+
+
+ /**
+ * Not used on a read-only graph
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ // do nothing
+ }
+ }
+
+
+ /**
+ * This class represents the state of the the database at a particular time. Only the most
+ * recent phase can be written to.
+ */
+ final class Phase implements PersistableMetaRoot {
+
+ /** The size of the data this object stores in the metaroot */
+ final static int RECORD_SIZE = TripleAVLFile.Phase.RECORD_SIZE * NR_INDEXES;
+
+ /** Maintaines parallel structural phases between all of the parallel tree data structures */
+ private TripleAVLFile.Phase[] tripleAVLFilePhases = new TripleAVLFile.Phase[NR_INDEXES];
+
+ /** The list of graphs valid in this phase. */
+ private List<Long> graphNodes = null;
+
+
+ /**
+ * Creates a new phase based on the current state of the database.
+ * This sets the latest phase on the outer statement store.
+ * @throws IOException Error on the filesystem.
+ */
+ Phase() throws IOException {
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase();
+ currentPhase = this;
+ dirty = true;
+ try {
+ graphNodes = committedGraphNodes == null ? scanForGraphs() : new ArrayList<Long>(committedGraphNodes);
+ } catch (StatementStoreException e) {
+ throw new IOException("Unable to get metadata for phase: " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * A copy constructor for duplicating a phase structure. This sets the latest phase
+ * on the outer statement store.
+ * @throws IOException Error on the filesystem.
+ */
+ Phase(Phase p) throws IOException {
+ assert p != null;
+
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(p.tripleAVLFilePhases[i]);
+ currentPhase = this;
+ dirty = true;
+ graphNodes = new ArrayList<Long>(p.graphNodes);
+ }
+
+
+ /**
+ * Create a phase based on information found in a buffer that came from a metaroot
+ * @param b The buffer containing the phase information.
+ * @param offset The start of the phase information in the buffer
+ * @throws IOException A filesystem error occurred while accessing the buffer.
+ */
+ Phase(Block b, int offset) throws IOException {
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ tripleAVLFilePhases[i] = tripleAVLFiles[i].new Phase(b, offset);
+ offset += TripleAVLFile.Phase.RECORD_SIZE;
+ }
+ currentPhase = this;
+ dirty = false;
+ try {
+ graphNodes = scanForGraphs();
+ } catch (StatementStoreException sse) {
+ throw new IOException("Error accessing graph data during initialization");
+ }
+ }
+
+
+ /**
+ * Writes this PersistableMetaRoot to the specified Block. The ints are
+ * written at the specified offset.
+ * @param b The metaroot Block to write this object to.
+ * @param offset The start within the buffer of where the phase information should be written to.
+ */
+ public void writeToBlock(Block b, int offset) {
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ tripleAVLFilePhases[i].writeToBlock(b, offset);
+ offset += TripleAVLFile.Phase.RECORD_SIZE;
+ }
+ }
+
+
+ /**
+ * Create a string representation of the current phase.
+ * @return A string representing this phase
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ StoreTuples ts = tripleAVLFilePhases[i].allTuples();
+ try {
+ sb.append(ts).append('\n');
+ } finally {
+ try {
+ ts.close();
+ } catch (TuplesException ex) {
+ logger.warn("TuplesException while closing Tuples", ex);
+ return ex.toString();
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Tests if any part of this phase has a reference being kept to it
+ * @return <code>true</code> if any part of this phase is being used.
+ */
+ boolean isInUse() {
+ for (int i = 0; i < NR_INDEXES; ++i) {
+ if (tripleAVLFilePhases[i].isInUse()) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Tests if the phase contains any triples
+ * @return <code>true</code> if the phase contains 1 or more triples
+ */
+ boolean isEmpty() {
+ return tripleAVLFilePhases[TI_3012].isEmpty();
+ }
+
+
+ /**
+ * Gets the number of triples in the phase
+ * @return The number of triples in this phase
+ */
+ long getNrTriples() {
+ return tripleAVLFilePhases[TI_3012].getNrTriples();
+ }
+
+
+ /**
+ * Adds a new triple to the graph if it doesn't already exist.
+ * @param node0 the first element of the new triple
+ * @param node1 the second element of the new triple
+ * @param node2 the third element of the new triple
+ * @param node3 the fourth element of the new triple
+ * @throws StatementStoreException An IO or data structure error
+ */
+ void addTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ assert node0 >= NodePool.MIN_NODE;
+ assert node1 >= NodePool.MIN_NODE;
+ assert node2 >= NodePool.MIN_NODE;
+ assert node3 >= NodePool.MIN_NODE;
+
+ //if (
+ // DEBUG && nodePool != null &&
+ // !nodePool.isValid(node0) && !nodePool.isValid(node1) &&
+ // !nodePool.isValid(node2) && !nodePool.isValid(node3)
+ //) throw new AssertionError(
+ // "Attempt to add a triple with an invalid node"
+ //);
+
+ long[] triple = new long[]{node0, node1, node2, node3};
+
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].asyncAddTriple(triple);
+
+ if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.add(node0);
+ }
+
+
+ /**
+ * Removes the specified triple.
+ * @param node0 the value for the first element of the triple
+ * @param node1 the value for the second element of the triple
+ * @param node2 the value for the third element of the triple
+ * @param node3 the value for the fourth element of the triple
+ * @throws StatementStoreException An IO or structural error
+ */
+ void removeTriple(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ if (
+ node0 < NodePool.MIN_NODE ||
+ node1 < NodePool.MIN_NODE ||
+ node2 < NodePool.MIN_NODE ||
+ node3 < NodePool.MIN_NODE
+ ) {
+ throw new StatementStoreException("Attempt to remove a triple with node number out of range: " + node0 + " " + node1 + " " + node2 + " " + node3);
+ }
+
+ try {
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFilePhases[i].removeTriple(node0, node1, node2, node3);
+ // removeTriple listeners can be informed here
+ } catch (IOException e) {
+ throw new StatementStoreException("I/O error", e);
+ }
+ if (node1 == rdfTypeNode && node2 == graphTypeNode && node3 == systemGraphNode) graphNodes.remove(node0);
+ }
+
+
+ /**
+ * Finds triples matching the given specification.
+ * @param variableMask the mask used to indicate the desired index.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A StoreTuples containing all the triples which match the search.
+ * @throws StatementStoreException An IO or structural error
+ */
+ StoreTuples findTuples(int variableMask, long node0, long node1, long node2, long node3) throws StatementStoreException {
+ if (
+ node0 < NodePool.NONE ||
+ node1 < NodePool.NONE ||
+ node2 < NodePool.NONE ||
+ node3 < NodePool.NONE
+ ) {
+ // There is at least one query node. Return an empty StoreTuples.
+ return TuplesOperations.empty();
+ }
+
+ if (0 == (variableMask & MASK3)) throw new StatementStoreException("This version of find is for re-ordering graphs, based on a given mask.");
+ try {
+ switch (variableMask) {
+ case MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3);
+ case MASK0 | MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3);
+ case MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3120].findTuples(node3);
+ case MASK0 | MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3);
+ case MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].findTuples(node3);
+ case MASK0 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].findTuples(node3);
+ case MASK1 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3120].findTuples(node3);
+ case MASK0 | MASK1 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3);
+ default:
+ throw new AssertionError();
+ }
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+
+ /**
+ * Finds triples matching the given specification.
+ * @param node0 The 0 node of the triple to find.
+ * @param node1 The 1 node of the triple to find.
+ * @param node2 The 2 node of the triple to find.
+ * @param node3 The 3 node of the triple to find.
+ * @return A StoreTuples containing all the triples which match the search.
+ * @throws StatementStoreException An IO or structural error
+ */
+ StoreTuples findTuples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ if (
+ node0 < NodePool.NONE ||
+ node1 < NodePool.NONE ||
+ node2 < NodePool.NONE ||
+ node3 < NodePool.NONE
+ ) {
+ // There is at least one query node. Return an empty StoreTuples.
+ return TuplesOperations.empty();
+ }
+
+ int variableMask =
+ (node0 != NONE ? MASK0 : 0) |
+ (node1 != NONE ? MASK1 : 0) |
+ (node2 != NONE ? MASK2 : 0) |
+ (node3 != NONE ? MASK3 : 0);
+
+ if (node3 == NONE && variableMask != 0) {
+ return joinGraphedTuples(variableMask, node0, node1, node2);
+ }
+
+
+ try {
+ switch (variableMask) {
+ case 0:
+ return tripleAVLFilePhases[TI_3012].allTuples();
+ case MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3);
+ case MASK0 | MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3, node0);
+ case MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3120].findTuples(node3, node1);
+ case MASK0 | MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3012].findTuples(node3, node0, node1);
+ case MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].findTuples(node3, node2);
+ case MASK0 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].findTuples(node3, node2, node0);
+ case MASK1 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3120].findTuples(node3, node1, node2);
+ case MASK0 | MASK1 | MASK2 | MASK3:
+ if (tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2)) {
+ return TuplesOperations.unconstrained();
+ }
+ return TuplesOperations.empty();
+ default:
+ throw new AssertionError("Search structure incorrectly calculated");
+ }
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+
+ StoreTuples findTuples(boolean node0Bound, boolean node1Bound, boolean node2Bound, boolean node3Bound) throws StatementStoreException {
+ // The variable mask does not need MASK3, as this has been taken into account in selectIndex[]
+ int variableMask =
+ (node0Bound ? MASK0 : 0) |
+ (node1Bound ? MASK1 : 0) |
+ (node2Bound ? MASK2 : 0);
+ if (variableMask == 0 || node3Bound) {
+ return tripleAVLFilePhases[selectIndex[variableMask]].allTuples();
+ } else {
+ return joinGraphedTuples(variableMask);
+ }
+ }
+
+
+ /**
+ * Iterates over all graphs, finding requested tuples, and joining all the results together into a single tuples.
+ * @param variableMask Pre-calculated from the bound node parameters.
+ * @param node0 The bound value for node0, or < 0 if not bound.
+ * @param node1 The bound value for node1, or < 0 if not bound.
+ * @param node2 The bound value for node2, or < 0 if not bound.
+ * @return A StoreTuples with all the intermediate tuples appended.
+ * @throws StatementStoreException On an error accessing the store.
+ */
+ StoreTuples joinGraphedTuples(int variableMask, long node0, long node1, long node2) throws StatementStoreException {
+ try {
+ assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
+
+ // get the graphNodes if not already configured
+ if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
+
+ if (variableMask == (MASK0 | MASK1 | MASK2)) {
+ LiteralGraphTuples result = new LiteralGraphTuples(false);
+ for (long graphNode: graphNodes) {
+ if (tripleAVLFilePhases[TI_3012].existsTriple(node0, node1, node2, graphNode)) {
+ result.appendTuple(new long[] { graphNode });
+ }
+ }
+ return result;
+ }
+
+ ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
+ for (long graphNode: graphNodes) {
+ StoreTuples partialResult = null;
+ switch (variableMask) {
+ case 0:
+ partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode);
+ break;
+ case MASK0:
+ partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0);
+ break;
+ case MASK1:
+ partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1);
+ break;
+ case MASK0 | MASK1:
+ partialResult = tripleAVLFilePhases[TI_3012].findTuplesForMeta(graphNode, node0, node1);
+ break;
+ case MASK2:
+ partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2);
+ break;
+ case MASK0 | MASK2:
+ partialResult = tripleAVLFilePhases[TI_3201].findTuplesForMeta(graphNode, node2, node0);
+ break;
+ case MASK1 | MASK2:
+ partialResult = tripleAVLFilePhases[TI_3120].findTuplesForMeta(graphNode, node1, node2);
+ break;
+ default:
+ throw new AssertionError("Search structure incorrectly calculated");
+ }
+ graphedTuples.add(partialResult);
+ }
+ return TuplesOperations.appendCompatible(graphedTuples);
+ } catch (TuplesException te) {
+ throw new StatementStoreException("Error accessing Tuples", te);
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+
+ /**
+ * Iterates over all graphs, getting all tuples in the requested order,
+ * and joining all the results together into a single tuples.
+ * @param variableMask Determines the required ordering of the data.
+ * @return A StoreTuples with all the intermediate tuples appended.
+ * @throws StatementStoreException On an error accessing the store.
+ */
+ StoreTuples joinGraphedTuples(int variableMask) throws StatementStoreException {
+ try {
+ assert (variableMask & MASK3) == 0 : "Must not be asking to join on multiple graphs unless graph is variable.";
+
+ // get the graphNodes if not already configured
+ if (graphNodes.isEmpty()) throw new IllegalStateException("Unable to query for variable graphs until graphs are initialized");
+
+ ArrayList<StoreTuples> graphedTuples = new ArrayList<StoreTuples>();
+ for (long graphNode: graphNodes) {
+ int phaseIndex;
+ switch (variableMask) {
+ case 0:
+ case MASK0:
+ case MASK0 | MASK1:
+ case MASK0 | MASK1 | MASK2:
+ phaseIndex = TI_3012;
+ break;
+ case MASK1:
+ case MASK1 | MASK2:
+ phaseIndex = TI_3120;
+ break;
+ case MASK2:
+ case MASK0 | MASK2:
+ phaseIndex = TI_3201;
+ break;
+ default:
+ throw new AssertionError("Search structure incorrectly calculated");
+ }
+ StoreTuples partialResult = tripleAVLFilePhases[phaseIndex].findTuplesForMeta(graphNode);
+ graphedTuples.add(partialResult);
+ }
+ return TuplesOperations.appendCompatible(graphedTuples);
+ } catch (TuplesException te) {
+ throw new StatementStoreException("Error accessing Tuples", te);
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+
+ /**
+ * Test is there exist triples according to a given pattern
+ * @param node0 A subject gNode, or NONE
+ * @param node1 A predicate gNode, or NONE
+ * @param node2 A object gNode, or NONE
+ * @param node3 A subject gNode. May not be NONE
+ * @return <code>true</code> if there exist triples that match the pattern
+ * @throws StatementStoreException A structural or IO exception
+ */
+ boolean existsTriples(long node0, long node1, long node2, long node3) throws StatementStoreException {
+ if (node3 == NONE) throw new IllegalStateException("Graph must be specified");
+
+ if (
+ node0 < NodePool.NONE ||
+ node1 < NodePool.NONE ||
+ node2 < NodePool.NONE ||
+ node3 < NodePool.NONE
+ ) {
+ // There is at least one query node (comes from the query, but not in the data pool).
+ // Return an empty StoreTuples.
+ return false;
+ }
+
+ int variableMask =
+ (node0 != NONE ? MASK0 : 0) |
+ (node1 != NONE ? MASK1 : 0) |
+ (node2 != NONE ? MASK2 : 0) |
+ MASK3;
+
+ try {
+ switch (variableMask) {
+ case MASK3:
+ return tripleAVLFilePhases[TI_3012].existsTriples(node3);
+ case MASK0 | MASK3:
+ return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0);
+ case MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1);
+ case MASK0 | MASK1 | MASK3:
+ return tripleAVLFilePhases[TI_3012].existsTriples(node3, node0, node1);
+ case MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2);
+ case MASK0 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3201].existsTriples(node3, node2, node0);
+ case MASK1 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3120].existsTriples(node3, node1, node2);
+ case MASK0 | MASK1 | MASK2 | MASK3:
+ return tripleAVLFilePhases[TI_3012].existsTriple(node3, node0, node1, node2);
+ default:
+ throw new AssertionError("Search structure incorrectly calculated");
+ }
+ } catch (IOException ex) {
+ throw new StatementStoreException("I/O error", ex);
+ }
+ }
+
+
+ /**
+ * Check that each index contains the same number of triples
+ * @throws AssertionError if the indexes contain a differing number of triples
+ */
+ long checkIntegrity() {
+ long nrTriples[] = new long[NR_INDEXES];
+
+ for (int i = 0; i < NR_INDEXES; ++i) nrTriples[i] = tripleAVLFilePhases[i].checkIntegrity();
+
+ for (int i = 1; i < NR_INDEXES; ++i) {
+ if (nrTriples[0] != nrTriples[i]) {
+ StringBuffer sb = new StringBuffer("tripleAVLFiles disagree on the number of triples:");
+ for (int j = 0; j < NR_INDEXES; ++j) sb.append(' ').append(nrTriples[j]);
+ throw new AssertionError(sb.toString());
+ }
+ }
+
+ return nrTriples[0];
+ }
+
+
+ /**
+ * Ask the system for all the known graphs.
+ * @return All the known graph nodes.
+ */
+ List<Long> scanForGraphs() throws StatementStoreException, IOException {
+ List<Long> nodeList = new ArrayList<Long>();
+
+ if (systemGraphNode == NONE || rdfTypeNode == NONE || graphTypeNode == NONE) return nodeList;
+
+ StoreTuples graphTuples = tripleAVLFilePhases[TI_3120].findTuples(systemGraphNode, rdfTypeNode, graphTypeNode);
+ assert graphTuples.getNumberOfVariables() == 1;
+
+ try {
+ graphTuples.beforeFirst();
+ while (graphTuples.next()) nodeList.add(graphTuples.getColumnValue(0));
+ } catch (TuplesException e) {
+ throw new StatementStoreException("Unable to construct a result containing all graphs.", e);
+ }
+
+ return nodeList;
+ }
+
+
+ /**
+ * Increment the reference count on this object.
+ * @return A new token representing the reference.
+ */
+ Token use() {
+ return new Token();
+ }
+
+
+ /**
+ * A token to reference the phase, incrementing the reference count from the perpective
+ * of the garbage collector.
+ */
+ final class Token {
+
+ /** A list of tokens from the underlying indexes */
+ private TripleAVLFile.Phase.Token[] tripleAVLFileTokens = new TripleAVLFile.Phase.Token[NR_INDEXES];
+
+ /** The phase being referenced */
+ private Phase phase = Phase.this;
+
+
+ /**
+ * Creates a token. This creates tokens for the underlying objects as well.
+ */
+ Token() {
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i] = tripleAVLFilePhases[i].use();
+ }
+
+
+ /**
+ * Get the phase that this token represents.
+ * @return The phase referenced by this token.
+ */
+ public Phase getPhase() {
+ assert tripleAVLFileTokens != null : "Invalid Token";
+ return phase;
+ }
+
+
+ /**
+ * Reduce the reference count on the referenced phase by releasing this token.
+ * The token may not be used after being released.
+ */
+ public void release() {
+ assert tripleAVLFileTokens != null : "Invalid Token";
+ for (int i = 0; i < NR_INDEXES; ++i) tripleAVLFileTokens[i].release();
+ tripleAVLFileTokens = null;
+ phase = null;
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @see org.mulgara.store.xa.XAStatementStore#initializeSystemNodes(long, long, long)
+ * Set the various system graph nodes. These may only be set once, but will allow duplicate calls if the values are the same.
+ * @param systemGraphNode The new system graph node.
+ * @param rdfTypeNode The node for <rdf:graph>.
+ * @param systemGraphTypeNode The node for the system graph type.
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) {
+ if (this.systemGraphNode != NONE && systemGraphNode != this.systemGraphNode) {
+ throw new IllegalStateException("Cannot set system graph again. Was: " + this.systemGraphNode + ", now: " + systemGraphNode);
+ }
+ if (systemGraphNode < 0) throw new IllegalArgumentException("Attempt to set invalid system graph node");
+ this.systemGraphNode = systemGraphNode;
+
+ if (this.rdfTypeNode != NONE && rdfTypeNode != this.rdfTypeNode) {
+ throw new IllegalStateException("Cannot set the rdf:type node again. Was: " + this.rdfTypeNode + ", now: " + rdfTypeNode);
+ }
+ if (rdfTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid rdf:type node");
+ this.rdfTypeNode = rdfTypeNode;
+
+ if (this.graphTypeNode != NONE && systemGraphTypeNode != this.graphTypeNode) {
+ throw new IllegalStateException("Cannot set graph type again. Was: " + this.graphTypeNode + ", now: " + systemGraphTypeNode);
+ }
+ if (systemGraphTypeNode < 0) throw new IllegalArgumentException("Attempt to set invalid graph type node");
+ this.graphTypeNode = systemGraphTypeNode;
+ }
+
+}
Deleted: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java
===================================================================
--- branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1,166 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is the Kowari Metadata Store.
- *
- * The Initial Developer of the Original Code is Plugged In Software Pty
- * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
- * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
- * Plugged In Software Pty Ltd. All Rights Reserved.
- *
- * Contributor(s): N/A.
- *
- * [NOTE: The text of this Exhibit A may differ slightly from the text
- * of the notices in the Source Code files of the Original Code. You
- * should use the text of this Exhibit A rather than the text found in the
- * Original Code Source Code for Your Modifications.]
- *
- */
-package org.mulgara.store.statement.xa11;
-
-// Java 2 standard packages
-import java.io.*;
-
-// JUnit
-import junit.framework.*;
-
-// log4j
-import org.apache.log4j.*;
-
-// locally written packages
-import org.mulgara.store.statement.*;
-import org.mulgara.store.tuples.TestTuples;
-import org.mulgara.util.*;
-
-
-/**
- * Test case for {@link XA11StatementStoreImpl}.
- *
- * @author <a href="http://staff.pisoftware.com/david">David Makepeace</a>
- * @author <a href="http://staff.pisoftware.com/pag">Paul Gearon</a>
- * @copyright ©2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
- * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
- */
-public class XA11StatementStoreImplUnitTest extends StatementStoreAbstractUnitTest {
-
- /** Logger. */
- @SuppressWarnings("unused")
- private final static Logger logger = Logger.getLogger(XA11StatementStoreImplUnitTest.class);
-
- /**
- * start of filenames to build the graph with.
- */
- private final static String DBFILENAME = "graphtest";
-
- /**
- * Description of the Field
- */
- private XA11StatementStoreImpl xaStore;
-
-
- /**
- * Named constructor.
- *
- * @param name The name of the test.
- */
- public XA11StatementStoreImplUnitTest(String name) {
- super(name);
- }
-
-
- /**
- * Hook for test runner to obtain a test suite from.
- *
- * @return The test suite to run.
- */
- public static Test suite() {
- return new TestSuite(XA11StatementStoreImplUnitTest.class);
- //TestSuite suite = new TestSuite();
- //suite.addTest(new GraphImplTest("testRemoveTriples"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode0"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode1"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode2"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode01"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode02"));
- //suite.addTest(new GraphImplTest("testFindTriplesByNode12"));
- //return suite;
- }
-
-
- /**
- * Default test runner.
- *
- * @param args The command line arguments
- */
- public static void main(String[] args) {
-
- junit.textui.TestRunner.run(suite());
- }
-
-
- /**
- * A method to call for each graph before running tests on it.
- *
- * @throws Exception EXCEPTION TO DO
- */
- protected void setUp() throws Exception {
- boolean exceptionOccurred = true;
- try {
- // create the graph object, using a new file
- store = new XA11StatementStoreImpl(
- TempDir.getTempDir().getPath() + File.separatorChar + DBFILENAME
- );
- xaStore = (XA11StatementStoreImpl) store;
- xaStore.clear();
- super.setUp();
- exceptionOccurred = false;
- }
- finally {
- if (exceptionOccurred) {
- tearDown();
- }
- }
- }
-
-
- /**
- * The teardown method for JUnit
- *
- * @throws Exception EXCEPTION TO DO
- */
- protected void tearDown() throws Exception {
- if (xaStore != null) {
- xaStore.unmap();
- if (System.getProperty("os.name").startsWith("Win")) {
- // Need this for Windows or truncate() always fails for mapped files.
- System.gc();
- System.runFinalization();
- }
- }
- super.tearDown();
- }
-
- /**
- * Return a dump of all tuples, sorted by the primary index: 3012.
- * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
- */
- protected TestTuples getDump() {
- TestTuples expected = new TestTuples();
- add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
- add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
- add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
- add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
- add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
- add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
- return expected;
- }
-
-}
Copied: trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java (from rev 1456, branches/xa11/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java)
===================================================================
--- trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java (rev 0)
+++ trunk/src/jar/resolver-store/java/org/mulgara/store/statement/xa11/XA11StatementStoreImplUnitTest.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,166 @@
+/*
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is the Kowari Metadata Store.
+ *
+ * The Initial Developer of the Original Code is Plugged In Software Pty
+ * Ltd (http://www.pisoftware.com, mailto:info at pisoftware.com). Portions
+ * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
+ * Plugged In Software Pty Ltd. All Rights Reserved.
+ *
+ * Contributor(s): N/A.
+ *
+ * [NOTE: The text of this Exhibit A may differ slightly from the text
+ * of the notices in the Source Code files of the Original Code. You
+ * should use the text of this Exhibit A rather than the text found in the
+ * Original Code Source Code for Your Modifications.]
+ *
+ */
+package org.mulgara.store.statement.xa11;
+
+// Java 2 standard packages
+import java.io.*;
+
+// JUnit
+import junit.framework.*;
+
+// log4j
+import org.apache.log4j.*;
+
+// locally written packages
+import org.mulgara.store.statement.*;
+import org.mulgara.store.tuples.TestTuples;
+import org.mulgara.util.*;
+
+
+/**
+ * Test case for {@link XA11StatementStoreImpl}.
+ *
+ * @author <a href="http://staff.pisoftware.com/david">David Makepeace</a>
+ * @author <a href="http://staff.pisoftware.com/pag">Paul Gearon</a>
+ * @copyright ©2001-2004 <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
+ * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
+ */
+public class XA11StatementStoreImplUnitTest extends StatementStoreAbstractUnitTest {
+
+ /** Logger. */
+ @SuppressWarnings("unused")
+ private final static Logger logger = Logger.getLogger(XA11StatementStoreImplUnitTest.class);
+
+ /**
+ * start of filenames to build the graph with.
+ */
+ private final static String DBFILENAME = "graphtest";
+
+ /**
+ * Description of the Field
+ */
+ private XA11StatementStoreImpl xaStore;
+
+
+ /**
+ * Named constructor.
+ *
+ * @param name The name of the test.
+ */
+ public XA11StatementStoreImplUnitTest(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Hook for test runner to obtain a test suite from.
+ *
+ * @return The test suite to run.
+ */
+ public static Test suite() {
+ return new TestSuite(XA11StatementStoreImplUnitTest.class);
+ //TestSuite suite = new TestSuite();
+ //suite.addTest(new GraphImplTest("testRemoveTriples"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode0"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode1"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode2"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode01"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode02"));
+ //suite.addTest(new GraphImplTest("testFindTriplesByNode12"));
+ //return suite;
+ }
+
+
+ /**
+ * Default test runner.
+ *
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+
+ junit.textui.TestRunner.run(suite());
+ }
+
+
+ /**
+ * A method to call for each graph before running tests on it.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ protected void setUp() throws Exception {
+ boolean exceptionOccurred = true;
+ try {
+ // create the graph object, using a new file
+ store = new XA11StatementStoreImpl(
+ TempDir.getTempDir().getPath() + File.separatorChar + DBFILENAME
+ );
+ xaStore = (XA11StatementStoreImpl) store;
+ xaStore.clear();
+ super.setUp();
+ exceptionOccurred = false;
+ }
+ finally {
+ if (exceptionOccurred) {
+ tearDown();
+ }
+ }
+ }
+
+
+ /**
+ * The teardown method for JUnit
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ protected void tearDown() throws Exception {
+ if (xaStore != null) {
+ xaStore.unmap();
+ if (System.getProperty("os.name").startsWith("Win")) {
+ // Need this for Windows or truncate() always fails for mapped files.
+ System.gc();
+ System.runFinalization();
+ }
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Return a dump of all tuples, sorted by the primary index: 3012.
+ * @see org.mulgara.store.statement.StatementStoreAbstractUnitTest#getDump()
+ */
+ protected TestTuples getDump() {
+ TestTuples expected = new TestTuples();
+ add(expected, StatementStore.VARIABLES, new long[] {1, 2, 3, 1});
+ add(expected, StatementStore.VARIABLES, new long[] {1, 2, 4, 2});
+ add(expected, StatementStore.VARIABLES, new long[] {2, 5, 6, 2});
+ add(expected, StatementStore.VARIABLES, new long[] {1, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ add(expected, StatementStore.VARIABLES, new long[] {2, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ add(expected, StatementStore.VARIABLES, new long[] {SYSTEM_GRAPH, RDF_TYPE, GRAPH_TYPE, SYSTEM_GRAPH});
+ return expected;
+ }
+
+}
Modified: trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java
===================================================================
--- trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-stringpool-memory/java/org/mulgara/store/stringpool/memory/MemoryStringPoolImpl.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -694,7 +694,7 @@
/**
* Copied from AbstractTuples
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
Modified: trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java
===================================================================
--- trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-stringpool-xa11/java/org/mulgara/store/stringpool/xa11/XA11StringPoolImpl.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -2085,7 +2085,7 @@
/**
* Copied from AbstractTuples
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
Modified: trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java
===================================================================
--- trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/store-xa/java/org/mulgara/store/xa/XAStatementStore.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -84,4 +84,12 @@
*/
public void delete() throws StatementStoreException;
+ /**
+ * Informs the statement store of the metadata it uses for managing data.
+ * @param systemGraphNode The node for the system graph.
+ * @param rdfTypeNode The node representing <rdf:type>.
+ * @param systemGraphTypeNode The node used for the SystemResolver graph type.
+ */
+ public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode);
+
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/AbstractTuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -69,6 +69,7 @@
private final static Variable[] emptyVariables = new Variable[] {};
/** Description of the Field */
+ @SuppressWarnings("unused")
private final static long[] NO_PREFIX = new long[] {};
/** Description of the Field */
@@ -577,7 +578,7 @@
variables = variableArray;
}
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/DefinablePrefixAnnotation.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -42,10 +42,6 @@
package org.mulgara.store.tuples;
// JDK packages
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
// Third party packages
@@ -73,5 +69,5 @@
*
* @param boundVars variables available to be bound in beforeFirst.
*/
- public void definePrefix(Set boundVars) throws TuplesException;
+ public void definePrefix(Set<Variable> boundVars) throws TuplesException;
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/LeftJoin.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -51,7 +51,6 @@
*/
public class LeftJoin extends AbstractTuples implements ContextOwner {
- @SuppressWarnings("unused")
private static Logger logger = Logger.getLogger(LeftJoin.class.getName());
/** The set of tuples to return all row from. */
@@ -576,7 +575,7 @@
}
/** @see org.mulgara.store.tuples.Tuples#getAnnotation(java.lang.Class) */
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return wrapped.getAnnotation(annotationClass);
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedAppend.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -75,7 +75,7 @@
/**
* The propositions to conjoin.
*/
- private final Tuples[] operands;
+ protected final Tuples[] operands;
/**
* The return value of the {@link #beforeFirst} method.
@@ -233,7 +233,7 @@
}
- public List getOperands() {
+ public List<Tuples> getOperands() {
return Arrays.asList(operands);
}
@@ -351,13 +351,13 @@
public Variable[] getVariables() {
// Container for our variables
- ArrayList variablesList = new ArrayList();
+ ArrayList<Variable> variablesList = new ArrayList<Variable>();
// Iterate through the tuples objects and get the variables for each
for (int index = 0; index < operands.length; index++) {
// Get the array of variables for the current tuples object
- Variable [] variableArray = operands[index].getVariables();
+ Variable[] variableArray = operands[index].getVariables();
// We need to prevent duplicate variables so iterate through the new array
// and remove duplicates
@@ -372,17 +372,17 @@
}
// Convert the list to an array
- Variable [] newVariables = new Variable [variablesList.size()];
- newVariables = (Variable []) variablesList.toArray(newVariables);
+ Variable[] newVariables = new Variable[variablesList.size()];
+ newVariables = variablesList.toArray(newVariables);
return newVariables;
}
- public Annotation getAnnotation(Class annotation) {
+ public Annotation getAnnotation(Class<? extends Annotation> annotation) {
if (annotation.equals(DefinablePrefixAnnotation.class) && prefixDefinable) {
return new DefinablePrefixAnnotation() {
- public void definePrefix(Set boundVars) throws TuplesException {
+ public void definePrefix(Set<Variable> boundVars) throws TuplesException {
for (int i = 0; i < operands.length; i++) {
DefinablePrefixAnnotation annotation =
(DefinablePrefixAnnotation)operands[i].getAnnotation(DefinablePrefixAnnotation.class);
Copied: trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java (from rev 1456, branches/xa11/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java)
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java (rev 0)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/OrderedStoreAppend.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Fedora Commons, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.store.tuples;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * A class for performing appends between identically structured StoreTuples.
+ *
+ * @created Dec 17, 2008
+ * @author Paul Gearon
+ * @copyright © 2005 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
+ */
+public class OrderedStoreAppend extends OrderedAppend implements StoreTuples {
+
+ /**
+ * @param operands
+ * @throws TuplesException
+ */
+ public OrderedStoreAppend(StoreTuples[] operands) throws TuplesException {
+ super(operands);
+ assert operands.length >= 2 : "Performing join on fewer than 2 operands";
+ assert operandsMatch(operands) : "Operands do not match in OrderedStoreAppend";
+ }
+
+ /**
+ * @see org.mulgara.store.tuples.StoreTuples#getColumnOrder()
+ */
+ public int[] getColumnOrder() {
+ return ((StoreTuples)operands[0]).getColumnOrder();
+ }
+
+ /**
+ * Test if all the operands match, like they are supposed to.
+ * @param operands The operands to test.
+ * @return <code>true</code> iff the operands all share column ordering.
+ */
+ private boolean operandsMatch(StoreTuples[] operands) {
+ int[] order = operands[0].getColumnOrder();
+ for (int i = 1; i < operands.length; i++) {
+ int[] newOrder = operands[i].getColumnOrder();
+ if (newOrder.length != order.length) return false;
+ for (int c = 0; c < order.length; c++) if (newOrder[c] != order[c]) return false;
+ }
+ return true;
+ }
+
+}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/Tuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -274,5 +274,5 @@
*
* @return An annotation of the class requested, or null if none exists.
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException;
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException;
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -46,33 +46,17 @@
* {@link Variable}s to {@link Value}s.
*
* @created 2003-01-30
- *
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
- *
- * @version $Revision: 1.12 $
- *
- * @modified $Date: 2005/05/16 11:07:10 $
- *
- * @maintenanceAuthor $Author: amuys $
- *
* @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
- * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
- * Software Pty Ltd</A>
- *
+ * @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In Software Pty Ltd</A>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public abstract class TuplesOperations {
- /**
- * Logger. This is named after the class.
- */
- private final static Logger logger =
- Logger.getLogger(TuplesOperations.class.getName());
+ /** Logger. This is named after the class. */
+ private final static Logger logger = Logger.getLogger(TuplesOperations.class.getName());
- /**
- * The factory used to generate new {@link Tuples} instances.
- */
+ /** The factory used to generate new {@link Tuples} instances. */
private static TuplesFactory tuplesFactory = TuplesFactory.newInstance();
/**
@@ -82,10 +66,9 @@
* value to a tuples generates an empty result.
*
* @return the expression which is never satisfied, no matter what value any
- * variable takes
+ * variable takes
*/
public static StoreTuples empty() {
-
return EmptyTuples.getInstance();
}
@@ -101,7 +84,6 @@
* @return the expression which is always true, for any value of any variables
*/
public static StoreTuples unconstrained() {
-
return UnconstrainedTuples.getInstance();
}
@@ -109,12 +91,11 @@
* Assign a value to a variable, representing the binding as a tuples with one
* row and one column.
*
- * @param variable PARAMETER TO DO
- * @param value PARAMETER TO DO
- * @return RETURNED VALUE TO DO
+ * @param variable The variable to bind
+ * @param value The value in local space to bind the variable to
+ * @return A Tuples with the variable bound to the given value.
*/
public static Tuples assign(Variable variable, long value) {
-
return (value == Tuples.UNBOUND) ? (Tuples)unconstrained()
: new Assignment(variable, value);
}
@@ -122,9 +103,9 @@
/**
* This is approximately a disjunction.
*
- * @param lhs PARAMETER TO DO
- * @param rhs PARAMETER TO DO
- * @return RETURNED VALUE TO DO
+ * @param lhs The first Tuples to be used in the result.
+ * @param rhs The second Tuples to be used in the result.
+ * @return A new Tuples containing all of the bindings from the lhs and rhs parameters.
* @throws TuplesException if the append fails
*/
public static Tuples append(Tuples lhs, Tuples rhs) throws TuplesException {
@@ -132,10 +113,16 @@
}
+ /**
+ * Creates a new Tuples which contains all of the bindings of the Tuples in the argument list.
+ * If any tuples contains variables not found in the other Tuples, then those values will
+ * remain unbound for the bindings of those Tuples missing those variables.
+ * @param args A list of the Tuples to be used in the result.
+ * @return A Tuples containing all of the bindings from the args list.
+ * @throws TuplesException If the data could not be appended.
+ */
public static Tuples append(List<? extends Tuples> args) throws TuplesException {
- if (logger.isDebugEnabled()) {
- logger.debug("Appending " + args);
- }
+ if (logger.isDebugEnabled()) logger.debug("Appending " + args);
HashSet<Variable> variableSet = new HashSet<Variable>();
List<Variable> variables = new ArrayList<Variable>();
@@ -147,25 +134,18 @@
Tuples operand = i.next();
if (operand.isUnconstrained()) {
closeOperands(operands);
- if (logger.isDebugEnabled()) {
- logger.debug("Returning unconstrained from append.");
- }
+ if (logger.isDebugEnabled()) logger.debug("Returning unconstrained from append.");
return unconstrained();
} else if (operand.getRowCardinality() == Cursor.ZERO) {
- if (logger.isDebugEnabled()) {
- logger.debug("Ignoring append operand " + operand + " with rowcount = " + operand.getRowCount());
- }
+ if (logger.isDebugEnabled()) logger.debug("Ignoring append operand " + operand + " with rowcount = " + operand.getRowCount());
continue;
}
operands.add((Tuples)operand.clone());
Variable[] vars = operand.getVariables();
- if (leftVars == null) {
- leftVars = vars;
- } else {
- unionCompat = unionCompat && Arrays.equals(leftVars, vars);
- }
+ if (leftVars == null) leftVars = vars;
+ else unionCompat = unionCompat && Arrays.equals(leftVars, vars);
for (int j = 0; j < vars.length; j++) {
if (!variableSet.contains(vars[j])) {
variableSet.add(vars[j]);
@@ -174,22 +154,16 @@
}
}
- if (logger.isDebugEnabled()) {
- logger.debug("Operands after append-unification: " + operands);
- }
+ if (logger.isDebugEnabled()) logger.debug("Operands after append-unification: " + operands);
if (operands.isEmpty()) {
- if (logger.isDebugEnabled()) {
- logger.debug("Returning empty from append.");
- }
+ if (logger.isDebugEnabled()) logger.debug("Returning empty from append.");
return empty();
}
if (operands.size() == 1) {
- if (logger.isDebugEnabled()) {
- logger.debug("Returning singleton from append.");
- }
- return (Tuples)operands.get(0);
+ if (logger.isDebugEnabled()) logger.debug("Returning singleton from append.");
+ return operands.get(0);
}
if (unionCompat) {
@@ -202,9 +176,7 @@
return result;
} else {
List<Tuples> projected = new ArrayList<Tuples>();
- i = operands.iterator();
- while (i.hasNext()) {
- Tuples operand = i.next();
+ for (Tuples operand: operands) {
Tuples proj = project(operand, variables);
Tuples sorted = sort(proj);
projected.add(sorted);
@@ -212,9 +184,7 @@
operand.close();
}
- if (logger.isDebugEnabled()) {
- logger.debug("Returning OrderedAppend from Non-Union compatible append.");
- }
+ if (logger.isDebugEnabled()) logger.debug("Returning OrderedAppend from Non-Union compatible append.");
Tuples result = new OrderedAppend(projected.toArray(new Tuples[projected.size()]));
closeOperands(projected);
return result;
@@ -223,49 +193,97 @@
/**
- * This is approximately a conjunction.
+ * Creates a new Tuples which contains all of the bindings of the Tuples in the argument list.
+ * All tuples must have an identical pattern, and come directly from the store.
+ * @param args A list of the Tuples directly backed by the store to be used in the result.
+ * @return A StoreTuples containing all of the bindings from the args list.
+ * @throws TuplesException If the data could not be appended.
*/
+ public static StoreTuples appendCompatible(List<StoreTuples> args) throws TuplesException {
+ if (logger.isDebugEnabled()) logger.debug("Compatible append of " + args);
+
+ Variable[] vars = null;
+ List<StoreTuples> operands = new ArrayList<StoreTuples>();
+ for (StoreTuples arg: args) {
+
+ // test for empty or unconstrained data
+ if (arg.isUnconstrained()) {
+ closeOperands(operands);
+ if (logger.isDebugEnabled()) logger.debug("Returning unconstrained from append.");
+ return unconstrained();
+ } else if (arg.getRowCardinality() == Cursor.ZERO) {
+ if (logger.isDebugEnabled()) logger.debug("Ignoring append operand " + arg + " with rowcount = " + arg.getRowCount());
+ continue;
+ }
+
+ operands.add((StoreTuples)arg.clone());
+
+ // test for tuples compatibility
+ if (vars == null) vars = arg.getVariables();
+ else if (!Arrays.equals(vars, arg.getVariables())) {
+ throw new IllegalArgumentException("Incompatible arguments to appendCompatible");
+ }
+
+ }
+
+ if (logger.isDebugEnabled()) logger.debug("Operands after compatible-append-unification: " + operands);
+
+ if (operands.isEmpty()) {
+ if (logger.isDebugEnabled()) logger.debug("Returning empty from append.");
+ return empty();
+ }
+
+ if (operands.size() == 1) {
+ if (logger.isDebugEnabled()) logger.debug("Returning singleton from append.");
+ return operands.get(0);
+ }
+
+ StoreTuples result = new OrderedStoreAppend(operands.toArray(new StoreTuples[operands.size()]));
+ closeOperands(operands);
+ return result;
+ }
+
+
+ /**
+ * Convenience method for doing a binary {@link #join(List)}.
+ * @param lhs The first argument to be joined.
+ * @param rhs The second argument to be joined.
+ * @return A Tuples containing the conjunction of lhs and rhs.
+ */
public static Tuples join(Tuples lhs, Tuples rhs) throws TuplesException {
return join(Arrays.asList(new Tuples[] { lhs, rhs }));
}
+ /**
+ * This is approximately a conjunction. Returns a set of bindings containing all the variables
+ * from both parameters. The only bindings returned are those where all the matching variables
+ * in each argument are bound to the same values.
+ * @param args The Tuples to be joined together.
+ * @return A Tuples containing the conjunction of all the arguments.
+ */
public static Tuples join(List<? extends Tuples> args) throws TuplesException {
try {
- if (logger.isDebugEnabled()) {
- logger.debug(printArgs("Flattening args:", args));
- }
+ if (logger.isDebugEnabled()) logger.debug(printArgs("Flattening args:", args));
List<Tuples> operands = flattenOperands(args);
- if (logger.isDebugEnabled()) {
- logger.debug(printArgs("Unifying args: ", operands));
- }
+ if (logger.isDebugEnabled()) logger.debug(printArgs("Unifying args: ", operands));
List<Tuples> unified = unifyOperands(operands);
- if (logger.isDebugEnabled()) {
- logger.debug(printArgs("Sorting args:", unified));
- }
+ if (logger.isDebugEnabled()) logger.debug(printArgs("Sorting args:", unified));
List<Tuples> sorted = sortOperands(unified);
- if (logger.isDebugEnabled()) {
- logger.debug(printArgs("Preparing result: ", sorted));
- }
+ if (logger.isDebugEnabled()) logger.debug(printArgs("Preparing result: ", sorted));
switch (sorted.size()) {
case 0:
- if (logger.isDebugEnabled()) {
- logger.debug("Short-circuit empty");
- }
+ if (logger.isDebugEnabled()) logger.debug("Short-circuit empty");
return empty();
case 1:
- if (logger.isDebugEnabled()) {
- logger.debug("Short-circuit singleton");
- }
- return (Tuples)sorted.get(0);
+ if (logger.isDebugEnabled()) logger.debug("Short-circuit singleton");
+ return sorted.get(0);
default:
- if (logger.isDebugEnabled()) {
- logger.debug("return UnboundJoin");
- }
+ if (logger.isDebugEnabled()) logger.debug("return UnboundJoin");
Tuples result = new UnboundJoin(sorted.toArray(new Tuples[sorted.size()]));
closeOperands(sorted);
return result;
@@ -291,10 +309,7 @@
*/
public static Tuples subtract(Tuples minuend, Tuples subtrahend) throws TuplesException {
try {
-
- if (logger.isDebugEnabled()) {
- logger.debug("subtracting " + subtrahend + " from " + minuend);
- }
+ if (logger.isDebugEnabled()) logger.debug("subtracting " + subtrahend + " from " + minuend);
// get the matching columns
Set<Variable> matchingVars = getMatchingVars(minuend, subtrahend);
if (matchingVars.isEmpty()) {
@@ -327,9 +342,7 @@
try {
return new Difference(minuend, sortedSubtrahend);
} finally {
- if (sortedSubtrahend != subtrahend) {
- sortedSubtrahend.close();
- }
+ if (sortedSubtrahend != subtrahend) sortedSubtrahend.close();
}
} catch (RuntimeException re) {
@@ -355,9 +368,7 @@
public static Tuples optionalJoin(Tuples standard, Tuples optional, Filter filter, QueryEvaluationContext context) throws TuplesException {
try {
- if (logger.isDebugEnabled()) {
- logger.debug("optional join of " + standard + " optional { " + optional + " }");
- }
+ if (logger.isDebugEnabled()) logger.debug("optional join of " + standard + " optional { " + optional + " }");
// get the matching columns
Set<Variable> matchingVars = getMatchingVars(standard, optional);
@@ -387,9 +398,7 @@
}
// yes, there are extra variables
- if (logger.isDebugEnabled()) {
- logger.debug("sorting on the common variables: " + matchingVars);
- }
+ if (logger.isDebugEnabled()) logger.debug("sorting on the common variables: " + matchingVars);
// re-sort the optional according to the matching variables
// reorder the optional as necessary
Tuples sortedOptional = reSort(optional, new ArrayList<Variable>(matchingVars));
@@ -413,27 +422,29 @@
/**
* Flattens any nested joins to allow polyadic join operations.
+ * @param A list of Tuples which may in turn be nested operations.
+ * @return A flattened list of flattened Tuples.
*/
private static List<Tuples> flattenOperands(List<? extends Tuples> operands) throws TuplesException {
List<Tuples> result = new ArrayList<Tuples>();
- for (Tuples operand: operands) {
- result.addAll(flattenOperand(operand));
- }
-
+ for (Tuples operand: operands) result.addAll(flattenOperand(operand));
return result;
}
+ /**
+ * Flattens a Tuples into a list of Tuples. This means that joins will be expanded into their components.
+ * @param operand The Tuples to flatten
+ * @return A flattened list.
+ * @throws TuplesException If the Tuples could not be accessed.
+ */
private static List<Tuples> flattenOperand(Tuples operand) throws TuplesException {
List<Tuples> operands = new ArrayList<Tuples>();
if (operand instanceof UnboundJoin) {
- for (Tuples op: operand.getOperands()) {
- operands.add((Tuples)op.clone());
- }
+ for (Tuples op: operand.getOperands()) operands.add((Tuples)op.clone());
} else {
operands.add((Tuples)operand.clone());
}
-
return operands;
}
@@ -442,7 +453,6 @@
* Unifies bound variables in operands.
* Prepends a LiteralTuples containing constrained variable bindings.
* If any operand returns 0-rows returns EmptyTuples.
- *
* @param operands List of Tuples to unify. Consumed by this function.
* @return List of operands remaining after full unification.
*/
@@ -456,7 +466,7 @@
}
List<Tuples> result = extractNonReresolvableTuples(operands);
- // operands is not effectively a List<ReresolvableResolution>
+ // operands is now effectively a List<ReresolvableResolution>
List<ReresolvableResolution> reresolved;
do {
@@ -466,6 +476,7 @@
closeOperands(result);
closeOperands(reresolved);
logger.debug("Returning empty due to shortcircuiting progressive bindSingleRowOperands");
+ // wrap in an Array list to convert the generic type
return new ArrayList<Tuples>(Collections.singletonList(empty()));
}
operands.addAll(reresolved);
@@ -481,8 +492,7 @@
/**
* Extracts all bound names from workingSet into bindings.
*/
- private static boolean bindSingleRowOperands(Map<Variable,Long> bindings, List<? extends Tuples> workingSet)
- throws TuplesException {
+ private static boolean bindSingleRowOperands(Map<Variable,Long> bindings, List<? extends Tuples> workingSet) throws TuplesException {
Iterator<? extends Tuples> iter = workingSet.iterator();
while (iter.hasNext()) {
Tuples tuples = iter.next();
@@ -498,22 +508,15 @@
for (int i = 0; i < vars.length; i++) {
Long value = new Long(tuples.getColumnValue(tuples.getColumnIndex(vars[i])));
Long oldValue = (Long)bindings.put(vars[i], value);
- if (oldValue != null && !value.equals(oldValue)) {
- return false;
- }
+ if (oldValue != null && !value.equals(oldValue)) return false;
}
} else {
// This should not happen.
// If the call to getRowCardinality returns > 0 then beforeFirst,
// and then next should return true too.
- logger.error(
- "No rows but getRowCardinality returned Cursor.ONE: (class=" +
- tuples.getClass().getName() + ") " + tuples.toString() + "\n" +
- new StackTrace()
- );
- throw new AssertionError(
- "No rows but getRowCardinality returned Cursor.ONE"
- );
+ logger.error("No rows but getRowCardinality returned Cursor.ONE: (class=" +
+ tuples.getClass().getName() + ") " + tuples.toString() + "\n" + new StackTrace());
+ throw new AssertionError("No rows but getRowCardinality returned Cursor.ONE");
}
iter.remove();
tuples.close();
@@ -531,8 +534,7 @@
}
- private static List<Tuples> extractNonReresolvableTuples(List<Tuples> workingSet)
- throws TuplesException {
+ private static List<Tuples> extractNonReresolvableTuples(List<Tuples> workingSet) throws TuplesException {
List<Tuples> nonReresolvable = new ArrayList<Tuples>(workingSet.size());
Iterator<Tuples> iter = workingSet.iterator();
@@ -554,8 +556,7 @@
* @param workingSet A set of ReresolvableResolution, though it will be represented as a set of Tuples
* @return List of ConstrainedTuples resulting from any resolutions required.
*/
- private static List<ReresolvableResolution> resolveNewlyBoundFreeNames(List<Tuples> workingSet, Map<Variable,Long> bindings)
- throws TuplesException {
+ private static List<ReresolvableResolution> resolveNewlyBoundFreeNames(List<Tuples> workingSet, Map<Variable,Long> bindings) throws TuplesException {
List<ReresolvableResolution> reresolved = new ArrayList<ReresolvableResolution>();
Iterator<Tuples> iter = workingSet.iterator();
while (iter.hasNext()) {
@@ -572,19 +573,14 @@
}
- private static Tuples createTuplesFromBindings(Map<Variable,Long> bindings)
- throws TuplesException {
- if (bindings.isEmpty()) {
- return unconstrained();
- }
+ private static Tuples createTuplesFromBindings(Map<Variable,Long> bindings) throws TuplesException {
+ if (bindings.isEmpty()) return unconstrained();
Set<Variable> keys = bindings.keySet();
Variable[] vars = keys.toArray(new Variable[keys.size()]);
long[] values = new long[vars.length];
- for (int i = 0; i < values.length; i++) {
- values[i] = bindings.get(vars[i]);
- }
+ for (int i = 0; i < values.length; i++) values[i] = bindings.get(vars[i]);
LiteralTuples tuples = new LiteralTuples(vars);
tuples.appendTuple(values);
@@ -615,9 +611,7 @@
DefinablePrefixAnnotation definable =
(DefinablePrefixAnnotation)bestTuples.getAnnotation(DefinablePrefixAnnotation.class);
- if (definable != null) {
- definable.definePrefix(boundVars);
- }
+ if (definable != null) definable.definePrefix(boundVars);
// Add all variables that don't contain UNBOUND to boundVars set.
// Note: the inefficiency this introduces for distributed results
@@ -627,9 +621,7 @@
// left-operand it becomes unprefixed.
Variable[] vars = bestTuples.getVariables();
for (int i = 0; i < vars.length; i++) {
- if (!bestTuples.isColumnEverUnbound(i)) {
- boundVars.add(vars[i]);
- }
+ if (!bestTuples.isColumnEverUnbound(i)) boundVars.add(vars[i]);
}
result.add(bestTuples);
@@ -640,8 +632,7 @@
// FIXME: Method too long. Refactor.
- private static Tuples removeBestTuples(List<Tuples> operands, Set<Variable> boundVars)
- throws TuplesException {
+ private static Tuples removeBestTuples(List<Tuples> operands, Set<Variable> boundVars) throws TuplesException {
ListIterator<Tuples> iter = operands.listIterator();
Tuples minTuples = null;
double minRowCount = Double.MAX_VALUE;
@@ -652,22 +643,17 @@
logger.debug("removeBestTuples");
while (iter.hasNext()) {
Tuples tuples = (Tuples)iter.next();
- if (logger.isDebugEnabled()) {
- logger.debug("tuples: " + tuplesSummary(tuples));
- }
+ if (logger.isDebugEnabled()) logger.debug("tuples: " + tuplesSummary(tuples));
// Check tuples meets any mandatory left bindings.
MandatoryBindingAnnotation bindingRequirements =
(MandatoryBindingAnnotation)tuples.getAnnotation(MandatoryBindingAnnotation.class);
- if (bindingRequirements != null && !bindingRequirements.meetsRequirement(boundVars)) {
- continue;
- }
+ if (bindingRequirements != null && !bindingRequirements.meetsRequirement(boundVars)) continue;
+
Variable[] vars = tuples.getVariables();
int numLeftBindings = calculateNumberOfLeftBindings(tuples, boundVars);
- if (logger.isDebugEnabled()) {
- logger.debug("numLeftBindings: " + numLeftBindings);
- }
+ if (logger.isDebugEnabled()) logger.debug("numLeftBindings: " + numLeftBindings);
// Basic formula assumes uniform distribution. So number of rows is the
// product of the length of each variable taken seperately, hence expected
@@ -703,32 +689,24 @@
throw new TuplesException("Unable to meet ordering constraints");
}
- if (logger.isDebugEnabled()) {
- logger.debug("Selected: " + tuplesSummary(minTuples) + " with weightedRowCount: " + minRowCount);
- }
+ if (logger.isDebugEnabled()) logger.debug("Selected: " + tuplesSummary(minTuples) + " with weightedRowCount: " + minRowCount);
operands.remove(minIndex);
return minTuples;
}
- private static int calculateNumberOfLeftBindings(Tuples tuples,
- Set<Variable> boundVars) throws TuplesException {
+ private static int calculateNumberOfLeftBindings(Tuples tuples, Set<Variable> boundVars) throws TuplesException {
int numLeftBindings = 0;
Variable[] vars = tuples.getVariables();
// If the tuples supports defining a prefix then
if (tuples.getAnnotation(DefinablePrefixAnnotation.class) != null) {
for (int i = 0; i < vars.length; i++) {
- if (boundVars.contains(vars[i])) {
- numLeftBindings++;
- }
+ if (boundVars.contains(vars[i])) numLeftBindings++;
}
} else {
for (int i = 0; i < vars.length; i++) {
- if (boundVars.contains(vars[i])) {
- numLeftBindings++;
- } else {
- break;
- }
+ if (boundVars.contains(vars[i])) numLeftBindings++;
+ else break;
}
}
@@ -745,18 +723,14 @@
* @return RETURNED VALUE TO DO
* @throws TuplesException if the projection operation fails
*/
- public static Tuples project(Tuples tuples, List<Variable> variableList)
- throws TuplesException {
+ public static Tuples project(Tuples tuples, List<Variable> variableList) throws TuplesException {
try {
boolean noVariables = (variableList == null) || (variableList.size() == 0);
- if (tuples.isUnconstrained() ||
- (noVariables && tuples.getRowCardinality() != Cursor.ZERO)) {
+ if (tuples.isUnconstrained() || (noVariables && tuples.getRowCardinality() != Cursor.ZERO)) {
- if (logger.isDebugEnabled()) {
- logger.debug("returning Unconstrained Tuples.");
- }
+ if (logger.isDebugEnabled()) logger.debug("returning Unconstrained Tuples.");
return TuplesOperations.unconstrained();
} else if (tuples.getRowCardinality() == Cursor.ZERO) {
@@ -766,9 +740,7 @@
} else if ((noVariables) && (tuples instanceof ConstrainedNegationTuples)) {
return empty();
} else {
- if (logger.isDebugEnabled()) {
- logger.debug("Projecting to " + variableList);
- }
+ if (logger.isDebugEnabled()) logger.debug("Projecting to " + variableList);
// Perform the actual projection
Tuples oldTuples = tuples;
@@ -785,12 +757,10 @@
oldTuples = tuples;
tuples = removeDuplicates(tuples);
assert tuples != oldTuples;
- if (tuples == oldTuples) {
- logger.warn("removeDuplicates does not change the underlying tuples");
- } else {
- oldTuples.close();
- }
+ if (tuples == oldTuples) logger.warn("removeDuplicates does not change the underlying tuples");
+ else oldTuples.close();
+
assert tuples.hasNoDuplicates();
return tuples;
@@ -801,6 +771,13 @@
}
+ /**
+ * Creates a new restriction tuples, based on a normal Tuples and a restriction predicate.
+ * @param tuples The tuples to restrict.
+ * @param pred The predicate describing the restriction.
+ * @return A new Tuples whose bindings only match the restriction.
+ * @throws TuplesException If the Tuples could not be accessed.
+ */
public static Tuples restrict(Tuples tuples, RestrictPredicate pred) throws TuplesException {
return new RestrictionTuples(tuples, pred);
}
@@ -823,9 +800,8 @@
/**
* Sort into default order, based on the columns and local node numbers.
- *
* @param tuples the tuples to sort
- * @return RETURNED VALUE TO DO
+ * @return A new Tuples with the bindings sorted.
* @throws TuplesException if the sorting can't be accomplished
*/
public static Tuples sort(Tuples tuples) throws TuplesException {
@@ -835,17 +811,13 @@
} else if (tuples.getRowCardinality() == Cursor.ZERO) {
tuples = empty();
} else {
- if (logger.isDebugEnabled()) {
- logger.debug("Sorting " + tuples.getRowCount() + " rows");
- }
+ if (logger.isDebugEnabled()) logger.debug("Sorting " + tuples.getRowCount() + " rows");
tuples = tuplesFactory.newTuples(tuples);
assert tuples.getComparator() != null;
}
- if (logger.isDebugEnabled()) {
- logger.debug("Sorted " + tuples.getRowCount() + " rows");
- }
+ if (logger.isDebugEnabled()) logger.debug("Sorted " + tuples.getRowCount() + " rows");
return tuples;
} else {
@@ -858,24 +830,15 @@
*
* @param tuples the tuples to sort
* @param rowComparator the ordering
- * @return RETURNED VALUE TO DO
+ * @return A Tuples with bindings sorted according to the rowComparator.
* @throws TuplesException if the sorting can't be accomplished
*/
- public static Tuples sort(Tuples tuples,
- RowComparator rowComparator) throws TuplesException {
-
+ public static Tuples sort(Tuples tuples, RowComparator rowComparator) throws TuplesException {
if (!rowComparator.equals(tuples.getComparator())) {
-
tuples = tuplesFactory.newTuples(tuples, rowComparator);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Sorted: " + tuples + " (using supplied row comparator)");
- }
-
+ if (logger.isDebugEnabled()) logger.debug("Sorted: " + tuples + " (using supplied row comparator)");
return tuples;
- }
- else {
-
+ } else {
return (Tuples) tuples.clone();
}
}
@@ -956,10 +919,9 @@
* @param tuples the instance to limit
* @param rowCount the number of leading rows to retain
* @return the truncated tuples
- * @throws TuplesException EXCEPTION TO DO
+ * @throws TuplesException If there was an error accessing the Tuples.
*/
- public static Tuples limit(Tuples tuples, long rowCount)
- throws TuplesException {
+ public static Tuples limit(Tuples tuples, long rowCount) throws TuplesException {
return new LimitedTuples((Tuples) tuples.clone(), rowCount);
}
@@ -967,17 +929,13 @@
* If a tuples is virtual, evaluate and store it.
*
* @param tuples the instance to materialize
- * @return RETURNED VALUE TO DO
- * @throws TuplesException EXCEPTION TO DO
+ * @return A set of Tuples with any virtual bindings converted into actual bindings.
+ * @throws TuplesException If there was an error evaluating the virtual bindings
*/
public static Tuples materialize(Tuples tuples) throws TuplesException {
-
if (tuples.isMaterialized()) {
-
- return (Tuples) tuples.clone();
- }
- else {
-
+ return (Tuples)tuples.clone();
+ } else {
return tuplesFactory.newTuples(tuples);
}
}
@@ -991,32 +949,27 @@
* @param tuples the instance to offset
* @param rowCount the number of leading rows to remove
* @return the remaining rows, if any
- * @throws TuplesException EXCEPTION TO DO
+ * @throws TuplesException If there was an error accessing the tuples.
*/
- public static Tuples offset(Tuples tuples, long rowCount)
- throws TuplesException {
- return new OffsetTuples((Tuples) tuples.clone(), rowCount);
+ public static Tuples offset(Tuples tuples, long rowCount) throws TuplesException {
+ return new OffsetTuples((Tuples)tuples.clone(), rowCount);
}
/**
* Filter out duplicate rows.
*
- * @param tuples PARAMETER TO DO
- * @return RETURNED VALUE TO DO
- * @throws TuplesException EXCEPTION TO DO
+ * @param tuples The tuples to filter.
+ * @return An equivalent Tuples, but with duplicate bindings removed.
+ * @throws TuplesException If there was an error accessing the tuples.
*/
public static Tuples removeDuplicates(Tuples tuples) throws TuplesException {
if (tuples.hasNoDuplicates()) {
- if (logger.isDebugEnabled()) {
- logger.debug("Didn't need to remove duplicates");
- }
- return (Tuples) tuples.clone();
+ if (logger.isDebugEnabled()) logger.debug("Didn't need to remove duplicates");
+ return (Tuples)tuples.clone();
}
- if (logger.isDebugEnabled()) {
- logger.debug("Removing duplicates");
- }
+ if (logger.isDebugEnabled()) logger.debug("Removing duplicates");
if (tuples.getComparator() == null) {
Tuples oldTuples = tuples;
@@ -1032,12 +985,8 @@
}
return tuples;
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Already sorted: " + tuples);
- }
-
+ } else {
+ if (logger.isDebugEnabled()) logger.debug("Already sorted: " + tuples);
Tuples result = new DistinctTuples(tuples);
return result;
}
@@ -1049,18 +998,16 @@
}
- public static StringBuffer tuplesSummary(Tuples tuples) {
- StringBuffer buff = new StringBuffer();
+ public static StringBuilder tuplesSummary(Tuples tuples) {
+ StringBuilder buff = new StringBuilder();
buff.append(tuples.getClass().toString());
buff.append("<" + System.identityHashCode(tuples) + ">");
buff.append("[");
- if (!tuples.isMaterialized()) {
- buff.append("~");
- } else {
- buff.append("=");
- }
+ if (!tuples.isMaterialized()) buff.append("~");
+ else buff.append("=");
+
try {
buff.append(tuples.getRowUpperBound()).append("]");
} catch (TuplesException et) {
@@ -1071,17 +1018,13 @@
Variable[] vars = tuples.getVariables();
if (vars.length > 0) {
buff.append(vars[0].toString());
- for (int i = 1; i < vars.length; i++) {
- buff.append(", " + vars[i].toString());
- }
+ for (int i = 1; i < vars.length; i++) buff.append(", " + vars[i].toString());
}
buff.append("}");
try {
MandatoryBindingAnnotation mba = (MandatoryBindingAnnotation)tuples.getAnnotation(MandatoryBindingAnnotation.class);
- if (mba != null) {
- buff.append(" :: MBA{ " + mba.requiredVariables() + " }");
- }
+ if (mba != null) buff.append(" :: MBA{ " + mba.requiredVariables() + " }");
} catch (TuplesException et) {
logger.error("Failed to obtain annotation", et);
}
@@ -1120,15 +1063,18 @@
// get the variable list
Variable[] sv = tuples.getVariables();
for (int i = 0; i < sv.length; i++) {
- if (!vars.contains(sv[i])) {
- // extra variable
- return true;
- }
+ if (!vars.contains(sv[i])) return true; // extra variable
}
return false;
}
+ /**
+ * Convert a list of Tuples into a string.
+ * @param header The header for the returned string.
+ * @param args The tuples to print.
+ * @return The string containing the full list of tuples.
+ */
private static String printArgs(String header, List<? extends Tuples> args) {
StringBuilder buff = new StringBuilder(header);
buff.append("[");
@@ -1146,17 +1092,11 @@
private static StringBuilder indentedTuplesTree(Tuples tuples, String indent) {
-
StringBuilder buff = new StringBuilder();
-
buff.append("\n").append(indent).append("(").append(tuplesSummary(tuples));
-
for (Tuples t: tuples.getOperands()) buff.append(" ").append(indentedTuplesTree(t, indent + ". "));
-
buff.append(")");
-
return buff;
}
-
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/WrappedTuples.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -328,7 +328,7 @@
/**
* Copied from AbstractTuples.
*/
- public Annotation getAnnotation(Class<?> annotationClass) throws TuplesException {
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
return null;
}
}
Modified: trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java
===================================================================
--- trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java 2009-01-24 04:13:55 UTC (rev 1456)
+++ trunk/src/jar/util-xa/java/org/mulgara/store/xa/AVLNode.java 2009-01-24 07:03:51 UTC (rev 1457)
@@ -1285,6 +1285,7 @@
*/
private int rotateL() throws IOException {
AVLNode nodeL = getLeftChildNode();
+ if (nodeL == null) throw new IllegalStateException("Invalid tree structure on disk");
int deltaHeight = (nodeL.block.getByte(IDX_BALANCE_B) >= 0) ?
rotateLL(nodeL) : rotateLR(nodeL);
nodeL.release();
@@ -1301,6 +1302,7 @@
*/
private int rotateR() throws IOException {
AVLNode nodeR = getRightChildNode();
+ if (nodeR == null) throw new IllegalStateException("Invalid tree structure on disk");
int deltaHeight = (nodeR.block.getByte(IDX_BALANCE_B) <= 0) ?
rotateRR(nodeR) : rotateRL(nodeR);
nodeR.release();
@@ -1443,6 +1445,7 @@
private int rotateLR(AVLNode nodeL) throws IOException {
// First perform rotateRR on nodeL.
AVLNode nodeLR = nodeL.getRightChildNode();
+ if (nodeLR == null) throw new IllegalStateException("Invalid tree structure on disk");
int deltaHeightL = nodeL.rotateRR(nodeLR);
// Adjust the balance of this node.
More information about the Mulgara-svn
mailing list