[Mulgara-svn] r1969 - in trunk: . conf lib src/jar/tuples-hybrid/java/org/mulgara/store src/jar/tuples-hybrid/java/org/mulgara/store/bdb
pag at mulgara.org
pag at mulgara.org
Tue Jul 20 13:54:48 UTC 2010
Author: pag
Date: 2010-07-20 13:54:47 +0000 (Tue, 20 Jul 2010)
New Revision: 1969
Added:
trunk/lib/je-4.0.103.jar
trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/
trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbEnvironment.java
trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuples.java
trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesFactory.java
trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesTest.java
Modified:
trunk/.classpath
trunk/build.properties
trunk/build.xml
trunk/common.properties
trunk/common.xml
trunk/conf/mulgara-rmi.policy
trunk/conf/mulgara-test.policy
trunk/conf/mulgara.policy
Log:
Added a new HybridTuples that uses BDB. Policies and path had to change for the BDB addition.
Modified: trunk/.classpath
===================================================================
--- trunk/.classpath 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/.classpath 2010-07-20 13:54:47 UTC (rev 1969)
@@ -91,6 +91,7 @@
<classpathentry kind="lib" path="lib/jasper-runtime-4.2.29.jar"/>
<classpathentry kind="lib" path="lib/javacc.jar"/>
<classpathentry kind="lib" path="lib/jboss-j2ee.jar"/>
+ <classpathentry kind="lib" path="lib/je-4.0.103.jar"/>
<classpathentry kind="lib" path="lib/jena-2.5.6.jar"/>
<classpathentry kind="lib" path="lib/jenatest-2.5.6.jar"/>
<classpathentry kind="lib" path="lib/interruptiblermi-1.1.jar"/>
Modified: trunk/build.properties
===================================================================
--- trunk/build.properties 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/build.properties 2010-07-20 13:54:47 UTC (rev 1969)
@@ -98,6 +98,7 @@
aspectjrt.jar =aspectjrt-1.2.jar
axis.jar =axis-1.4.jar
bsh.jar =bsh-2.0b1.jar
+bdb.jar =je-4.0.103.jar
castor-xml.jar =castor-1.2-xml.jar
castor-xml-schema.jar =castor-1.2-xml-schema.jar
castor-codegen.jar =castor-1.2-codegen.jar
Modified: trunk/build.xml
===================================================================
--- trunk/build.xml 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/build.xml 2010-07-20 13:54:47 UTC (rev 1969)
@@ -501,6 +501,7 @@
<zipfileset src="${lib.dir}/${antlr.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${axis.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${activation.jar}" excludes="META-INF/**"/>
+ <zipfileset src="${lib.dir}/${bdb.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${carol.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-codegen.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-xml.jar}" excludes="META-INF/**"/>
@@ -1677,6 +1678,7 @@
<zipfileset src="${lib.dir}/${activation.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${antlr.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${axis.jar}" excludes="META-INF/**, log4j.properties"/>
+ <zipfileset src="${lib.dir}/${bdb.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${carol.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-xml.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-xml-schema.jar}" excludes="META-INF/**"/>
@@ -2125,6 +2127,7 @@
<zipfileset src="${lib.dir}/${activation.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${antlr.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${axis.jar}" excludes="META-INF/**, log4j.properties"/>
+ <zipfileset src="${lib.dir}/${bdb.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${carol.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-xml.jar}" excludes="META-INF/**"/>
<zipfileset src="${lib.dir}/${castor-xml-schema.jar}" excludes="META-INF/**"/>
Modified: trunk/common.properties
===================================================================
--- trunk/common.properties 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/common.properties 2010-07-20 13:54:47 UTC (rev 1969)
@@ -5,7 +5,7 @@
# Product properties
project =mulgara
description =Mulgara Semantic Store
-mulgara-version=2.1.8
+mulgara-version=2.1.9
year =2001-2010
default.build.label=${description} Version ${mulgara-version} (Build @@build@@)
Modified: trunk/common.xml
===================================================================
--- trunk/common.xml 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/common.xml 2010-07-20 13:54:47 UTC (rev 1969)
@@ -143,7 +143,7 @@
${jena.jar}, ${iri.jar}, ${icu4j.jar}, jxunit*.jar, castor*.jar,
mail-*.jar, activation-*.jar, apache-soap-*.jar, jline*.jar,
axis-*.jar, saaj-*.jar, emory-*.jar, ${trove.jar},
- jargs-*.jar, jetty-*.jar, jta-spec*.jar,
+ ${bdb.jar}, jargs-*.jar, jetty-*.jar, jta-spec*.jar,
jotm*.jar, commons-logging-*.jar, Quick4rt.jar,
commons-discovery-*.jar, commons-httpclient-*.jar,
commons-codec-*.jar, connector-*.jar, jaxrpc-*.jar,
Modified: trunk/conf/mulgara-rmi.policy
===================================================================
--- trunk/conf/mulgara-rmi.policy 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/conf/mulgara-rmi.policy 2010-07-20 13:54:47 UTC (rev 1969)
@@ -18,6 +18,7 @@
permission java.lang.RuntimePermission "setIO";
permission java.lang.RuntimePermission "exitVM";
permission java.lang.RuntimePermission "loadLibrary.keychain";
+ permission java.lang.management.ManagementPermission "monitor";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.net.SocketPermission "*:80", "listen,accept,connect,resolve";
permission java.net.SocketPermission "*:443", "connect,resolve";
@@ -37,6 +38,7 @@
permission java.util.PropertyPermission "triple.store.implementation", "write";
permission java.util.PropertyPermission "descriptor.model", "write";
permission java.util.PropertyPermission "*", "read";
+ permission java.util.logging.LoggingPermission "control";
permission javax.security.auth.AuthPermission "createLoginContext.mulgara";
permission javax.security.auth.AuthPermission "doAsPrivileged";
permission javax.security.auth.AuthPermission "modifyPrincipals";
Modified: trunk/conf/mulgara-test.policy
===================================================================
--- trunk/conf/mulgara-test.policy 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/conf/mulgara-test.policy 2010-07-20 13:54:47 UTC (rev 1969)
@@ -14,6 +14,7 @@
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "loadLibrary.keychain";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ permission java.lang.management.ManagementPermission "monitor";
permission java.net.SocketPermission "*:1099", "connect,resolve";
permission java.net.SocketPermission "*:1024-", "accept,connect,resolve";
permission java.net.SocketPermission "*:443", "accept,connect,resolve";
@@ -26,6 +27,7 @@
permission java.util.PropertyPermission "java.naming.provider.url", "write";
permission java.util.PropertyPermission "java.rmi.server.codebase", "write";
permission java.util.PropertyPermission "sun.arch.data.model", "read";
+ permission java.util.logging.LoggingPermission "control";
permission javax.security.auth.AuthPermission "createLoginContext.mulgara";
permission javax.security.auth.AuthPermission "doAsPrivileged";
Modified: trunk/conf/mulgara.policy
===================================================================
--- trunk/conf/mulgara.policy 2010-07-06 21:50:25 UTC (rev 1968)
+++ trunk/conf/mulgara.policy 2010-07-20 13:54:47 UTC (rev 1969)
@@ -14,6 +14,7 @@
permission java.lang.RuntimePermission "shutdownHooks";
permission java.lang.RuntimePermission "setIO";
permission java.lang.RuntimePermission "exitVM";
+ permission java.lang.management.ManagementPermission "monitor";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.net.SocketPermission "*:80", "accept,connect,resolve";
permission java.net.SocketPermission "*:443", "connect,resolve";
@@ -31,6 +32,7 @@
permission java.util.PropertyPermission "mail.smtp.host", "write";
permission java.util.PropertyPermission "descriptor.model", "write";
permission java.util.PropertyPermission "*", "read";
+ permission java.util.logging.LoggingPermission "control";
permission javax.security.auth.AuthPermission "createLoginContext.mulgara";
permission javax.security.auth.AuthPermission "doAsPrivileged";
permission javax.security.auth.AuthPermission "modifyPrincipals";
Added: trunk/lib/je-4.0.103.jar
===================================================================
(Binary files differ)
Property changes on: trunk/lib/je-4.0.103.jar
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbEnvironment.java
===================================================================
--- trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbEnvironment.java (rev 0)
+++ trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbEnvironment.java 2010-07-20 13:54:47 UTC (rev 1969)
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010, Paul Gearon
+ *
+ * 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.bdb;
+
+import org.apache.log4j.Logger;
+import org.mulgara.util.TempDir;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+
+/**
+ * A central location for creating a singleton BerkeleyDB environment.
+ *
+ * @created Jul 12, 2010
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+public class DbEnvironment {
+
+ private final static Logger logger = Logger.getLogger(DbEnvironment.class);
+
+ static private Environment env;
+ static private EnvironmentConfig envCfg;
+
+ static Environment getEnv() {
+ if (env == null) {
+ try {
+ envCfg = new EnvironmentConfig();
+ envCfg.setAllowCreate(true);
+ env = new Environment(TempDir.getTempDir(), envCfg);
+ } catch (DatabaseException dbe) {
+ logger.error("Error creating BDB environment: " + dbe.getMessage(), dbe);
+ throw new RuntimeException("Unable to manage data with BDB", dbe);
+ }
+ }
+ return env;
+ }
+
+
+}
Added: trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuples.java
===================================================================
--- trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuples.java (rev 0)
+++ trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuples.java 2010-07-20 13:54:47 UTC (rev 1969)
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2010, Paul Gearon
+ *
+ * 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.bdb;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Map;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.LongBuffer;
+
+import org.apache.log4j.Logger;
+
+import org.mulgara.query.Constraint;
+import org.mulgara.query.Cursor;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+import org.mulgara.store.statement.StatementStore;
+import org.mulgara.store.tuples.Annotation;
+import org.mulgara.store.tuples.RowComparator;
+import org.mulgara.store.tuples.SimpleTuplesFormat;
+import org.mulgara.store.tuples.Tuples;
+import org.mulgara.store.tuples.TuplesOperations;
+import org.mulgara.util.Constants;
+import org.mulgara.util.StackTrace;
+
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.LockMode;
+import com.sleepycat.je.OperationStatus;
+
+/**
+ * Represents a group of tuples, sorted and stored in a Berkeley DB.
+ *
+ * @created 2010-07-11
+ * @author Paul Gearon
+ */
+public final class DbTuples implements Tuples {
+
+ /** A map from DbTuples objects to their comparators */
+ static private Map<Integer,RowComparator> comparators = new HashMap<Integer,RowComparator>();
+
+ protected final Variable[] vars;
+ protected final int width;
+ protected final RowComparator comparator;
+ protected final boolean unconstrained;
+ protected final boolean duplicates;
+ protected final boolean[] columnEverUnbound;
+ protected Tuples tuples;
+
+ // Would be final except for clone
+ // can be final once clone semantics migrated into CacheLine.
+ protected boolean beforeFirstCalled;
+ protected boolean nextCalled;
+
+ /** Used to indicate that beforeFirst has set the first record to be returned from next */
+ protected boolean initialRecord = false;
+ /** Indicates that beforeFirst found data to be returned */
+ protected boolean initialStatus = false;
+
+ /** The prefix used in the most recent beforeFirst */
+ protected long[] currentPrefix;
+
+ /** The database used to represent these tuples */
+ protected Database database;
+ /** The reference count to the database */
+ private int refCount = 0;
+
+ /** The internal cursor over the BDB table */
+ protected com.sleepycat.je.Cursor cursor;
+ /** The data to be read from the BDB table */
+ protected DatabaseEntry line = new DatabaseEntry();
+ /** The empty value object that is required for reading, but will always be empty. */
+ protected DatabaseEntry emptyVal = new DatabaseEntry();
+
+ /** The buffer containing the data from the current record of the tuples. */
+ protected LongBuffer tupleLine;
+
+ protected int[] varLookupList;
+ private boolean closed = false;
+
+ // Debugging.
+ private final static Logger logger = Logger.getLogger(DbTuples.class);
+ private StackTrace allocatedBy;
+ private StackTrace closedBy;
+
+ /**
+ * Constructs a tuples that represents another tuples with a given ordering.
+ * @param tuples The original tuples to represent.
+ * @param comparator The definition of the new ordering.
+ * @throws TuplesException If there is a problem accessing the original tuples.
+ */
+ protected DbTuples(Tuples tuples, RowComparator comparator) throws TuplesException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("DbTuples created " + System.identityHashCode(this));
+ }
+
+ // store the comparator, and map to it by the current identifier
+ this.comparator = comparator;
+ comparators.put(System.identityHashCode(this), comparator);
+
+ // get some of tuples structure from the original tuples
+ this.vars = tuples.getVariables();
+ this.unconstrained = tuples.isUnconstrained();
+ this.duplicates = !tuples.hasNoDuplicates();
+
+ // Create a lookup up list of unique variables to their position in an index.
+ HashSet<Variable> uniqueVars = new HashSet<Variable>();
+ List<Variable> uniqueVarIndex = new ArrayList<Variable>();
+ varLookupList = new int[vars.length];
+ int varIndex = -1;
+ for (int index = 0; index < vars.length; index++) {
+
+ // Add variable to set.
+ uniqueVars.add(vars[index]);
+
+ // Check to see if variable is already in list, if not add to list. Set
+ // lookup list to current variable index value.
+ int indexPos = uniqueVarIndex.indexOf(vars[index]);
+ if (indexPos == -1) {
+ uniqueVarIndex.add(vars[index]);
+ varIndex++;
+ indexPos = varIndex;
+ }
+ varLookupList[index] = indexPos;
+ }
+
+ this.width = uniqueVars.size();
+ this.columnEverUnbound = new boolean[this.width];
+ Arrays.fill(this.columnEverUnbound, false);
+
+ // put everything into a BDB
+ database = createTempDb();
+ refCount++; // created the first reference to database
+ materialiseTuples(tuples, database);
+
+ // set up some state on cursors
+ this.beforeFirstCalled = false;
+ this.nextCalled = false;
+
+ // Set up details for debugging, if necessary
+ if (logger.isDebugEnabled()) {
+ this.tuples = (Tuples)tuples.clone();
+ } else {
+ this.tuples = TuplesOperations.empty();
+ }
+ if (logger.isDebugEnabled()) this.allocatedBy = new StackTrace();
+ }
+
+
+ /**
+ * Required by Tuples, Cursor.
+ */
+ public boolean next() throws TuplesException {
+ if (!beforeFirstCalled) {
+ logger.error("next() called before beforeFirst()");
+ throw new TuplesException("next() called before beforeFirst()");
+ }
+
+ boolean status;
+ if (initialRecord) {
+ // beforeFirst already read the record, so just extract it and test it
+ initialRecord = false;
+ if (!initialStatus) status = false;
+ else {
+ tupleLine = ByteBuffer.wrap(line.getData()).asLongBuffer();
+ status = testLine(tupleLine, currentPrefix);
+ }
+ } else {
+ // subsequent record, so move to the next and test it
+ status = cursor.getNext(line, emptyVal, LockMode.DEFAULT) == OperationStatus.SUCCESS;
+ if (status) {
+ // extract the current record
+ tupleLine = ByteBuffer.wrap(line.getData()).asLongBuffer();
+ // check to see if the cursor has stepped past the matching data
+ status = testLine(tupleLine, currentPrefix);
+ }
+ }
+ nextCalled = true;
+ return status;
+ }
+
+
+ /**
+ * Required by Tuples.
+ */
+ public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
+ assert prefix != null;
+
+ if (suffixTruncation != 0) {
+ logger.error("DbTuples.beforeFirst(suffix) unimplemented");
+ throw new IllegalArgumentException("DbTuples.beforeFirst(suffix) unimplemented");
+ }
+
+ // copy the prefix so we know when we've left the search range
+ currentPrefix = new long[prefix.length];
+ System.arraycopy(prefix, 0, currentPrefix, 0, prefix.length);
+
+ // get a new cursor
+ if (cursor == null) cursor = database.openCursor(null, null);
+
+ // construct the buffer that cursor will search on
+ ByteBuffer bb = ByteBuffer.allocate(width * Constants.SIZEOF_LONG);
+ LongBuffer lb = bb.asLongBuffer();
+ for (int i = 0; i < prefix.length; i++) lb.put(i, prefix[i]);
+ line.setData(bb.array());
+ initialStatus = cursor.getSearchKey(line, emptyVal, LockMode.DEFAULT) == OperationStatus.SUCCESS;
+
+ // remember state
+ initialRecord = true;
+ beforeFirstCalled = true;
+ nextCalled = false;
+ }
+
+
+ /**
+ * Required by Tuples.
+ */
+ public long getColumnValue(int column) throws TuplesException {
+ if (column < 0 || column >= width) {
+ throw new TuplesException("No column " + column + " in " + Arrays.asList(vars));
+ }
+
+ if (!nextCalled) throw new TuplesException("getColumnValue() called before next()");
+
+ return tupleLine.get(varLookupList[column]);
+ }
+
+
+ /**
+ * Required by Tuples.
+ */
+ public void renameVariables(Constraint constraint) {
+ for (int i = 0; i < vars.length; i++) {
+ Variable v = vars[i];
+ boolean found = false;
+ for (int j = 0; j < 4; j++) {
+ // v will be a reference to one of the objects in Graph.VARIABLES[]
+ if (v == StatementStore.VARIABLES[j]) {
+ // The array obtained from getVariables() is modifiable.
+ vars[i] = (Variable)constraint.getElement(j);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ logger.error("Unexpected variable: " + v);
+ throw new Error("Unexpected variable: " + v);
+ }
+ }
+ }
+
+
+ /**
+ * Required by Tuples.
+ */
+ public Object clone() {
+ try {
+ DbTuples copy = (DbTuples)super.clone();
+ // we now have a new reference to database
+ refCount++;
+ if (logger.isDebugEnabled()) copy.allocatedBy = new StackTrace();
+ copy.tuples = (Tuples)tuples.clone();
+ copy.currentPrefix = currentPrefix == null ? null : currentPrefix.clone();
+ copy.line = new DatabaseEntry(line.getData());
+ if (tupleLine != null ) {
+ tupleLine.position(0);
+ copy.tupleLine = ByteBuffer.allocate(width * Constants.SIZEOF_LONG)
+ .asLongBuffer().put(tupleLine);
+ }
+
+ return copy;
+ } catch (CloneNotSupportedException ce) {
+ logger.error("DbTuples.clone() threw CloneNotSupported", ce);
+ throw new RuntimeException("DbTuples.clone() threw CloneNotSupported", ce);
+ }
+ }
+
+
+ /**
+ * This could fall back to beforeFirst(Tuples.NO_PREFIX), but this is more efficient
+ */
+ public void beforeFirst() throws TuplesException {
+ currentPrefix = Tuples.NO_PREFIX;
+
+ // get a new cursor
+ if (cursor == null) cursor = database.openCursor(null, null);
+
+ initialStatus = cursor.getFirst(line, emptyVal, LockMode.DEFAULT) == OperationStatus.SUCCESS;
+
+ // remember state
+ initialRecord = true;
+ beforeFirstCalled = true;
+ nextCalled = false;
+ }
+
+
+ /** @see org.mulgara.store.tuples.Tuples#getOperands() */
+ public List<Tuples> getOperands() {
+ return Collections.singletonList(tuples);
+ }
+
+ /**
+ * Required by Cursor.
+ */
+ public void close() throws TuplesException {
+ if (closed) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Attempt to close DbTuples twice; first closed: " + closedBy);
+ logger.debug("Attempt to close DbTuples twice; second closed: " + new StackTrace());
+ logger.debug(" allocated: " + allocatedBy);
+ } else {
+ logger.error("Attempt to close HybridTuples twice. Enable debug to trace how.");
+ }
+ throw new TuplesException("Attempted to close HybribTuples more than once");
+ }
+ closed = true;
+ if (logger.isDebugEnabled()) closedBy = new StackTrace();
+
+ comparators.remove(System.identityHashCode(this));
+ try {
+ tuples.close();
+ tuples = null;
+ } finally {
+ try {
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
+ }
+ } finally {
+ assert refCount > 0 : "Released all BDB reference counts before closing Tuples";
+ refCount--;
+ if (refCount == 0 && database != null) {
+ database.close();
+ database = null;
+ }
+ }
+ }
+ }
+
+
+ /** {@inheritDoc} */
+ public int getColumnIndex(Variable variable) throws TuplesException {
+ for (int c = 0; c < vars.length; c++) if (vars[c].equals(variable)) return c;
+
+ logger.warn("Variable not found: " + variable);
+ throw new TuplesException("Variable not found: " + variable);
+ }
+
+
+ /** {@inheritDoc} */
+ public long getRawColumnValue(int column) throws TuplesException {
+ return UNBOUND;
+ }
+
+
+ /** {@inheritDoc} */
+ public int getNumberOfVariables() {
+ return vars != null ? vars.length : 0;
+ }
+
+
+ /** {@inheritDoc} */
+ public Variable[] getVariables() {
+ return vars;
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isUnconstrained() throws TuplesException {
+ return unconstrained;
+ }
+
+
+ /** {@inheritDoc} */
+ public long getRowCount() throws TuplesException {
+ return database.count();
+ }
+
+
+ public long getRowUpperBound() throws TuplesException {
+ return getRowCount();
+ }
+
+
+ public long getRowExpectedCount() throws TuplesException {
+ return getRowCount();
+ }
+
+
+ public int getRowCardinality() throws TuplesException {
+ switch ((int)getRowCount()) {
+ case 0:
+ return Cursor.ZERO;
+ case 1:
+ return Cursor.ONE;
+ default:
+ return Cursor.MANY;
+ }
+ }
+
+
+ public boolean isEmpty() throws TuplesException {
+ return getRowCount() == 0;
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isColumnEverUnbound(int column) throws TuplesException {
+ try {
+ return columnEverUnbound[column];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new TuplesException("No such column "+column);
+ }
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isMaterialized() {
+ return true;
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean hasNoDuplicates() {
+ return !duplicates;
+ }
+
+
+ /** {@inheritDoc} */
+ public RowComparator getComparator() {
+ return comparator;
+ }
+
+ /** Get the comparator for the given DbTuples ID */
+ public static RowComparator getCmp(int id) {
+ return comparators.get(id);
+ }
+
+ /** {@inheritDoc} */
+ public boolean equals(Object o) {
+ Tuples t;
+ Tuples c;
+
+ if (o == this) return true;
+
+ if (!(o instanceof Tuples)) return false;
+
+ t = (Tuples)o;
+ if (t instanceof DbTuples) return this.database.equals(((DbTuples)t).database);
+
+ try {
+ Variable[] tvars = t.getVariables();
+ if (this.getRowCount() != t.getRowCount() || this.vars.length != tvars.length) {
+ return false;
+ }
+
+ for (int v = 0; v < this.width; v++) {
+ if (!this.vars[v].equals(tvars[v])) return false;
+ }
+
+ t = (Tuples)t.clone();
+ c = (Tuples)this.clone();
+
+ try {
+ t.beforeFirst();
+ c.beforeFirst();
+
+ while(true) {
+ boolean tn = t.next();
+ boolean cn = c.next();
+ if (!tn && !cn) return true;
+ if ((!tn && cn) || (tn && !cn)) return false;
+ for (int i = 0; i < width; i++) {
+ if (t.getColumnValue(i) != c.getColumnValue(i)) return false;
+ }
+ }
+ } finally {
+ t.close();
+ c.close();
+ }
+ } catch (TuplesException te) {
+ throw new RuntimeException("Tuples Exception in HybridTuples.equals", te);
+ }
+ }
+
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return SimpleTuplesFormat.format(this);
+ }
+
+
+ /**
+ * Load all of the tuples into the local database.
+ * @param tuples The tuples to load.
+ * @param db The database to insert into.
+ * @return The number of insertions made. This will be the row count if duplicates are allowed.
+ * @throws TuplesException Due to an error reading from the tuples.
+ */
+ private long materialiseTuples(Tuples tuples, Database db) throws TuplesException {
+ tuples.beforeFirst();
+
+ ByteBuffer bb = ByteBuffer.allocate(width * Constants.SIZEOF_LONG);
+ LongBuffer lb = bb.asLongBuffer();
+ byte[] array = bb.array();
+ DatabaseEntry key = new DatabaseEntry(array);
+
+ byte[] valArray;
+ LongBuffer valLB = null;
+ if (duplicates) {
+ ByteBuffer valB = ByteBuffer.allocate(Constants.SIZEOF_LONG);
+ valLB = valB.asLongBuffer();
+ valArray = valB.array();
+ } else {
+ valArray = new byte[0];
+ }
+ // The ignored value. If we can have duplicates, then make this an incrementing number.
+ DatabaseEntry emptyVal = new DatabaseEntry(valArray);
+
+ long count = 0;
+ while (tuples.next()) {
+ for (int i = 0; i < width; i++) lb.put(i, tuples.getColumnValue(i));
+ if (duplicates) valLB.put(0, count);
+ db.put(null, key, emptyVal);
+ count++;
+ }
+ return count;
+ }
+
+ private Database createTempDb() throws TuplesException {
+ Environment env = DbEnvironment.getEnv();
+ try {
+ DatabaseConfig dbCfg = new DatabaseConfig();
+ dbCfg.setAllowCreate(true);
+ dbCfg.setTemporary(true);
+ dbCfg.setSortedDuplicates(duplicates);
+ int id = System.identityHashCode(this);
+ dbCfg.setBtreeComparator(new DbComparator(id, comparator));
+ return env.openDatabase(null, "tuples_" + id, dbCfg);
+ } catch (DatabaseException dbe) {
+ throw new TuplesException("Error creating BDB database: " + dbe.getMessage());
+ }
+
+ }
+
+ /**
+ * Tests if a long buffer matches a long array, starting at the end of the array
+ * and working backwards. Only the length of the array is tested.
+ * @param l The buffer to compare.
+ * @param p The array to compare. This also sets the comparison length.
+ * @return <code>true</code> if all the elements of the array match the corresponding
+ * elements in the buffer.
+ */
+ private static final boolean testLine(LongBuffer l, long[] p) {
+ for (int i = p.length - 1; i >= 0; i--) {
+ if (l.get(i) != p[i]) return false;
+ }
+ return true;
+ }
+
+
+ /** Copied from AbstractTuples */
+ public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
+ return null;
+ }
+
+
+ public static class DbComparator implements Comparator<byte[]>, Serializable {
+
+ /** The serialization ID */
+ private static final long serialVersionUID = -2986622291706235593L;
+
+ /** An internal identifier */
+ private final Integer id;
+
+ /** The wrapped RowComparator that does the actual work */
+ private transient RowComparator rc;
+
+ /**
+ * Creates a comparator, based on a row comparator
+ * @param rc The comparator to do the real work.
+ */
+ public DbComparator(int id, RowComparator rc) {
+ this.id = id;
+ this.rc = rc;
+ }
+
+ /** @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */
+ public int compare(byte[] o1, byte[] o2) {
+ try {
+ LongBuffer lb1 = ByteBuffer.wrap(o1).asLongBuffer();
+ LongBuffer lb2 = ByteBuffer.wrap(o2).asLongBuffer();
+ long[] l1 = new long[lb1.capacity()];
+ long[] l2 = new long[lb2.capacity()];
+ lb1.get(l1);
+ lb2.get(l2);
+ return rc.compare(l1, l2);
+ } catch (TuplesException e) {
+ throw new RuntimeException("Error reading values for comparison in the BDB table", e);
+ }
+ }
+
+ /** The identifier assigned to this comparator */
+ public Integer getId() {
+ return id;
+ }
+
+ /**
+ * After reading back this object, find the row comparator that was assigned for it.
+ * @param in The input stream to get the object from.
+ * @throws IOException Error reading from the stream.
+ * @throws ClassNotFoundException If the class in the stream is not in the classpath.
+ */
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ rc = getCmp(id);
+ }
+
+ }
+
+}
+
Added: trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesFactory.java
===================================================================
--- trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesFactory.java (rev 0)
+++ trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesFactory.java 2010-07-20 13:54:47 UTC (rev 1969)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010, Paul Gearon
+ *
+ * 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.bdb;
+
+
+import org.mulgara.query.TuplesException;
+import org.mulgara.store.tuples.DefaultRowComparator;
+import org.mulgara.store.tuples.RowComparator;
+import org.mulgara.store.tuples.Tuples;
+import org.mulgara.store.tuples.TuplesFactory;
+
+/**
+ * Generates {@link BdTuples} instances.
+ *
+ * @created 2010-07-12
+ * @author Paul Gearon
+ */
+public class DbTuplesFactory extends TuplesFactory {
+
+ /** The default ordering for tuples is by node number. */
+ private RowComparator rowComparator = new DefaultRowComparator();
+
+
+ /**
+ * Copy constructor.
+ *
+ * @param tuples an existing instance, whose contents will be copied into the new instance
+ * @return a new {@link HybridTuples} instance
+ * @throws IllegalArgumentException if <var>tuples</var> is <code>null</code>
+ * @throws TuplesException if a copy of <var>tuples</var> can't be created
+ */
+ public Tuples newTuples(Tuples tuples) throws TuplesException {
+ return newTuples(tuples, rowComparator);
+ }
+
+
+ /**
+ * Construct a new tuples with a specified order.
+ *
+ * @param tuples an existing instance, whose contents will be copied into the
+ * new instance
+ * @param rowComparator the desired sort order
+ * @return a new {@link HybridTuples} instance
+ * @throws IllegalArgumentException if <var>tuples</var> or <var>rowComparator
+ * </var> parameters are <code>null</code>
+ * @throws TuplesException if a copy of <var>tuples</var> can't be created
+ */
+ public Tuples newTuples(Tuples tuples, RowComparator rowComparator) throws TuplesException {
+ if (rowComparator == null) {
+ throw new IllegalArgumentException("Null \"rowComparator\" parameter");
+ }
+ if (tuples == null) {
+ throw new IllegalArgumentException("Null \"tuples\" parameter");
+ }
+
+ return new DbTuples(tuples, rowComparator);
+ }
+}
Added: trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesTest.java
===================================================================
--- trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesTest.java (rev 0)
+++ trunk/src/jar/tuples-hybrid/java/org/mulgara/store/bdb/DbTuplesTest.java 2010-07-20 13:54:47 UTC (rev 1969)
@@ -0,0 +1,658 @@
+/*
+ * 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.bdb;
+
+// Third party packages
+import junit.framework.*;
+
+import java.io.*;
+
+// Java 2 standard packages
+import java.util.*;
+
+import org.apache.log4j.Logger;
+
+// Locally written packages.
+import org.mulgara.query.Variable;
+import org.mulgara.store.tuples.DefaultRowComparator;
+import org.mulgara.store.tuples.LiteralTuples;
+import org.mulgara.store.tuples.RowComparator;
+
+/**
+ * Test cases for DbTuples.
+ *
+ * @created 2003-02-04
+ *
+ * @author Paul Gearon
+ *
+ * @version $Revision: 1.9 $
+ *
+ * @modified $Date: 2005/01/05 04:59:12 $
+ *
+ * @maintenanceAuthor $Author: newmana $
+ *
+ * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
+ *
+ * @copyright ©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 DbTuplesTest extends TestCase {
+ // Larger than this and in memory structures used by the tests fail with OOM
+// private final static int LOAD_SIZE = 262142;
+ private final static int LOAD_SIZE = 1000000;
+ private final static int ODD_LOAD_SIZE = 200000;
+ private final static int BF_SMALL_LOAD_SIZE = 10;
+ private final static int BF_LARGE_LOAD_SIZE = 100;
+ private final static Logger logger = Logger.getLogger(DbTuplesTest.class);
+ private final static int WIDTH = 3;
+ private DbTuples dbTuples;
+ private RowComparator rowComparator;
+
+ private final static Comparator<long[]> longSingletonArrayComparator = new Comparator<long[]>() {
+ public int compare(long[] a1, long[] a2) {
+ return a1[0] == a2[0] ? 0 : (a1[0] < a2[0] ? -1 : +1);
+ }
+ };
+
+ /**
+ * Named constructor.
+ *
+ * @param name The name of the test.
+ */
+ public DbTuplesTest(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Hook for test runner to obtain a test suite from.
+ *
+ * @return The test suite to run.
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new DbTuplesTest("testCreate"));
+ suite.addTest(new DbTuplesTest("testSort"));
+ suite.addTest(new DbTuplesTest("testOddLoad"));
+ suite.addTest(new DbTuplesTest("testLoadSort"));
+ suite.addTest(new DbTuplesTest("testEmpty"));
+ suite.addTest(new DbTuplesTest("testLargeOrdered"));
+ suite.addTest(new DbTuplesTest("testCloneAndClose"));
+
+ // determine why these do not work
+ // suite.addTest(new DbTuplesTest("testPositioning"));
+ // suite.addTest(new DbTuplesTest("testSmallBeforeFirst"));
+ // suite.addTest(new DbTuplesTest("testLargeBeforeFirst"));
+
+ return suite;
+ }
+
+
+ /**
+ * Default test runner.
+ *
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+
+ /**
+ * Creates a new file required to do the testing.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void setUp() throws Exception {
+ boolean exceptionOccurred = true;
+ try {
+ rowComparator = DefaultRowComparator.getInstance();
+ exceptionOccurred = false;
+ } finally {
+ if (exceptionOccurred) {
+ tearDown();
+ }
+ }
+ }
+
+
+ /**
+ * Closes the file used for testing.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void tearDown() throws Exception {
+ if (dbTuples != null) {
+ dbTuples.close();
+ dbTuples = null;
+ }
+ }
+
+
+ /**
+ * Test creation based on a 6 element set.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void testCreate() throws Exception {
+ LiteralTuples tt = new LiteralTuples(new String[] { "test" });
+ tt.appendTuple(new long[] { 1 });
+ tt.appendTuple(new long[] { 2 });
+ tt.appendTuple(new long[] { 3 });
+ tt.appendTuple(new long[] { 4 });
+ tt.appendTuple(new long[] { 5 });
+ tt.appendTuple(new long[] { 6 });
+
+ dbTuples = new DbTuples(tt, rowComparator);
+
+ dbTuples.beforeFirst();
+
+ // check that the order is as expected
+ long row = 1;
+ while (dbTuples.next()) {
+ assertEquals(row++, dbTuples.getColumnValue(0));
+ }
+
+ // check for the correct number of elements in dbTuples
+ assertTrue(row == 7);
+ }
+
+
+ /**
+ * Test sorting
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void testSort() throws Exception {
+ LiteralTuples tt = new LiteralTuples(new String[] { "test" });
+ tt.appendTuple(new long[] { 6 });
+ tt.appendTuple(new long[] { 5 });
+ tt.appendTuple(new long[] { 4 });
+ tt.appendTuple(new long[] { 3 });
+ tt.appendTuple(new long[] { 2 });
+ tt.appendTuple(new long[] { 1 });
+
+ dbTuples = new DbTuples(tt, rowComparator);
+
+ dbTuples.beforeFirst();
+ // check that the order is as expected
+ long row = 1;
+ while (dbTuples.next()) {
+ assertEquals(row++, dbTuples.getColumnValue(0));
+ }
+
+ // check for the correct number of elements in dbTuples
+ assertTrue(row == 7);
+ }
+
+
+ /**
+ * Test cloneing DbTuples and closing original copy.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void testCloneAndClose() throws Exception {
+ LiteralTuples tt = new LiteralTuples(new String[] { "test" });
+ tt.appendTuple(new long[] { 6 });
+ tt.appendTuple(new long[] { 5 });
+ tt.appendTuple(new long[] { 4 });
+ tt.appendTuple(new long[] { 3 });
+ tt.appendTuple(new long[] { 2 });
+ tt.appendTuple(new long[] { 1 });
+
+ DbTuples origTuples = new DbTuples(tt, rowComparator);
+ dbTuples = (DbTuples)origTuples.clone();
+ origTuples.close();
+
+ dbTuples.beforeFirst();
+ // check that the order is as expected
+ long row = 1;
+ while (dbTuples.next()) {
+ assertEquals(row++, dbTuples.getColumnValue(0));
+ }
+
+ // check for the correct number of elements in dbTuples
+ assertTrue(row == 7);
+ }
+
+
+ /**
+ * Load test the sorting
+ *
+ * @throws Throwable EXCEPTION TO DO
+ */
+ public void testLoadSort() throws Throwable {
+ Random r = new Random(42); // use a constant seed
+ long[] v = new long[] { r.nextLong() & 0xFFFFFFFFL };
+ LiteralTuples tt = new LiteralTuples(new String[] { "test" });
+ tt.appendTuple(v);
+
+ ArrayList<long[]> values = new ArrayList<long[]>();
+ values.add(v);
+
+ // iterate over a large enough range to guarantee several blocks
+ for (int i = 0; i < LOAD_SIZE; i++) {
+ v = new long[] { r.nextLong() & 0xFFFFFFFFL };
+ if (v[0] == 0) {
+ v[0]++;
+ }
+ values.add(v);
+ tt.appendTuple(v);
+ }
+ Collections.sort(values, longSingletonArrayComparator);
+
+// logger.info("LoadSort: Creating DbTuples");
+ dbTuples = new DbTuples(tt, rowComparator);
+// logger.info("LoadSort: BeforeFirst");
+ dbTuples.beforeFirst();
+
+// logger.info("LoadSort: Checking Order");
+ // check that the order is as expected
+ Iterator<long[]> it = values.iterator();
+ int i = 0;
+ try {
+ while (it.hasNext()) {
+ assertEquals("On iteration " + i, dbTuples.next(), true);
+ v = it.next();
+ i++;
+// if (i % 10000 == 0) {
+// logger.info("Checked " + i + " tuples");
+// }
+ assertEquals("On iteration " + i, v[0], dbTuples.getColumnValue(0));
+ }
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+
+// logger.info("LoadSort: Finished order check");
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+// logger.info("LoadSort: Finished test");
+ }
+
+
+ /**
+ * Load test odd sized tuples
+ *
+ * @throws Throwable EXCEPTION TO DO
+ */
+ public void testOddLoad() throws Throwable {
+ Variable[] vars = new Variable[WIDTH];
+
+ for (int c = 0; c < WIDTH; c++) {
+ vars[c] = new Variable("test" + (c + 1));
+ }
+
+ // use a constant seed
+ Random r = new Random(42);
+
+ LiteralTuples tt = new LiteralTuples(vars);
+ long[] v = new long[WIDTH];
+
+ // iterate over a large enough range to guarantee several blocks
+ for (int i = 0; i < ODD_LOAD_SIZE; i++) {
+ for (int c = 0; c < WIDTH; c++) {
+ v[c] = r.nextLong() & 0x0000FFFFL;
+ if (v[c] == 0) {
+ v[c]++;
+ }
+ }
+
+ tt.appendTuple(v);
+ }
+
+ dbTuples = new DbTuples(tt, rowComparator);
+ dbTuples.beforeFirst();
+
+ // check that the order is as expected
+ long[] tuple = new long[WIDTH];
+ long[] lastTuple = new long[WIDTH];
+
+ for (int c = 0; c < WIDTH; c++) {
+ lastTuple[c] = 0;
+ }
+
+ int i = 0;
+ try {
+ while (dbTuples.next()) {
+ for (int c = 0; c < WIDTH; c++) {
+ tuple[c] = dbTuples.getColumnValue(c);
+ }
+
+ for (int c = 0; c < WIDTH; c++) {
+ if (tuple[c] < lastTuple[c]) {
+ logger.error("Error tuple[" + tuple[0] + "," + tuple[1] + "," +
+ tuple[2] + "] < lastTuple[" + lastTuple[0] + "," + lastTuple[1] +
+ "," + lastTuple[2] + "]");
+ }
+ assertTrue(tuple[c] >= lastTuple[c]);
+ if (tuple[c] != lastTuple[c]) {
+ break;
+ }
+ }
+
+ for (int c = 0; c < WIDTH; c++) {
+ lastTuple[c] = tuple[c];
+ }
+
+ i++;
+ }
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+
+ // check that there aren't any extraneous values
+// logger.warn("i = " + i + ", LOAD_SIZE = " + ODD_LOAD_SIZE);
+ assertTrue(i == ODD_LOAD_SIZE);
+ }
+
+
+ /**
+ * Test adding an empty tuple
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void testEmpty() throws Exception {
+ LiteralTuples tt = new LiteralTuples(new Variable[] {});
+
+ dbTuples = new DbTuples(tt, rowComparator);
+ dbTuples.beforeFirst();
+
+ // check that the order is as expected
+ assertTrue(!dbTuples.next());
+ }
+
+
+ /**
+ * Test the {@link DbTuples#beforeFirst(long[], int)} and {@link
+ * DbTuples#next} methods.
+ *
+ * @throws Exception EXCEPTION TO DO
+ */
+ public void testPositioning() throws Exception {
+ LiteralTuples tt = new LiteralTuples(new String[] { "x", "y" });
+ tt.appendTuple(new long[] { 1, 2 });
+ tt.appendTuple(new long[] { 3, 4 });
+ tt.appendTuple(new long[] { 5, 6 });
+ tt.appendTuple(new long[] { 7, 8 });
+ dbTuples = new DbTuples(tt, rowComparator);
+
+ dbTuples.beforeFirst(new long[] {7, 8} , 0);
+ assertTrue(dbTuples.next());
+ assertEquals(7, dbTuples.getColumnValue(0));
+ assertEquals(8, dbTuples.getColumnValue(1));
+ assertTrue(!dbTuples.next());
+
+ dbTuples.beforeFirst();
+
+ assertTrue(dbTuples.next());
+ assertEquals(1, dbTuples.getColumnValue(0));
+ assertEquals(2, dbTuples.getColumnValue(1));
+
+ dbTuples.beforeFirst(new long[] {7, 8} , 0);
+ assertTrue(dbTuples.next());
+ assertEquals(7, dbTuples.getColumnValue(0));
+ assertEquals(8, dbTuples.getColumnValue(1));
+
+ assertTrue(!dbTuples.next());
+
+ dbTuples.beforeFirst(new long[] {1, 2} , 0);
+
+ assertTrue(dbTuples.next());
+ assertEquals(1, dbTuples.getColumnValue(0));
+ assertEquals(2, dbTuples.getColumnValue(1));
+
+ assertTrue(!dbTuples.next());
+
+ dbTuples.beforeFirst(new long[] {2} , 0);
+ assertTrue(!dbTuples.next());
+
+ dbTuples.beforeFirst(new long[] {3} , 0);
+ assertTrue(dbTuples.next());
+ assertEquals(3, dbTuples.getColumnValue(0));
+ assertEquals(4, dbTuples.getColumnValue(1));
+
+ assertTrue(!dbTuples.next());
+
+ dbTuples.close();
+ dbTuples = null;
+ }
+
+
+ public void testLargeOrdered() throws Throwable {
+ LiteralTuples tt = new LiteralTuples(new String[] { "test" });
+
+
+ ArrayList<long[]> values = new ArrayList<long[]>();
+
+ long count = 0;
+ // iterate over a large enough range to guarantee several blocks
+ for (int i = 0; i < LOAD_SIZE; i++) {
+ long[] v = new long[] { count++ };
+ v[0] = count++;
+ values.add(v);
+ tt.appendTuple(v);
+ }
+ Collections.sort(values, longSingletonArrayComparator);
+
+ dbTuples = new DbTuples(tt, rowComparator);
+ dbTuples.beforeFirst();
+
+ // check that the order is as expected
+ Iterator<long[]> it = values.iterator();
+ int i = 0;
+ try {
+ while (it.hasNext()) {
+ assertTrue(dbTuples.next());
+ long[] v = it.next();
+ i++;
+ assertEquals("On iteration " + i, v[0], dbTuples.getColumnValue(0));
+ }
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+ }
+
+
+ public void testSmallBeforeFirst() throws Throwable {
+ logger.warn("testSmallBeforeFirst");
+ LiteralTuples tt = new LiteralTuples(new String[] { "i", "j", "k" });
+
+ logger.warn("testSmallBeforeFirst: checkpoint 1");
+ // iterate over a large enough range to guarantee several blocks
+ for (int i = (BF_SMALL_LOAD_SIZE * 2) - 1; i > 0; i -= 2) {
+ for (int j = (BF_SMALL_LOAD_SIZE * 2) - 1; j > 0; j -= 2) {
+ for (int k = (BF_SMALL_LOAD_SIZE * 2) - 1; k > 0; k -= 2) {
+ long[] v = new long[] { i, j, k };
+ tt.appendTuple(v);
+ }
+ }
+ }
+
+ logger.warn("testSmallBeforeFirst: checkpoint 2");
+ dbTuples = new DbTuples(tt, rowComparator);
+
+ logger.warn("testSmallBeforeFirst: checkpoint 3");
+ dbTuples.beforeFirst();
+ // check that the order is as expected
+ logger.warn("testSmallBeforeFirst: checkpoint 4");
+ try {
+ long count = 0;
+ for (int i = 1; i < BF_SMALL_LOAD_SIZE * 2; i += 2) {
+ for (int j = 1; j < BF_SMALL_LOAD_SIZE * 2; j += 2) {
+ for (int k = 1; k < BF_SMALL_LOAD_SIZE * 2; k += 2) {
+ count++;
+ assertTrue(dbTuples.next());
+ assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
+ assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
+ assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
+ }
+ }
+ }
+
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+ logger.warn("testSmallBeforeFirst: checkpoint 5");
+
+ dbTuples.beforeFirst(new long[] { 3, 5 }, 0);
+ logger.warn("testSmallBeforeFirst: checkpoint 6");
+ // check that the order is as expected
+ try {
+ long count = 0;
+ int i = 3;
+ int j = 5;
+ for (int k = 1; k < BF_SMALL_LOAD_SIZE * 2; k += 2) {
+ count++;
+ assertTrue(dbTuples.next());
+ assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
+ assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
+ assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
+ }
+
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+ logger.warn("testSmallBeforeFirst: checkpoint 7");
+
+ dbTuples.beforeFirst(new long[] { 3, 4 }, 0);
+ logger.warn("testSmallBeforeFirst: checkpoint 8");
+ assertFalse(dbTuples.next());
+ }
+
+
+ public void testLargeBeforeFirst() throws Throwable {
+ logger.info("testLargeBeforeFirst");
+
+ LiteralTuples tt = new LiteralTuples(new String[] { "i", "j", "k" });
+
+ // iterate over a large enough range to guarantee several blocks
+ for (int i = (BF_LARGE_LOAD_SIZE * 2) - 1; i > 0; i -= 2) {
+ for (int j = (BF_LARGE_LOAD_SIZE * 2) - 1; j > 0; j -= 2) {
+ for (int k = (BF_LARGE_LOAD_SIZE * 2) - 1; k > 0; k -= 2) {
+ long[] v = new long[] { i, j, k };
+ tt.appendTuple(v);
+ }
+ }
+ }
+
+ dbTuples = new DbTuples(tt, rowComparator);
+
+ dbTuples.beforeFirst();
+ // check that the order is as expected
+ try {
+ long count = 0;
+ for (int i = 1; i < BF_LARGE_LOAD_SIZE * 2; i += 2) {
+ for (int j = 1; j < BF_LARGE_LOAD_SIZE * 2; j += 2) {
+ for (int k = 1; k < BF_LARGE_LOAD_SIZE * 2; k += 2) {
+ count++;
+ assertTrue(dbTuples.next());
+ assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
+ assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
+ assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
+ }
+ }
+ }
+
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+
+ dbTuples.beforeFirst(new long[] { 1, 133 }, 0);
+ // check that the order is as expected
+ try {
+ long count = 0;
+ int i = 1;
+ int j = 133;
+ for (int k = 1; k < BF_LARGE_LOAD_SIZE * 2; k += 2) {
+ count++;
+ if(!dbTuples.next()) {
+ logger.error("On iteration " + count + " dbTuples failed .next()");
+ assertTrue(false);
+ }
+ assertEquals("i On iteration " + count, i, dbTuples.getColumnValue(0));
+ assertEquals("j On iteration " + count, j, dbTuples.getColumnValue(1));
+ assertEquals("k On iteration " + count, k, dbTuples.getColumnValue(2));
+ }
+
+ // check that there aren't any extraneous values
+ assertTrue(!dbTuples.next());
+ } catch (Throwable e) {
+ // for debugging:
+ // dumpFile(dbTuples);
+ throw e;
+ }
+
+ dbTuples.beforeFirst(new long[] { 3, 4 }, 0);
+ assertFalse(dbTuples.next());
+ }
+
+
+ /**
+ * METHOD TO DO
+ *
+ * @param ft PARAMETER TO DO
+ * @throws Exception EXCEPTION TO DO
+ */
+ @SuppressWarnings("unused")
+ private void dumpFile(DbTuples ft) throws Exception {
+ PrintStream ps = new PrintStream(new FileOutputStream("/tmp/random.dump"));
+
+ try {
+ ft.beforeFirst();
+ while (ft.next()) {
+ ps.println(ft.getColumnValue(0));
+ }
+ } finally {
+ ps.close();
+ }
+ }
+}
More information about the Mulgara-svn
mailing list