Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
32
test/scr024/Makefile
Normal file
32
test/scr024/Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
TESTCLASSES=\
|
||||
./src/com/sleepycat/bind/serial/test/*.java\
|
||||
./src/com/sleepycat/bind/test/*.java\
|
||||
./src/com/sleepycat/bind/tuple/test/*.java\
|
||||
./src/com/sleepycat/collections/test/*.java\
|
||||
./src/com/sleepycat/collections/test/serial/*.java\
|
||||
./src/com/sleepycat/util/test/*.java
|
||||
|
||||
TESTSERIALPATH=com/sleepycat/collections/test/serial/TestSerial
|
||||
|
||||
all: dbtest.jar
|
||||
|
||||
dbtest.jar: classesdir
|
||||
# Compile the tests and build the test jar
|
||||
javac -classpath ${DB_JAR}:${REQUIRED_JARS} \
|
||||
-d ./classes ${TESTCLASSES}
|
||||
jar cf ./dbtest.jar -C ./classes ./com/sleepycat
|
||||
# Build the original version of TestSerial in the testserial directory
|
||||
mkdir -p "testserial/${TESTSERIALPATH}"
|
||||
cp "./src/${TESTSERIALPATH}.java.original" \
|
||||
"./testserial/${TESTSERIALPATH}.java"
|
||||
javac -classpath ${DB_JAR}:${REQUIRED_JARS} \
|
||||
-d ./testserial "testserial/${TESTSERIALPATH}.java"
|
||||
|
||||
classesdir:
|
||||
[ -d ./classes ] || (mkdir ./classes)
|
||||
|
||||
clean:
|
||||
[ -d ./classes ] && rm -rf ./classes
|
||||
[ -f ./dbtest.jar ] && rm ./dbtest.jar
|
||||
[ -d ./testserial ] && rm -rf ./testserial
|
||||
|
||||
16
test/scr024/README
Normal file
16
test/scr024/README
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
This directory contains a set of tests written in Java run by JUnit. To be
|
||||
able to run them you must first set the following environment variables.
|
||||
|
||||
example sh:
|
||||
JUNIT_JAR="$HOME/tools/junit3.8.1/junit.jar"
|
||||
export JUNIT_JAR
|
||||
XMLAPI_JAR="$HOME/tools/ant/lib/xml-apis.jar"
|
||||
export XMLAPI_JAR
|
||||
XMLIMPL_JAR="$HOME/tools/ant/lib/xercesImpl.jar"
|
||||
export XMLIMPL_JAR
|
||||
|
||||
example csh:
|
||||
setenv JUNIT_JAR $HOME/tools/junit3.8.1/junit.jar
|
||||
setenv XMLAPI_JAR $HOME/tools/ant/lib/xml-apis.jar
|
||||
setenv XMLIMPL_JAR $HOME/tools/ant/lib/xercesImpl.jar
|
||||
67
test/scr024/chk.bdb
Normal file
67
test/scr024/chk.bdb
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh -
|
||||
#
|
||||
# $Id: chk.bdb,v 12.1 2006/09/12 00:37:26 alexg Exp $
|
||||
#
|
||||
# Run the collections/bind test suite.
|
||||
|
||||
# NOTES:
|
||||
# This test requires one JAR not included with the Berkeley DB
|
||||
# distribution: JUnit (junit.jar) I've been using the 8/31/2002 version
|
||||
# of JUnit. You can download this JAR from http://jakarta.apache.org/
|
||||
#
|
||||
# JUNIT_JAR=/Users/gburd/Unix/opt/junit/junit.jar
|
||||
|
||||
[ "x$JUNIT_JAR" = "x" ] && {
|
||||
echo 'FAIL: unset environment variable JUNIT_JAR for junit.jar.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -f $JUNIT_JAR ] || {
|
||||
echo 'FAIL: JUNIT_JAR not a valid path to the junit.jar.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
d=..
|
||||
REQUIRED_JARS=$JUNIT_JAR
|
||||
DB_JAR=$d/db.jar
|
||||
DB_LIB_DIR=$d/.libs
|
||||
export DB_JAR
|
||||
export REQUIRED_JARS
|
||||
|
||||
# Build the tests.
|
||||
|
||||
make clean
|
||||
|
||||
[ -f ./dbtest.jar ] || (make dbtest.jar) || {
|
||||
echo 'FAIL: unable to find or build dbtest.jar'
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Perform initialization needed before StoredClassCatalogTest is run in
|
||||
# the tests below. The testserial directory must be first in the classpath.
|
||||
|
||||
c="com.sleepycat.collections.test.serial.StoredClassCatalogTestInit"
|
||||
echo "Running: $c"
|
||||
if java -Djava.library.path=$DB_LIB_DIR \
|
||||
-cp testserial:$REQUIRED_JARS:$DB_JAR:./dbtest.jar $c ; then
|
||||
:
|
||||
else
|
||||
echo "FAIL: test program failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run the tests.
|
||||
|
||||
for f in `find classes -name "*Test.class"`; do
|
||||
c=`echo "$f" | sed -e 's/classes\///' -e 's/\.class//' -e 's/\//./g'`
|
||||
echo "Running: $c"
|
||||
if java -Djava.library.path=$DB_LIB_DIR \
|
||||
-cp $REQUIRED_JARS:$DB_JAR:./dbtest.jar $c ; then
|
||||
:
|
||||
else
|
||||
echo "FAIL: test program failed"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
25
test/scr024/coverage/README
Normal file
25
test/scr024/coverage/README
Normal file
@@ -0,0 +1,25 @@
|
||||
The Ant build.xml file in this directory compiles all db Java sources (except
|
||||
examples), runs the test suite using Clover to instrument the sources, and then
|
||||
generates the Clover coverage reports.
|
||||
|
||||
You must place clover.jar in your Ant lib directory as well as placing
|
||||
clover.jar and velocity.jar in this directory. (Using a classpathref in the
|
||||
Ant javac task doesn't seem to work.)
|
||||
|
||||
$ cp <YOUR-CLOVER-INSTALL>/clover.jar .
|
||||
$ cp <YOUR-CLOVER-INSTALL>/velocity.jar .
|
||||
$ cp clover.jar <YOUR-ANT-DIRECTORY>/lib
|
||||
$ ant all
|
||||
|
||||
'ant all' will delete all output files, compile and run the tests, and then
|
||||
generate the reports.
|
||||
|
||||
'ant' will compile sources that need compiling and run the tests to collect
|
||||
coverage information.
|
||||
|
||||
'ant report' will generate the reports against the current coverage database.
|
||||
|
||||
The build.xml file works when run from db/test/scr024/coverage but it should
|
||||
also work when run from a build directory copied by the TCL test harness, e.g.,
|
||||
db/build_unix/TESTDIR/coverage.
|
||||
|
||||
233
test/scr024/coverage/build.xml
Normal file
233
test/scr024/coverage/build.xml
Normal file
@@ -0,0 +1,233 @@
|
||||
<!-- $Id: build.xml 63573 2008-05-23 21:43:21Z trent.nelson $ -->
|
||||
<project name="clover" default="build" basedir=".">
|
||||
|
||||
<property name="db" location="../../.."/>
|
||||
<property name="src" location="${db}/java/src"/>
|
||||
<property name="test.src" location="${db}/test/scr024/src"/>
|
||||
<property name="examples.src" location="${db}/examples_java/src"/>
|
||||
<property name="testserialdir" value="testserial"/>
|
||||
<property name="clover.initstring" location="reports/clover.db"/>
|
||||
<property name="clover.excludes" value="**/test/** collections/** db/** com/sleepycat/db/**"/>
|
||||
<!--
|
||||
<property name="build.compiler"
|
||||
value="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
|
||||
-->
|
||||
|
||||
<target name="all" depends="clean,test,report"/>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="classes"/>
|
||||
<delete dir="tmp"/>
|
||||
<delete dir="reports"/>
|
||||
</target>
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="classes"/>
|
||||
<mkdir dir="tmp"/>
|
||||
<mkdir dir="reports"/>
|
||||
</target>
|
||||
|
||||
<path id="clover.classpath">
|
||||
<pathelement location="clover.jar"/>
|
||||
<pathelement location="velocity.jar"/>
|
||||
</path>
|
||||
|
||||
<path id="classpath">
|
||||
<pathelement location="classes"/>
|
||||
<path refid="clover.classpath"/>
|
||||
</path>
|
||||
|
||||
<target name="build" depends="init">
|
||||
<javac destdir="classes" debug="on" source="1.5" target="1.5">
|
||||
<src path="${src}"/>
|
||||
<src path="${test.src}"/>
|
||||
<src path="${examples.src}"/>
|
||||
<exclude name="com/sleepycat/**/release/**"/>
|
||||
<exclude name="com/sleepycat/xa/**"/>
|
||||
</javac>
|
||||
<!-- Compile original version of TestSerial.java.original. -->
|
||||
<property name="testserialpath"
|
||||
value="com/sleepycat/collections/test/serial/TestSerial"/>
|
||||
<copy file="${test.src}/${testserialpath}.java.original"
|
||||
tofile="${testserialdir}/${testserialpath}.java"/>
|
||||
<javac destdir="${testserialdir}" debug="on" source="1.5" target="1.5"
|
||||
includeAntRuntime="true" srcdir="${testserialdir}">
|
||||
<include name="${testserialpath}.java"/>
|
||||
</javac>
|
||||
<!-- Compile original version of EvolveClasses. -->
|
||||
<copy file=
|
||||
"${test.src}/com/sleepycat/persist/test/EvolveClasses.java.original"
|
||||
tofile=
|
||||
"testevolvedir/com/sleepycat/persist/test/EvolveClasses.java"/>
|
||||
<copy file=
|
||||
"${test.src}/com/sleepycat/persist/test/EvolveCase.java"
|
||||
tofile=
|
||||
"testevolvedir/com/sleepycat/persist/test/EvolveCase.java"/>
|
||||
<copy file=
|
||||
"${test.src}/com/sleepycat/persist/test/PersistTestUtils.java"
|
||||
tofile=
|
||||
"testevolvedir/com/sleepycat/persist/test/PersistTestUtils.java"/>
|
||||
<javac debug="on" source="1.5" target="1.5" classpath="classes">
|
||||
<src path="testevolvedir"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="build">
|
||||
|
||||
<!-- Determine which tests to run. -->
|
||||
<condition property="dotestserial">
|
||||
<or>
|
||||
<not><isset property="testcase"/></not>
|
||||
<equals arg1="${testcase}" arg2=
|
||||
"com.sleepycat.collections.test.serial.StoredClassCatalogTest"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="dotestevolve">
|
||||
<or>
|
||||
<not><isset property="testcase"/></not>
|
||||
<equals arg1="${testcase}"
|
||||
arg2="com.sleepycat.persist.test.EvolveTest"/>
|
||||
</or>
|
||||
</condition>
|
||||
|
||||
<!-- Performs initialization needed before StoredClassCatalogTest. -->
|
||||
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
|
||||
showoutput="on">
|
||||
<jvmarg value="-ea"/>
|
||||
<classpath path="${testserialdir}"/> <!-- Must be first -->
|
||||
<classpath refid="classpath"/>
|
||||
<sysproperty key="testdestdir" value="./tmp"/>
|
||||
<sysproperty key="longtest" value="${longtest}"/>
|
||||
<formatter type="plain" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<test name=
|
||||
"com.sleepycat.collections.test.serial.StoredClassCatalogTestInit"
|
||||
todir="reports" if="dotestserial"/>
|
||||
</junit>
|
||||
|
||||
<!-- Performs initialization needed before persist EvolveTest. -->
|
||||
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
|
||||
showoutput="on">
|
||||
<jvmarg value="-ea"/>
|
||||
<classpath path="testevolvedir"/>
|
||||
<classpath refid="classpath"/>
|
||||
<sysproperty key="testdestdir" value="./tmp"/>
|
||||
<sysproperty key="longtest" value="${longtest}"/>
|
||||
<formatter type="plain" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<test name="com.sleepycat.persist.test.EvolveTestInit"
|
||||
todir="reports" if="dotestevolve"/>
|
||||
</junit>
|
||||
|
||||
<!-- Performs testcase if set, or batch tests. -->
|
||||
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
|
||||
showoutput="on">
|
||||
<jvmarg value="-ea"/>
|
||||
<classpath refid="classpath"/>
|
||||
<sysproperty key="testdestdir" value="./tmp"/>
|
||||
<sysproperty key="longtest" value="${longtest}"/>
|
||||
<formatter type="plain" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<test name="${testcase}" todir="reports" if="testcase"/>
|
||||
<batchtest todir="reports" unless="testcase">
|
||||
<fileset dir="classes" includes="**/*Test.class"/>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
<target name="testevolve" depends="build">
|
||||
</target>
|
||||
|
||||
<target name="examples" depends="build">
|
||||
<echo message="=== HelloDatabaseWorld ==="/>
|
||||
<java dir="." fork="yes" classpathref="classpath"
|
||||
classname="collections.hello.HelloDatabaseWorld"/>
|
||||
<echo message=""/>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="basic"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="index"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="entity"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="tuple"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="sentity"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="marshal"/>
|
||||
</antcall>
|
||||
<antcall target="one_shipment_example">
|
||||
<param name="param_name" value="factory"/>
|
||||
</antcall>
|
||||
<antcall target="one_persist_example">
|
||||
<param name="param_name" value="CustomKeyOrderExample"/>
|
||||
</antcall>
|
||||
<antcall target="one_persist_example">
|
||||
<param name="param_name" value="EventExample"/>
|
||||
</antcall>
|
||||
<antcall target="one_persist_example">
|
||||
<param name="param_name" value="EventExampleDPL"/>
|
||||
</antcall>
|
||||
<antcall target="one_persist_example">
|
||||
<param name="param_name" value="PersonExample"/>
|
||||
</antcall>
|
||||
<antcall target="DplDump">
|
||||
<param name="home" value="tmp"/>
|
||||
<param name="store" value="PersonStore"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
<target name="one_shipment_example">
|
||||
<echo message="=== ${param_name} ==="/>
|
||||
<delete dir="tmp"/>
|
||||
<mkdir dir="tmp"/>
|
||||
<java dir="." fork="yes" classpathref="classpath"
|
||||
classname="collections.ship.${param_name}.Sample"/>
|
||||
</target>
|
||||
|
||||
<target name="one_persist_example">
|
||||
<echo message="=== ${param_name} ==="/>
|
||||
<delete dir="tmp"/>
|
||||
<mkdir dir="tmp"/>
|
||||
<java fork="yes" dir="." classname="persist.${param_name}">
|
||||
<jvmarg value="-ea"/>
|
||||
<arg line="-h tmp"/>
|
||||
<classpath refid="classpath"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="DplDump">
|
||||
<echo message="=== DplDump ${home} ${store} ==="/>
|
||||
<java fork="yes" dir="." classname="persist.DplDump">
|
||||
<jvmarg value="-ea"/>
|
||||
<arg line="-h ${home} -s ${store}"/>
|
||||
<classpath refid="classpath"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<!-- Using fork="yes" does not work for AccessExample, apparently because
|
||||
it is interactive and the input stream of the forked process isn't
|
||||
functional; therefore this sample writes to the base directory.
|
||||
-->
|
||||
<target name="access_example" depends="build">
|
||||
<echo message="=== AccessExample ==="/>
|
||||
<java classpathref="classpath"
|
||||
classname="collections.access.AccessExample">
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="report">
|
||||
<java classname="com.cortexeb.tools.clover.reporters.html.HtmlReporter"
|
||||
fork="true">
|
||||
<arg line="--outputdir reports --showSrc --initstring ${clover.initstring} --title 'Berkeley DB Java BDB API'"/>
|
||||
<classpath refid="clover.classpath"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: MarshalledObject.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.serial.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
|
||||
import com.sleepycat.bind.tuple.TupleInput;
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class MarshalledObject
|
||||
implements Serializable, MarshalledTupleKeyEntity {
|
||||
|
||||
private String data;
|
||||
private transient String primaryKey;
|
||||
private String indexKey1;
|
||||
private String indexKey2;
|
||||
|
||||
public MarshalledObject(String data, String primaryKey,
|
||||
String indexKey1, String indexKey2) {
|
||||
this.data = data;
|
||||
this.primaryKey = primaryKey;
|
||||
this.indexKey1 = indexKey1;
|
||||
this.indexKey2 = indexKey2;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
|
||||
try {
|
||||
MarshalledObject other = (MarshalledObject) o;
|
||||
|
||||
return this.data.equals(other.data) &&
|
||||
this.primaryKey.equals(other.primaryKey) &&
|
||||
this.indexKey1.equals(other.indexKey1) &&
|
||||
this.indexKey2.equals(other.indexKey2);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getPrimaryKey() {
|
||||
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
public String getIndexKey1() {
|
||||
|
||||
return indexKey1;
|
||||
}
|
||||
|
||||
public String getIndexKey2() {
|
||||
|
||||
return indexKey2;
|
||||
}
|
||||
|
||||
public int expectedKeyLength() {
|
||||
|
||||
return primaryKey.length() + 1;
|
||||
}
|
||||
|
||||
public void marshalPrimaryKey(TupleOutput keyOutput) {
|
||||
|
||||
keyOutput.writeString(primaryKey);
|
||||
}
|
||||
|
||||
public void unmarshalPrimaryKey(TupleInput keyInput) {
|
||||
|
||||
primaryKey = keyInput.readString();
|
||||
}
|
||||
|
||||
public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
|
||||
|
||||
if ("1".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
keyOutput.writeString(indexKey1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ("2".equals(keyName)) {
|
||||
if (indexKey2.length() > 0) {
|
||||
keyOutput.writeString(indexKey2);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown keyName: " + keyName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean nullifyForeignKey(String keyName) {
|
||||
|
||||
if ("1".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
indexKey1 = "";
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ("2".equals(keyName)) {
|
||||
if (indexKey2.length() > 0) {
|
||||
indexKey2 = "";
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown keyName: " + keyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: NullClassCatalog.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.serial.test;
|
||||
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.bind.serial.ClassCatalog;
|
||||
|
||||
/**
|
||||
* NullCatalog is a dummy Catalog implementation that simply
|
||||
* returns large (8 byte) class IDs so that ObjectOutput
|
||||
* can be simulated when computing a serialized size.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class NullClassCatalog implements ClassCatalog {
|
||||
|
||||
private long id = Long.MAX_VALUE;
|
||||
|
||||
public void close()
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
public byte[] getClassID(ObjectStreamClass classFormat)
|
||||
throws DatabaseException {
|
||||
|
||||
return BigInteger.valueOf(id--).toByteArray();
|
||||
}
|
||||
|
||||
public ObjectStreamClass getClassFormat(byte[] classID)
|
||||
throws DatabaseException, ClassNotFoundException {
|
||||
|
||||
return null; // ObjectInput not supported
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: SerialBindingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.serial.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.EntityBinding;
|
||||
import com.sleepycat.bind.serial.ClassCatalog;
|
||||
import com.sleepycat.bind.serial.SerialBinding;
|
||||
import com.sleepycat.bind.serial.SerialSerialBinding;
|
||||
import com.sleepycat.bind.serial.TupleSerialMarshalledBinding;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
import com.sleepycat.util.FastOutputStream;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class SerialBindingTest extends TestCase {
|
||||
|
||||
private ClassCatalog catalog;
|
||||
private DatabaseEntry buffer;
|
||||
private DatabaseEntry keyBuffer;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(SerialBindingTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public SerialBindingTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("SerialBindingTest." + getName());
|
||||
catalog = new TestClassCatalog();
|
||||
buffer = new DatabaseEntry();
|
||||
keyBuffer = new DatabaseEntry();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
/* Ensure that GC can cleanup. */
|
||||
catalog = null;
|
||||
buffer = null;
|
||||
keyBuffer = null;
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Throwable {
|
||||
|
||||
try {
|
||||
super.runTest();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUnwrapper.unwrap(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void primitiveBindingTest(Object val) {
|
||||
|
||||
Class cls = val.getClass();
|
||||
SerialBinding binding = new SerialBinding(catalog, cls);
|
||||
|
||||
binding.objectToEntry(val, buffer);
|
||||
assertTrue(buffer.getSize() > 0);
|
||||
|
||||
Object val2 = binding.entryToObject(buffer);
|
||||
assertSame(cls, val2.getClass());
|
||||
assertEquals(val, val2);
|
||||
|
||||
Object valWithWrongCls = (cls == String.class)
|
||||
? ((Object) new Integer(0)) : ((Object) new String(""));
|
||||
try {
|
||||
binding.objectToEntry(valWithWrongCls, buffer);
|
||||
} catch (IllegalArgumentException expected) {}
|
||||
}
|
||||
|
||||
public void testPrimitiveBindings() {
|
||||
|
||||
primitiveBindingTest("abc");
|
||||
primitiveBindingTest(new Character('a'));
|
||||
primitiveBindingTest(new Boolean(true));
|
||||
primitiveBindingTest(new Byte((byte) 123));
|
||||
primitiveBindingTest(new Short((short) 123));
|
||||
primitiveBindingTest(new Integer(123));
|
||||
primitiveBindingTest(new Long(123));
|
||||
primitiveBindingTest(new Float(123.123));
|
||||
primitiveBindingTest(new Double(123.123));
|
||||
}
|
||||
|
||||
public void testNullObjects() {
|
||||
|
||||
SerialBinding binding = new SerialBinding(catalog, null);
|
||||
buffer.setSize(0);
|
||||
binding.objectToEntry(null, buffer);
|
||||
assertTrue(buffer.getSize() > 0);
|
||||
assertEquals(null, binding.entryToObject(buffer));
|
||||
}
|
||||
|
||||
public void testSerialSerialBinding() {
|
||||
|
||||
SerialBinding keyBinding = new SerialBinding(catalog, String.class);
|
||||
SerialBinding valueBinding = new SerialBinding(catalog, String.class);
|
||||
EntityBinding binding = new MySerialSerialBinding(keyBinding,
|
||||
valueBinding);
|
||||
|
||||
String val = "key#value?indexKey";
|
||||
binding.objectToData(val, buffer);
|
||||
assertTrue(buffer.getSize() > 0);
|
||||
binding.objectToKey(val, keyBuffer);
|
||||
assertTrue(keyBuffer.getSize() > 0);
|
||||
|
||||
Object result = binding.entryToObject(keyBuffer, buffer);
|
||||
assertEquals(val, result);
|
||||
}
|
||||
|
||||
// also tests TupleSerialBinding since TupleSerialMarshalledBinding extends
|
||||
// it
|
||||
public void testTupleSerialMarshalledBinding() {
|
||||
|
||||
SerialBinding valueBinding = new SerialBinding(catalog,
|
||||
MarshalledObject.class);
|
||||
EntityBinding binding =
|
||||
new TupleSerialMarshalledBinding(valueBinding);
|
||||
|
||||
MarshalledObject val = new MarshalledObject("abc", "primary",
|
||||
"index1", "index2");
|
||||
binding.objectToData(val, buffer);
|
||||
assertTrue(buffer.getSize() > 0);
|
||||
binding.objectToKey(val, keyBuffer);
|
||||
assertEquals(val.expectedKeyLength(), keyBuffer.getSize());
|
||||
|
||||
Object result = binding.entryToObject(keyBuffer, buffer);
|
||||
assertTrue(result instanceof MarshalledObject);
|
||||
val = (MarshalledObject) result;
|
||||
assertEquals("abc", val.getData());
|
||||
assertEquals("primary", val.getPrimaryKey());
|
||||
assertEquals("index1", val.getIndexKey1());
|
||||
assertEquals("index2", val.getIndexKey2());
|
||||
}
|
||||
|
||||
public void testBufferSize() {
|
||||
|
||||
CaptureSizeBinding binding =
|
||||
new CaptureSizeBinding(catalog, String.class);
|
||||
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertEquals(FastOutputStream.DEFAULT_INIT_SIZE, binding.bufSize);
|
||||
|
||||
binding.setSerialBufferSize(1000);
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertEquals(1000, binding.bufSize);
|
||||
}
|
||||
|
||||
private static class CaptureSizeBinding extends SerialBinding {
|
||||
|
||||
int bufSize;
|
||||
|
||||
CaptureSizeBinding(ClassCatalog classCatalog, Class baseClass) {
|
||||
super(classCatalog, baseClass);
|
||||
}
|
||||
|
||||
public FastOutputStream getSerialOutput(Object object) {
|
||||
FastOutputStream fos = super.getSerialOutput(object);
|
||||
bufSize = fos.getBufferBytes().length;
|
||||
return fos;
|
||||
}
|
||||
}
|
||||
|
||||
public void testBufferOverride() {
|
||||
|
||||
FastOutputStream out = new FastOutputStream(10);
|
||||
CachedOutputBinding binding =
|
||||
new CachedOutputBinding(catalog, String.class, out);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("aaaaaaaaaaaaaaaaaaaaaa", buffer);
|
||||
assertEquals("aaaaaaaaaaaaaaaaaaaaaa", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
}
|
||||
|
||||
private static class CachedOutputBinding extends SerialBinding {
|
||||
|
||||
FastOutputStream out;
|
||||
boolean used;
|
||||
|
||||
CachedOutputBinding(ClassCatalog classCatalog,
|
||||
Class baseClass,
|
||||
FastOutputStream out) {
|
||||
super(classCatalog, baseClass);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public FastOutputStream getSerialOutput(Object object) {
|
||||
out.reset();
|
||||
used = true;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MySerialSerialBinding extends SerialSerialBinding {
|
||||
|
||||
private MySerialSerialBinding(SerialBinding keyBinding,
|
||||
SerialBinding valueBinding) {
|
||||
|
||||
super(keyBinding, valueBinding);
|
||||
}
|
||||
|
||||
public Object entryToObject(Object keyInput, Object valueInput) {
|
||||
|
||||
return "" + keyInput + '#' + valueInput;
|
||||
}
|
||||
|
||||
public Object objectToKey(Object object) {
|
||||
|
||||
String s = (String) object;
|
||||
int i = s.indexOf('#');
|
||||
if (i < 0 || i == s.length() - 1) {
|
||||
throw new IllegalArgumentException(s);
|
||||
} else {
|
||||
return s.substring(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
public Object objectToData(Object object) {
|
||||
|
||||
String s = (String) object;
|
||||
int i = s.indexOf('#');
|
||||
if (i < 0 || i == s.length() - 1) {
|
||||
throw new IllegalArgumentException(s);
|
||||
} else {
|
||||
return s.substring(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that overriding SerialBinding.getClassLoader is possible. This is
|
||||
* a crude test because to create a truly working class loader is a large
|
||||
* undertaking.
|
||||
*/
|
||||
public void testClassloaderOverride()
|
||||
throws Exception {
|
||||
|
||||
DatabaseEntry entry = new DatabaseEntry();
|
||||
|
||||
SerialBinding binding = new CustomLoaderBinding
|
||||
(catalog, null, new FailureClassLoader());
|
||||
|
||||
try {
|
||||
binding.objectToEntry(new MyClass(), entry);
|
||||
binding.entryToObject(entry);
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
assertTrue(e.getMessage().startsWith("expect failure"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomLoaderBinding extends SerialBinding {
|
||||
|
||||
private ClassLoader loader;
|
||||
|
||||
CustomLoaderBinding(ClassCatalog classCatalog,
|
||||
Class baseClass,
|
||||
ClassLoader loader) {
|
||||
|
||||
super(classCatalog, baseClass);
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return loader;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FailureClassLoader extends ClassLoader {
|
||||
|
||||
public Class loadClass(String name)
|
||||
throws ClassNotFoundException {
|
||||
|
||||
throw new RuntimeException("expect failure: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyClass implements Serializable {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestClassCatalog.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.serial.test;
|
||||
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.sleepycat.bind.serial.ClassCatalog;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TestClassCatalog implements ClassCatalog {
|
||||
|
||||
private HashMap idToDescMap = new HashMap();
|
||||
private HashMap nameToIdMap = new HashMap();
|
||||
private int nextId = 1;
|
||||
|
||||
public TestClassCatalog() {
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
public synchronized byte[] getClassID(ObjectStreamClass desc)
|
||||
throws DatabaseException {
|
||||
|
||||
String className = desc.getName();
|
||||
byte[] id = (byte[]) nameToIdMap.get(className);
|
||||
if (id == null) {
|
||||
String strId = String.valueOf(nextId);
|
||||
id = strId.getBytes();
|
||||
nextId += 1;
|
||||
|
||||
idToDescMap.put(strId, desc);
|
||||
nameToIdMap.put(className, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public synchronized ObjectStreamClass getClassFormat(byte[] id)
|
||||
throws DatabaseException {
|
||||
|
||||
String strId = new String(id);
|
||||
ObjectStreamClass desc = (ObjectStreamClass) idToDescMap.get(strId);
|
||||
if (desc == null) {
|
||||
throw new DatabaseException("classID not found");
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
491
test/scr024/src/com/sleepycat/bind/test/BindingSpeedTest.java
Normal file
491
test/scr024/src/com/sleepycat/bind/test/BindingSpeedTest.java
Normal file
@@ -0,0 +1,491 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: BindingSpeedTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.test;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
import com.sleepycat.bind.serial.SerialInput;
|
||||
import com.sleepycat.bind.serial.SerialOutput;
|
||||
import com.sleepycat.bind.serial.test.TestClassCatalog;
|
||||
import com.sleepycat.bind.tuple.TupleInput;
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
import com.sleepycat.util.FastInputStream;
|
||||
import com.sleepycat.util.FastOutputStream;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class BindingSpeedTest extends TestCase {
|
||||
|
||||
static final String JAVA_UNSHARED = "java-unshared".intern();
|
||||
static final String JAVA_SHARED = "java-shared".intern();
|
||||
static final String JAVA_EXTERNALIZABLE = "java-externalizable".intern();
|
||||
static final String XML_SAX = "xml-sax".intern();
|
||||
static final String TUPLE = "tuple".intern();
|
||||
static final String REFLECT_METHOD = "reflectMethod".intern();
|
||||
static final String REFLECT_FIELD = "reflectField".intern();
|
||||
|
||||
static final int RUN_COUNT = 1000;
|
||||
static final boolean VERBOSE = false;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTest(new BindingSpeedTest(JAVA_UNSHARED));
|
||||
suite.addTest(new BindingSpeedTest(JAVA_SHARED));
|
||||
suite.addTest(new BindingSpeedTest(JAVA_EXTERNALIZABLE));
|
||||
suite.addTest(new BindingSpeedTest(XML_SAX));
|
||||
suite.addTest(new BindingSpeedTest(TUPLE));
|
||||
suite.addTest(new BindingSpeedTest(REFLECT_METHOD));
|
||||
suite.addTest(new BindingSpeedTest(REFLECT_FIELD));
|
||||
return suite;
|
||||
}
|
||||
|
||||
private String command;
|
||||
private FastOutputStream fo;
|
||||
private TupleOutput to;
|
||||
private TestClassCatalog jtc;
|
||||
private byte[] buf;
|
||||
private XMLReader parser;
|
||||
private Method[] getters;
|
||||
private Method[] setters;
|
||||
private Field[] fields;
|
||||
|
||||
public BindingSpeedTest(String name) {
|
||||
|
||||
super("BindingSpeedTest." + name);
|
||||
command = name;
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
|
||||
boolean isTuple = false;
|
||||
boolean isReflectMethod = false;
|
||||
boolean isReflectField = false;
|
||||
boolean isXmlSax = false;
|
||||
boolean isSerial = false;
|
||||
boolean isShared = false;
|
||||
boolean isExternalizable = false;
|
||||
|
||||
if (command == TUPLE) {
|
||||
isTuple = true;
|
||||
} else if (command == REFLECT_METHOD) {
|
||||
isReflectMethod = true;
|
||||
} else if (command == REFLECT_FIELD) {
|
||||
isReflectField = true;
|
||||
} else if (command == XML_SAX) {
|
||||
isXmlSax = true;
|
||||
} else if (command == JAVA_UNSHARED) {
|
||||
isSerial = true;
|
||||
} else if (command == JAVA_SHARED) {
|
||||
isSerial = true;
|
||||
isShared = true;
|
||||
} else if (command == JAVA_EXTERNALIZABLE) {
|
||||
isSerial = true;
|
||||
isShared = true;
|
||||
isExternalizable = true;
|
||||
} else {
|
||||
throw new Exception("invalid command: " + command);
|
||||
}
|
||||
|
||||
// Do initialization
|
||||
|
||||
if (isTuple) {
|
||||
initTuple();
|
||||
} else if (isReflectMethod) {
|
||||
initReflectMethod();
|
||||
} else if (isReflectField) {
|
||||
initReflectField();
|
||||
} else if (isXmlSax) {
|
||||
initXmlSax();
|
||||
} else if (isSerial) {
|
||||
if (isShared) {
|
||||
initSerialShared();
|
||||
} else {
|
||||
initSerialUnshared();
|
||||
}
|
||||
}
|
||||
|
||||
// Prime the Java compiler
|
||||
|
||||
int size = 0;
|
||||
for (int i = 0; i < RUN_COUNT; i += 1) {
|
||||
|
||||
if (isTuple) {
|
||||
size = runTuple();
|
||||
} else if (isReflectMethod) {
|
||||
size = runReflectMethod();
|
||||
} else if (isReflectField) {
|
||||
size = runReflectField();
|
||||
} else if (isXmlSax) {
|
||||
size = runXmlSax();
|
||||
} else if (isSerial) {
|
||||
if (isShared) {
|
||||
if (isExternalizable) {
|
||||
size = runSerialExternalizable();
|
||||
} else {
|
||||
size = runSerialShared();
|
||||
}
|
||||
} else {
|
||||
size = runSerialUnshared();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then run the timing tests
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < RUN_COUNT; i += 1) {
|
||||
if (isTuple) {
|
||||
size = runTuple();
|
||||
} else if (isReflectMethod) {
|
||||
size = runReflectMethod();
|
||||
} else if (isReflectField) {
|
||||
size = runReflectField();
|
||||
} else if (isXmlSax) {
|
||||
size = runXmlSax();
|
||||
} else if (isSerial) {
|
||||
if (isShared) {
|
||||
if (isExternalizable) {
|
||||
size = runSerialExternalizable();
|
||||
} else {
|
||||
size = runSerialShared();
|
||||
}
|
||||
} else {
|
||||
size = runSerialUnshared();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long stopTime = System.currentTimeMillis();
|
||||
|
||||
assertTrue("data size too big", size < 250);
|
||||
|
||||
if (VERBOSE) {
|
||||
System.out.println(command);
|
||||
System.out.println("data size: " + size);
|
||||
System.out.println("run time: " +
|
||||
((stopTime - startTime) / (double) RUN_COUNT));
|
||||
}
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
/* Ensure that GC can cleanup. */
|
||||
command = null;
|
||||
fo = null;
|
||||
to = null;
|
||||
jtc = null;
|
||||
buf = null;
|
||||
parser = null;
|
||||
}
|
||||
|
||||
void initSerialUnshared()
|
||||
throws Exception {
|
||||
|
||||
fo = new FastOutputStream();
|
||||
}
|
||||
|
||||
int runSerialUnshared()
|
||||
throws Exception {
|
||||
|
||||
fo.reset();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fo);
|
||||
oos.writeObject(new Data());
|
||||
byte[] bytes = fo.toByteArray();
|
||||
FastInputStream fi = new FastInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(fi);
|
||||
ois.readObject();
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
void initSerialShared()
|
||||
throws Exception {
|
||||
|
||||
jtc = new TestClassCatalog();
|
||||
fo = new FastOutputStream();
|
||||
}
|
||||
|
||||
int runSerialShared()
|
||||
throws Exception {
|
||||
|
||||
fo.reset();
|
||||
SerialOutput oos = new SerialOutput(fo, jtc);
|
||||
oos.writeObject(new Data());
|
||||
byte[] bytes = fo.toByteArray();
|
||||
FastInputStream fi = new FastInputStream(bytes);
|
||||
SerialInput ois = new SerialInput(fi, jtc);
|
||||
ois.readObject();
|
||||
return (bytes.length - SerialOutput.getStreamHeader().length);
|
||||
}
|
||||
|
||||
int runSerialExternalizable()
|
||||
throws Exception {
|
||||
|
||||
fo.reset();
|
||||
SerialOutput oos = new SerialOutput(fo, jtc);
|
||||
oos.writeObject(new Data2());
|
||||
byte[] bytes = fo.toByteArray();
|
||||
FastInputStream fi = new FastInputStream(bytes);
|
||||
SerialInput ois = new SerialInput(fi, jtc);
|
||||
ois.readObject();
|
||||
return (bytes.length - SerialOutput.getStreamHeader().length);
|
||||
}
|
||||
|
||||
void initTuple()
|
||||
throws Exception {
|
||||
|
||||
buf = new byte[500];
|
||||
to = new TupleOutput(buf);
|
||||
}
|
||||
|
||||
int runTuple()
|
||||
throws Exception {
|
||||
|
||||
to.reset();
|
||||
new Data().writeTuple(to);
|
||||
|
||||
TupleInput ti = new TupleInput(
|
||||
to.getBufferBytes(), to.getBufferOffset(),
|
||||
to.getBufferLength());
|
||||
new Data().readTuple(ti);
|
||||
|
||||
return to.getBufferLength();
|
||||
}
|
||||
|
||||
void initReflectMethod()
|
||||
throws Exception {
|
||||
|
||||
initTuple();
|
||||
|
||||
Class cls = Data.class;
|
||||
|
||||
getters = new Method[5];
|
||||
getters[0] = cls.getMethod("getField1", new Class[0]);
|
||||
getters[1] = cls.getMethod("getField2", new Class[0]);
|
||||
getters[2] = cls.getMethod("getField3", new Class[0]);
|
||||
getters[3] = cls.getMethod("getField4", new Class[0]);
|
||||
getters[4] = cls.getMethod("getField5", new Class[0]);
|
||||
|
||||
setters = new Method[5];
|
||||
setters[0] = cls.getMethod("setField1", new Class[] {String.class});
|
||||
setters[1] = cls.getMethod("setField2", new Class[] {String.class});
|
||||
setters[2] = cls.getMethod("setField3", new Class[] {Integer.TYPE});
|
||||
setters[3] = cls.getMethod("setField4", new Class[] {Integer.TYPE});
|
||||
setters[4] = cls.getMethod("setField5", new Class[] {String.class});
|
||||
}
|
||||
|
||||
int runReflectMethod()
|
||||
throws Exception {
|
||||
|
||||
to.reset();
|
||||
Data data = new Data();
|
||||
to.writeString((String) getters[0].invoke(data, (Object[]) null));
|
||||
to.writeString((String) getters[1].invoke(data, (Object[]) null));
|
||||
to.writeInt(((Integer) getters[2].invoke(data, (Object[]) null)).intValue());
|
||||
to.writeInt(((Integer) getters[3].invoke(data, (Object[]) null)).intValue());
|
||||
to.writeString((String) getters[4].invoke(data, (Object[]) null));
|
||||
|
||||
TupleInput ti = new TupleInput(
|
||||
to.getBufferBytes(), to.getBufferOffset(),
|
||||
to.getBufferLength());
|
||||
data = new Data();
|
||||
setters[0].invoke(data, new Object[] {ti.readString()});
|
||||
setters[1].invoke(data, new Object[] {ti.readString()});
|
||||
setters[2].invoke(data, new Object[] {new Integer(ti.readInt())});
|
||||
setters[3].invoke(data, new Object[] {new Integer(ti.readInt())});
|
||||
setters[4].invoke(data, new Object[] {ti.readString()});
|
||||
|
||||
return to.getBufferLength();
|
||||
}
|
||||
|
||||
void initReflectField()
|
||||
throws Exception {
|
||||
|
||||
initTuple();
|
||||
|
||||
Class cls = Data.class;
|
||||
|
||||
fields = new Field[5];
|
||||
fields[0] = cls.getField("field1");
|
||||
fields[1] = cls.getField("field2");
|
||||
fields[2] = cls.getField("field3");
|
||||
fields[3] = cls.getField("field4");
|
||||
fields[4] = cls.getField("field5");
|
||||
}
|
||||
|
||||
int runReflectField()
|
||||
throws Exception {
|
||||
|
||||
to.reset();
|
||||
Data data = new Data();
|
||||
to.writeString((String) fields[0].get(data));
|
||||
to.writeString((String) fields[1].get(data));
|
||||
to.writeInt(((Integer) fields[2].get(data)).intValue());
|
||||
to.writeInt(((Integer) fields[3].get(data)).intValue());
|
||||
to.writeString((String) fields[4].get(data));
|
||||
|
||||
TupleInput ti = new TupleInput(
|
||||
to.getBufferBytes(), to.getBufferOffset(),
|
||||
to.getBufferLength());
|
||||
data = new Data();
|
||||
fields[0].set(data, ti.readString());
|
||||
fields[1].set(data, ti.readString());
|
||||
fields[2].set(data, new Integer(ti.readInt()));
|
||||
fields[3].set(data, new Integer(ti.readInt()));
|
||||
fields[4].set(data, ti.readString());
|
||||
|
||||
return to.getBufferLength();
|
||||
}
|
||||
|
||||
void initXmlSax()
|
||||
throws Exception {
|
||||
|
||||
buf = new byte[500];
|
||||
fo = new FastOutputStream();
|
||||
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
|
||||
saxFactory.setNamespaceAware(true);
|
||||
parser = saxFactory.newSAXParser().getXMLReader();
|
||||
}
|
||||
|
||||
int runXmlSax()
|
||||
throws Exception {
|
||||
|
||||
fo.reset();
|
||||
OutputStreamWriter writer = new OutputStreamWriter(fo);
|
||||
new Data().writeXmlText(writer);
|
||||
|
||||
byte[] bytes = fo.toByteArray();
|
||||
FastInputStream fi = new FastInputStream(bytes);
|
||||
InputSource input = new InputSource(fi);
|
||||
parser.parse(input);
|
||||
|
||||
//InputStreamReader reader = new InputStreamReader(fi);
|
||||
//new Data().readXmlText(??);
|
||||
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
static class Data2 extends Data implements Externalizable {
|
||||
|
||||
public Data2() {}
|
||||
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
field1 = in.readUTF();
|
||||
field2 = in.readUTF();
|
||||
field3 = in.readInt();
|
||||
field4 = in.readInt();
|
||||
field5 = in.readUTF();
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException {
|
||||
|
||||
out.writeUTF(field1);
|
||||
out.writeUTF(field2);
|
||||
out.writeInt(field3);
|
||||
out.writeInt(field4);
|
||||
out.writeUTF(field5);
|
||||
}
|
||||
}
|
||||
|
||||
static class Data implements Serializable {
|
||||
|
||||
public String field1 = "field1";
|
||||
public String field2 = "field2";
|
||||
public int field3 = 333;
|
||||
public int field4 = 444;
|
||||
public String field5 = "field5";
|
||||
|
||||
public String getField1() { return field1; }
|
||||
public String getField2() { return field2; }
|
||||
public int getField3() { return field3; }
|
||||
public int getField4() { return field4; }
|
||||
public String getField5() { return field5; }
|
||||
|
||||
public void setField1(String v) { field1 = v; }
|
||||
public void setField2(String v) { field2 = v; }
|
||||
public void setField3(int v) { field3 = v; }
|
||||
public void setField4(int v) { field4 = v; }
|
||||
public void setField5(String v) { field5 = v; }
|
||||
|
||||
void readTuple(TupleInput _input) {
|
||||
|
||||
field1 = _input.readString();
|
||||
field2 = _input.readString();
|
||||
field3 = _input.readInt();
|
||||
field4 = _input.readInt();
|
||||
field5 = _input.readString();
|
||||
}
|
||||
|
||||
void writeTuple(TupleOutput _output) {
|
||||
|
||||
_output.writeString(field1);
|
||||
_output.writeString(field2);
|
||||
_output.writeInt(field3);
|
||||
_output.writeInt(field4);
|
||||
_output.writeString(field5);
|
||||
}
|
||||
|
||||
void writeXmlText(Writer writer) throws IOException {
|
||||
|
||||
writer.write("<Data><Field1>");
|
||||
writer.write(field1);
|
||||
writer.write("</Field1><Field2>");
|
||||
writer.write(field2);
|
||||
writer.write("</Field2><Field3>");
|
||||
writer.write(String.valueOf(field3));
|
||||
writer.write("</Field3><Field4>");
|
||||
writer.write(String.valueOf(field4));
|
||||
writer.write("</Field4><Field5>");
|
||||
writer.write(field5);
|
||||
writer.write("</Field5></Data>");
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: MarshalledObject.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.tuple.test;
|
||||
|
||||
import com.sleepycat.bind.tuple.MarshalledTupleEntry;
|
||||
import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
|
||||
import com.sleepycat.bind.tuple.TupleInput;
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class MarshalledObject
|
||||
implements MarshalledTupleEntry, MarshalledTupleKeyEntity {
|
||||
|
||||
private String data;
|
||||
private String primaryKey;
|
||||
private String indexKey1;
|
||||
private String indexKey2;
|
||||
|
||||
public MarshalledObject() {
|
||||
}
|
||||
|
||||
MarshalledObject(String data, String primaryKey,
|
||||
String indexKey1, String indexKey2) {
|
||||
|
||||
this.data = data;
|
||||
this.primaryKey = primaryKey;
|
||||
this.indexKey1 = indexKey1;
|
||||
this.indexKey2 = indexKey2;
|
||||
}
|
||||
|
||||
String getData() {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
String getPrimaryKey() {
|
||||
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
String getIndexKey1() {
|
||||
|
||||
return indexKey1;
|
||||
}
|
||||
|
||||
String getIndexKey2() {
|
||||
|
||||
return indexKey2;
|
||||
}
|
||||
|
||||
int expectedDataLength() {
|
||||
|
||||
return data.length() + 1 +
|
||||
indexKey1.length() + 1 +
|
||||
indexKey2.length() + 1;
|
||||
}
|
||||
|
||||
int expectedKeyLength() {
|
||||
|
||||
return primaryKey.length() + 1;
|
||||
}
|
||||
|
||||
public void marshalEntry(TupleOutput dataOutput) {
|
||||
|
||||
dataOutput.writeString(data);
|
||||
dataOutput.writeString(indexKey1);
|
||||
dataOutput.writeString(indexKey2);
|
||||
}
|
||||
|
||||
public void unmarshalEntry(TupleInput dataInput) {
|
||||
|
||||
data = dataInput.readString();
|
||||
indexKey1 = dataInput.readString();
|
||||
indexKey2 = dataInput.readString();
|
||||
}
|
||||
|
||||
public void marshalPrimaryKey(TupleOutput keyOutput) {
|
||||
|
||||
keyOutput.writeString(primaryKey);
|
||||
}
|
||||
|
||||
public void unmarshalPrimaryKey(TupleInput keyInput) {
|
||||
|
||||
primaryKey = keyInput.readString();
|
||||
}
|
||||
|
||||
public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
|
||||
|
||||
if ("1".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
keyOutput.writeString(indexKey1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ("2".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
keyOutput.writeString(indexKey2);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown keyName: " + keyName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean nullifyForeignKey(String keyName) {
|
||||
|
||||
if ("1".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
indexKey1 = "";
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ("2".equals(keyName)) {
|
||||
if (indexKey1.length() > 0) {
|
||||
indexKey2 = "";
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown keyName: " + keyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,420 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TupleBindingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.tuple.test;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import com.sleepycat.bind.EntityBinding;
|
||||
import com.sleepycat.bind.EntryBinding;
|
||||
import com.sleepycat.bind.tuple.BooleanBinding;
|
||||
import com.sleepycat.bind.tuple.ByteBinding;
|
||||
import com.sleepycat.bind.tuple.CharacterBinding;
|
||||
import com.sleepycat.bind.tuple.DoubleBinding;
|
||||
import com.sleepycat.bind.tuple.FloatBinding;
|
||||
import com.sleepycat.bind.tuple.IntegerBinding;
|
||||
import com.sleepycat.bind.tuple.LongBinding;
|
||||
import com.sleepycat.bind.tuple.ShortBinding;
|
||||
import com.sleepycat.bind.tuple.BigIntegerBinding;
|
||||
import com.sleepycat.bind.tuple.SortedDoubleBinding;
|
||||
import com.sleepycat.bind.tuple.SortedFloatBinding;
|
||||
import com.sleepycat.bind.tuple.StringBinding;
|
||||
import com.sleepycat.bind.tuple.TupleBinding;
|
||||
import com.sleepycat.bind.tuple.TupleInput;
|
||||
import com.sleepycat.bind.tuple.TupleInputBinding;
|
||||
import com.sleepycat.bind.tuple.TupleMarshalledBinding;
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
import com.sleepycat.bind.tuple.TupleTupleMarshalledBinding;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.util.FastOutputStream;
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TupleBindingTest extends TestCase {
|
||||
|
||||
private DatabaseEntry buffer;
|
||||
private DatabaseEntry keyBuffer;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(TupleBindingTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public TupleBindingTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("TupleBindingTest." + getName());
|
||||
buffer = new DatabaseEntry();
|
||||
keyBuffer = new DatabaseEntry();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
/* Ensure that GC can cleanup. */
|
||||
buffer = null;
|
||||
keyBuffer = null;
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Throwable {
|
||||
|
||||
try {
|
||||
super.runTest();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUnwrapper.unwrap(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void primitiveBindingTest(Class primitiveCls, Class compareCls,
|
||||
Object val, int byteSize) {
|
||||
|
||||
TupleBinding binding = TupleBinding.getPrimitiveBinding(primitiveCls);
|
||||
|
||||
/* Test standard object binding. */
|
||||
|
||||
binding.objectToEntry(val, buffer);
|
||||
assertEquals(byteSize, buffer.getSize());
|
||||
|
||||
Object val2 = binding.entryToObject(buffer);
|
||||
assertSame(compareCls, val2.getClass());
|
||||
assertEquals(val, val2);
|
||||
|
||||
Object valWithWrongCls = (primitiveCls == String.class)
|
||||
? ((Object) new Integer(0)) : ((Object) new String(""));
|
||||
try {
|
||||
binding.objectToEntry(valWithWrongCls, buffer);
|
||||
}
|
||||
catch (ClassCastException expected) {}
|
||||
|
||||
/* Test nested tuple binding. */
|
||||
forMoreCoverageTest(binding, val);
|
||||
}
|
||||
|
||||
private void forMoreCoverageTest(TupleBinding val1,Object val2) {
|
||||
|
||||
TupleOutput output = new TupleOutput();
|
||||
output.writeString("abc");
|
||||
val1.objectToEntry(val2, output);
|
||||
output.writeString("xyz");
|
||||
|
||||
TupleInput input = new TupleInput(output);
|
||||
assertEquals("abc", input.readString());
|
||||
Object val3 = val1.entryToObject(input);
|
||||
assertEquals("xyz", input.readString());
|
||||
|
||||
assertEquals(0, input.available());
|
||||
assertSame(val2.getClass(), val3.getClass());
|
||||
assertEquals(val2, val3);
|
||||
}
|
||||
|
||||
public void testPrimitiveBindings() {
|
||||
|
||||
primitiveBindingTest(String.class, String.class,
|
||||
"abc", 4);
|
||||
|
||||
primitiveBindingTest(Character.class, Character.class,
|
||||
new Character('a'), 2);
|
||||
primitiveBindingTest(Boolean.class, Boolean.class,
|
||||
new Boolean(true), 1);
|
||||
primitiveBindingTest(Byte.class, Byte.class,
|
||||
new Byte((byte) 123), 1);
|
||||
primitiveBindingTest(Short.class, Short.class,
|
||||
new Short((short) 123), 2);
|
||||
primitiveBindingTest(Integer.class, Integer.class,
|
||||
new Integer(123), 4);
|
||||
primitiveBindingTest(Long.class, Long.class,
|
||||
new Long(123), 8);
|
||||
primitiveBindingTest(Float.class, Float.class,
|
||||
new Float(123.123), 4);
|
||||
primitiveBindingTest(Double.class, Double.class,
|
||||
new Double(123.123), 8);
|
||||
|
||||
primitiveBindingTest(Character.TYPE, Character.class,
|
||||
new Character('a'), 2);
|
||||
primitiveBindingTest(Boolean.TYPE, Boolean.class,
|
||||
new Boolean(true), 1);
|
||||
primitiveBindingTest(Byte.TYPE, Byte.class,
|
||||
new Byte((byte) 123), 1);
|
||||
primitiveBindingTest(Short.TYPE, Short.class,
|
||||
new Short((short) 123), 2);
|
||||
primitiveBindingTest(Integer.TYPE, Integer.class,
|
||||
new Integer(123), 4);
|
||||
primitiveBindingTest(Long.TYPE, Long.class,
|
||||
new Long(123), 8);
|
||||
primitiveBindingTest(Float.TYPE, Float.class,
|
||||
new Float(123.123), 4);
|
||||
primitiveBindingTest(Double.TYPE, Double.class,
|
||||
new Double(123.123), 8);
|
||||
|
||||
DatabaseEntry entry = new DatabaseEntry();
|
||||
|
||||
StringBinding.stringToEntry("abc", entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
assertEquals("abc", StringBinding.entryToString(entry));
|
||||
|
||||
new StringBinding().objectToEntry("abc", entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
|
||||
StringBinding.stringToEntry(null, entry);
|
||||
assertEquals(2, entry.getData().length);
|
||||
assertEquals(null, StringBinding.entryToString(entry));
|
||||
|
||||
new StringBinding().objectToEntry(null, entry);
|
||||
assertEquals(2, entry.getData().length);
|
||||
|
||||
CharacterBinding.charToEntry('a', entry);
|
||||
assertEquals(2, entry.getData().length);
|
||||
assertEquals('a', CharacterBinding.entryToChar(entry));
|
||||
|
||||
new CharacterBinding().objectToEntry(new Character('a'), entry);
|
||||
assertEquals(2, entry.getData().length);
|
||||
|
||||
BooleanBinding.booleanToEntry(true, entry);
|
||||
assertEquals(1, entry.getData().length);
|
||||
assertEquals(true, BooleanBinding.entryToBoolean(entry));
|
||||
|
||||
new BooleanBinding().objectToEntry(Boolean.TRUE, entry);
|
||||
assertEquals(1, entry.getData().length);
|
||||
|
||||
ByteBinding.byteToEntry((byte) 123, entry);
|
||||
assertEquals(1, entry.getData().length);
|
||||
assertEquals((byte) 123, ByteBinding.entryToByte(entry));
|
||||
|
||||
ShortBinding.shortToEntry((short) 123, entry);
|
||||
assertEquals(2, entry.getData().length);
|
||||
assertEquals((short) 123, ShortBinding.entryToShort(entry));
|
||||
|
||||
new ByteBinding().objectToEntry(new Byte((byte) 123), entry);
|
||||
assertEquals(1, entry.getData().length);
|
||||
|
||||
IntegerBinding.intToEntry(123, entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
assertEquals(123, IntegerBinding.entryToInt(entry));
|
||||
|
||||
new IntegerBinding().objectToEntry(new Integer(123), entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
|
||||
LongBinding.longToEntry(123, entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
assertEquals(123, LongBinding.entryToLong(entry));
|
||||
|
||||
new LongBinding().objectToEntry(new Long(123), entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
|
||||
FloatBinding.floatToEntry((float) 123.123, entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
assertTrue(((float) 123.123) == FloatBinding.entryToFloat(entry));
|
||||
|
||||
new FloatBinding().objectToEntry(new Float((float) 123.123), entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
|
||||
DoubleBinding.doubleToEntry(123.123, entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
assertTrue(123.123 == DoubleBinding.entryToDouble(entry));
|
||||
|
||||
new DoubleBinding().objectToEntry(new Double(123.123), entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
|
||||
BigIntegerBinding.bigIntegerToEntry
|
||||
(new BigInteger("1234567890123456"), entry);
|
||||
assertEquals(9, entry.getData().length);
|
||||
assertTrue((new BigInteger("1234567890123456")).equals
|
||||
(BigIntegerBinding.entryToBigInteger(entry)));
|
||||
|
||||
new BigIntegerBinding().objectToEntry
|
||||
(new BigInteger("1234567890123456"), entry);
|
||||
assertEquals(9, entry.getData().length);
|
||||
forMoreCoverageTest(new BigIntegerBinding(),
|
||||
new BigInteger("1234567890123456"));
|
||||
|
||||
SortedFloatBinding.floatToEntry((float) 123.123, entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
assertTrue(((float) 123.123) ==
|
||||
SortedFloatBinding.entryToFloat(entry));
|
||||
|
||||
new SortedFloatBinding().objectToEntry
|
||||
(new Float((float) 123.123), entry);
|
||||
assertEquals(4, entry.getData().length);
|
||||
forMoreCoverageTest(new SortedFloatBinding(),
|
||||
new Float((float) 123.123));
|
||||
|
||||
SortedDoubleBinding.doubleToEntry(123.123, entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
assertTrue(123.123 == SortedDoubleBinding.entryToDouble(entry));
|
||||
|
||||
new SortedDoubleBinding().objectToEntry(new Double(123.123), entry);
|
||||
assertEquals(8, entry.getData().length);
|
||||
forMoreCoverageTest(new SortedDoubleBinding(),
|
||||
new Double(123.123));
|
||||
}
|
||||
|
||||
public void testTupleInputBinding() {
|
||||
|
||||
EntryBinding binding = new TupleInputBinding();
|
||||
|
||||
TupleOutput out = new TupleOutput();
|
||||
out.writeString("abc");
|
||||
binding.objectToEntry(new TupleInput(out), buffer);
|
||||
assertEquals(4, buffer.getSize());
|
||||
|
||||
Object result = binding.entryToObject(buffer);
|
||||
assertTrue(result instanceof TupleInput);
|
||||
TupleInput in = (TupleInput) result;
|
||||
assertEquals("abc", in.readString());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
// also tests TupleBinding since TupleMarshalledBinding extends it
|
||||
public void testTupleMarshalledBinding() {
|
||||
|
||||
EntryBinding binding =
|
||||
new TupleMarshalledBinding(MarshalledObject.class);
|
||||
|
||||
MarshalledObject val = new MarshalledObject("abc", "", "", "");
|
||||
binding.objectToEntry(val, buffer);
|
||||
assertEquals(val.expectedDataLength(), buffer.getSize());
|
||||
|
||||
Object result = binding.entryToObject(buffer);
|
||||
assertTrue(result instanceof MarshalledObject);
|
||||
val = (MarshalledObject) result;
|
||||
assertEquals("abc", val.getData());
|
||||
}
|
||||
|
||||
// also tests TupleTupleBinding since TupleTupleMarshalledBinding extends
|
||||
// it
|
||||
public void testTupleTupleMarshalledBinding() {
|
||||
|
||||
EntityBinding binding =
|
||||
new TupleTupleMarshalledBinding(MarshalledObject.class);
|
||||
|
||||
MarshalledObject val = new MarshalledObject("abc", "primary",
|
||||
"index1", "index2");
|
||||
binding.objectToData(val, buffer);
|
||||
assertEquals(val.expectedDataLength(), buffer.getSize());
|
||||
binding.objectToKey(val, keyBuffer);
|
||||
assertEquals(val.expectedKeyLength(), keyBuffer.getSize());
|
||||
|
||||
Object result = binding.entryToObject(keyBuffer, buffer);
|
||||
assertTrue(result instanceof MarshalledObject);
|
||||
val = (MarshalledObject) result;
|
||||
assertEquals("abc", val.getData());
|
||||
assertEquals("primary", val.getPrimaryKey());
|
||||
assertEquals("index1", val.getIndexKey1());
|
||||
assertEquals("index2", val.getIndexKey2());
|
||||
}
|
||||
|
||||
public void testBufferSize() {
|
||||
|
||||
CaptureSizeBinding binding = new CaptureSizeBinding();
|
||||
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertEquals(FastOutputStream.DEFAULT_INIT_SIZE, binding.bufSize);
|
||||
|
||||
binding.setTupleBufferSize(1000);
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertEquals(1000, binding.bufSize);
|
||||
}
|
||||
|
||||
private class CaptureSizeBinding extends TupleBinding {
|
||||
|
||||
int bufSize;
|
||||
|
||||
CaptureSizeBinding() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TupleOutput getTupleOutput(Object object) {
|
||||
TupleOutput out = super.getTupleOutput(object);
|
||||
bufSize = out.getBufferBytes().length;
|
||||
return out;
|
||||
}
|
||||
|
||||
public Object entryToObject(TupleInput input) {
|
||||
return input.readString();
|
||||
}
|
||||
|
||||
public void objectToEntry(Object object, TupleOutput output) {
|
||||
assertEquals(bufSize, output.getBufferBytes().length);
|
||||
output.writeString((String) object);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBufferOverride() {
|
||||
|
||||
TupleOutput out = new TupleOutput(new byte[10]);
|
||||
CachedOutputBinding binding = new CachedOutputBinding(out);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("aaaaaaaaaaaaaaaaaaaaaa", buffer);
|
||||
assertEquals("aaaaaaaaaaaaaaaaaaaaaa", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
|
||||
binding.used = false;
|
||||
binding.objectToEntry("x", buffer);
|
||||
assertEquals("x", binding.entryToObject(buffer));
|
||||
assertTrue(binding.used);
|
||||
}
|
||||
|
||||
private class CachedOutputBinding extends TupleBinding {
|
||||
|
||||
TupleOutput out;
|
||||
boolean used;
|
||||
|
||||
CachedOutputBinding(TupleOutput out) {
|
||||
super();
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public TupleOutput getTupleOutput(Object object) {
|
||||
out.reset();
|
||||
used = true;
|
||||
return out;
|
||||
}
|
||||
|
||||
public Object entryToObject(TupleInput input) {
|
||||
return input.readString();
|
||||
}
|
||||
|
||||
public void objectToEntry(Object object, TupleOutput output) {
|
||||
assertSame(out, output);
|
||||
output.writeString((String) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,929 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TupleFormatTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.tuple.test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.tuple.TupleBinding;
|
||||
import com.sleepycat.bind.tuple.TupleInput;
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TupleFormatTest extends TestCase {
|
||||
|
||||
private TupleInput in;
|
||||
private TupleOutput out;
|
||||
private DatabaseEntry buffer;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(TupleFormatTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public TupleFormatTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("TupleFormatTest." + getName());
|
||||
buffer = new DatabaseEntry();
|
||||
out = new TupleOutput();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
/* Ensure that GC can cleanup. */
|
||||
in = null;
|
||||
out = null;
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
private void copyOutputToInput() {
|
||||
|
||||
TupleBinding.outputToEntry(out, buffer);
|
||||
assertEquals(out.size(), buffer.getSize());
|
||||
in = TupleBinding.entryToInput(buffer);
|
||||
assertEquals(in.available(), buffer.getSize());
|
||||
assertEquals(in.getBufferLength(), buffer.getSize());
|
||||
}
|
||||
|
||||
private void stringTest(String val) {
|
||||
|
||||
out.reset();
|
||||
out.writeString(val);
|
||||
assertEquals(val.length() + 1, out.size()); // assume 1-byte chars
|
||||
copyOutputToInput();
|
||||
assertEquals(val, in.readString());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
public void testString() {
|
||||
|
||||
stringTest("");
|
||||
stringTest("a");
|
||||
stringTest("abc");
|
||||
|
||||
out.reset();
|
||||
out.writeString("abc");
|
||||
out.writeString("defg");
|
||||
assertEquals(9, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readString());
|
||||
assertEquals("defg", in.readString());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeString("abc");
|
||||
out.writeString("defg");
|
||||
out.writeString("hijkl");
|
||||
assertEquals(15, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readString());
|
||||
assertEquals("defg", in.readString());
|
||||
assertEquals("hijkl", in.readString());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void fixedStringTest(char[] val) {
|
||||
|
||||
out.reset();
|
||||
out.writeString(val);
|
||||
assertEquals(val.length, out.size()); // assume 1 byte chars
|
||||
copyOutputToInput();
|
||||
char[] val2 = new char[val.length];
|
||||
in.readString(val2);
|
||||
assertTrue(Arrays.equals(val, val2));
|
||||
assertEquals(0, in.available());
|
||||
in.reset();
|
||||
String val3 = in.readString(val.length);
|
||||
assertTrue(Arrays.equals(val, val3.toCharArray()));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
public void testFixedString() {
|
||||
|
||||
fixedStringTest(new char[0]);
|
||||
fixedStringTest(new char[] {'a'});
|
||||
fixedStringTest(new char[] {'a', 'b', 'c'});
|
||||
|
||||
out.reset();
|
||||
out.writeString(new char[] {'a', 'b', 'c'});
|
||||
out.writeString(new char[] {'d', 'e', 'f', 'g'});
|
||||
assertEquals(7, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readString(3));
|
||||
assertEquals("defg", in.readString(4));
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeString(new char[] {'a', 'b', 'c'});
|
||||
out.writeString(new char[] {'d', 'e', 'f', 'g'});
|
||||
out.writeString(new char[] {'h', 'i', 'j', 'k', 'l'});
|
||||
assertEquals(12, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readString(3));
|
||||
assertEquals("defg", in.readString(4));
|
||||
assertEquals("hijkl", in.readString(5));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
public void testNullString() {
|
||||
|
||||
out.reset();
|
||||
out.writeString((String) null);
|
||||
assertEquals(2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(null, in.readString());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeString((String) null);
|
||||
out.writeString("x");
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(null, in.readString());
|
||||
assertEquals(2, in.available());
|
||||
assertEquals("x", in.readString());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeString("x");
|
||||
out.writeString((String) null);
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("x", in.readString());
|
||||
assertEquals(2, in.available());
|
||||
assertEquals(null, in.readString());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeString((String) null);
|
||||
out.writeInt(123);
|
||||
assertEquals(6, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(null, in.readString());
|
||||
assertEquals(4, in.available());
|
||||
assertEquals(123, in.readInt());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeInt(123);
|
||||
out.writeString((String) null);
|
||||
assertEquals(6, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(123, in.readInt());
|
||||
assertEquals(2, in.available());
|
||||
assertEquals(null, in.readString());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void charsTest(char[] val) {
|
||||
|
||||
for (int mode = 0; mode < 2; mode += 1) {
|
||||
out.reset();
|
||||
switch (mode) {
|
||||
case 0: out.writeChars(val); break;
|
||||
case 1: out.writeChars(new String(val)); break;
|
||||
default: throw new IllegalStateException();
|
||||
}
|
||||
assertEquals(val.length * 2, out.size());
|
||||
copyOutputToInput();
|
||||
char[] val2 = new char[val.length];
|
||||
in.readChars(val2);
|
||||
assertTrue(Arrays.equals(val, val2));
|
||||
assertEquals(0, in.available());
|
||||
in.reset();
|
||||
String val3 = in.readChars(val.length);
|
||||
assertTrue(Arrays.equals(val, val3.toCharArray()));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
}
|
||||
|
||||
public void testChars() {
|
||||
|
||||
charsTest(new char[0]);
|
||||
charsTest(new char[] {'a'});
|
||||
charsTest(new char[] {'a', 'b', 'c'});
|
||||
|
||||
out.reset();
|
||||
out.writeChars("abc");
|
||||
out.writeChars("defg");
|
||||
assertEquals(7 * 2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readChars(3));
|
||||
assertEquals("defg", in.readChars(4));
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeChars("abc");
|
||||
out.writeChars("defg");
|
||||
out.writeChars("hijkl");
|
||||
assertEquals(12 * 2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readChars(3));
|
||||
assertEquals("defg", in.readChars(4));
|
||||
assertEquals("hijkl", in.readChars(5));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void bytesTest(char[] val) {
|
||||
|
||||
char[] valBytes = new char[val.length];
|
||||
for (int i = 0; i < val.length; i += 1)
|
||||
valBytes[i] = (char) (val[i] & 0xFF);
|
||||
|
||||
for (int mode = 0; mode < 2; mode += 1) {
|
||||
out.reset();
|
||||
switch (mode) {
|
||||
case 0: out.writeBytes(val); break;
|
||||
case 1: out.writeBytes(new String(val)); break;
|
||||
default: throw new IllegalStateException();
|
||||
}
|
||||
assertEquals(val.length, out.size());
|
||||
copyOutputToInput();
|
||||
char[] val2 = new char[val.length];
|
||||
in.readBytes(val2);
|
||||
assertTrue(Arrays.equals(valBytes, val2));
|
||||
assertEquals(0, in.available());
|
||||
in.reset();
|
||||
String val3 = in.readBytes(val.length);
|
||||
assertTrue(Arrays.equals(valBytes, val3.toCharArray()));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
}
|
||||
|
||||
public void testBytes() {
|
||||
|
||||
bytesTest(new char[0]);
|
||||
bytesTest(new char[] {'a'});
|
||||
bytesTest(new char[] {'a', 'b', 'c'});
|
||||
bytesTest(new char[] {0x7F00, 0x7FFF, 0xFF00, 0xFFFF});
|
||||
|
||||
out.reset();
|
||||
out.writeBytes("abc");
|
||||
out.writeBytes("defg");
|
||||
assertEquals(7, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readBytes(3));
|
||||
assertEquals("defg", in.readBytes(4));
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeBytes("abc");
|
||||
out.writeBytes("defg");
|
||||
out.writeBytes("hijkl");
|
||||
assertEquals(12, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals("abc", in.readBytes(3));
|
||||
assertEquals("defg", in.readBytes(4));
|
||||
assertEquals("hijkl", in.readBytes(5));
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void booleanTest(boolean val) {
|
||||
|
||||
out.reset();
|
||||
out.writeBoolean(val);
|
||||
assertEquals(1, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(val, in.readBoolean());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
public void testBoolean() {
|
||||
|
||||
booleanTest(true);
|
||||
booleanTest(false);
|
||||
|
||||
out.reset();
|
||||
out.writeBoolean(true);
|
||||
out.writeBoolean(false);
|
||||
assertEquals(2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(true, in.readBoolean());
|
||||
assertEquals(false, in.readBoolean());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
out.reset();
|
||||
out.writeBoolean(true);
|
||||
out.writeBoolean(false);
|
||||
out.writeBoolean(true);
|
||||
assertEquals(3, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(true, in.readBoolean());
|
||||
assertEquals(false, in.readBoolean());
|
||||
assertEquals(true, in.readBoolean());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void unsignedByteTest(int val) {
|
||||
|
||||
unsignedByteTest(val, val);
|
||||
}
|
||||
|
||||
private void unsignedByteTest(int val, int expected) {
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedByte(val);
|
||||
assertEquals(1, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(expected, in.readUnsignedByte());
|
||||
}
|
||||
|
||||
public void testUnsignedByte() {
|
||||
|
||||
unsignedByteTest(0);
|
||||
unsignedByteTest(1);
|
||||
unsignedByteTest(254);
|
||||
unsignedByteTest(255);
|
||||
unsignedByteTest(256, 0);
|
||||
unsignedByteTest(-1, 255);
|
||||
unsignedByteTest(-2, 254);
|
||||
unsignedByteTest(-255, 1);
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedByte(0);
|
||||
out.writeUnsignedByte(1);
|
||||
out.writeUnsignedByte(255);
|
||||
assertEquals(3, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readUnsignedByte());
|
||||
assertEquals(1, in.readUnsignedByte());
|
||||
assertEquals(255, in.readUnsignedByte());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void unsignedShortTest(int val) {
|
||||
|
||||
unsignedShortTest(val, val);
|
||||
}
|
||||
|
||||
private void unsignedShortTest(int val, int expected) {
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedShort(val);
|
||||
assertEquals(2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(expected, in.readUnsignedShort());
|
||||
}
|
||||
|
||||
public void testUnsignedShort() {
|
||||
|
||||
unsignedShortTest(0);
|
||||
unsignedShortTest(1);
|
||||
unsignedShortTest(255);
|
||||
unsignedShortTest(256);
|
||||
unsignedShortTest(257);
|
||||
unsignedShortTest(Short.MAX_VALUE - 1);
|
||||
unsignedShortTest(Short.MAX_VALUE);
|
||||
unsignedShortTest(Short.MAX_VALUE + 1);
|
||||
unsignedShortTest(0xFFFF - 1);
|
||||
unsignedShortTest(0xFFFF);
|
||||
unsignedShortTest(0xFFFF + 1, 0);
|
||||
unsignedShortTest(0x7FFF0000, 0);
|
||||
unsignedShortTest(0xFFFF0000, 0);
|
||||
unsignedShortTest(-1, 0xFFFF);
|
||||
unsignedShortTest(-2, 0xFFFF - 1);
|
||||
unsignedShortTest(-0xFFFF, 1);
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedShort(0);
|
||||
out.writeUnsignedShort(1);
|
||||
out.writeUnsignedShort(0xFFFF);
|
||||
assertEquals(6, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readUnsignedShort());
|
||||
assertEquals(1, in.readUnsignedShort());
|
||||
assertEquals(0xFFFF, in.readUnsignedShort());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void unsignedIntTest(long val) {
|
||||
|
||||
unsignedIntTest(val, val);
|
||||
}
|
||||
|
||||
private void unsignedIntTest(long val, long expected) {
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedInt(val);
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(expected, in.readUnsignedInt());
|
||||
}
|
||||
|
||||
public void testUnsignedInt() {
|
||||
|
||||
unsignedIntTest(0L);
|
||||
unsignedIntTest(1L);
|
||||
unsignedIntTest(255L);
|
||||
unsignedIntTest(256L);
|
||||
unsignedIntTest(257L);
|
||||
unsignedIntTest(Short.MAX_VALUE - 1L);
|
||||
unsignedIntTest(Short.MAX_VALUE);
|
||||
unsignedIntTest(Short.MAX_VALUE + 1L);
|
||||
unsignedIntTest(Integer.MAX_VALUE - 1L);
|
||||
unsignedIntTest(Integer.MAX_VALUE);
|
||||
unsignedIntTest(Integer.MAX_VALUE + 1L);
|
||||
unsignedIntTest(0xFFFFFFFFL - 1L);
|
||||
unsignedIntTest(0xFFFFFFFFL);
|
||||
unsignedIntTest(0xFFFFFFFFL + 1L, 0L);
|
||||
unsignedIntTest(0x7FFFFFFF00000000L, 0L);
|
||||
unsignedIntTest(0xFFFFFFFF00000000L, 0L);
|
||||
unsignedIntTest(-1, 0xFFFFFFFFL);
|
||||
unsignedIntTest(-2, 0xFFFFFFFFL - 1L);
|
||||
unsignedIntTest(-0xFFFFFFFFL, 1L);
|
||||
|
||||
out.reset();
|
||||
out.writeUnsignedInt(0L);
|
||||
out.writeUnsignedInt(1L);
|
||||
out.writeUnsignedInt(0xFFFFFFFFL);
|
||||
assertEquals(12, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0L, in.readUnsignedInt());
|
||||
assertEquals(1L, in.readUnsignedInt());
|
||||
assertEquals(0xFFFFFFFFL, in.readUnsignedInt());
|
||||
assertEquals(0L, in.available());
|
||||
}
|
||||
|
||||
private void byteTest(int val) {
|
||||
|
||||
out.reset();
|
||||
out.writeByte(val);
|
||||
assertEquals(1, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals((byte) val, in.readByte());
|
||||
}
|
||||
|
||||
public void testByte() {
|
||||
|
||||
byteTest(0);
|
||||
byteTest(1);
|
||||
byteTest(-1);
|
||||
byteTest(Byte.MAX_VALUE - 1);
|
||||
byteTest(Byte.MAX_VALUE);
|
||||
byteTest(Byte.MAX_VALUE + 1);
|
||||
byteTest(Byte.MIN_VALUE + 1);
|
||||
byteTest(Byte.MIN_VALUE);
|
||||
byteTest(Byte.MIN_VALUE - 1);
|
||||
byteTest(0x7F);
|
||||
byteTest(0xFF);
|
||||
byteTest(0x7FFF);
|
||||
byteTest(0xFFFF);
|
||||
byteTest(0x7FFFFFFF);
|
||||
byteTest(0xFFFFFFFF);
|
||||
|
||||
out.reset();
|
||||
out.writeByte(0);
|
||||
out.writeByte(1);
|
||||
out.writeByte(-1);
|
||||
assertEquals(3, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readByte());
|
||||
assertEquals(1, in.readByte());
|
||||
assertEquals(-1, in.readByte());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void shortTest(int val) {
|
||||
|
||||
out.reset();
|
||||
out.writeShort(val);
|
||||
assertEquals(2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals((short) val, in.readShort());
|
||||
}
|
||||
|
||||
public void testShort() {
|
||||
|
||||
shortTest(0);
|
||||
shortTest(1);
|
||||
shortTest(-1);
|
||||
shortTest(Short.MAX_VALUE - 1);
|
||||
shortTest(Short.MAX_VALUE);
|
||||
shortTest(Short.MAX_VALUE + 1);
|
||||
shortTest(Short.MIN_VALUE + 1);
|
||||
shortTest(Short.MIN_VALUE);
|
||||
shortTest(Short.MIN_VALUE - 1);
|
||||
shortTest(0x7F);
|
||||
shortTest(0xFF);
|
||||
shortTest(0x7FFF);
|
||||
shortTest(0xFFFF);
|
||||
shortTest(0x7FFFFFFF);
|
||||
shortTest(0xFFFFFFFF);
|
||||
|
||||
out.reset();
|
||||
out.writeShort(0);
|
||||
out.writeShort(1);
|
||||
out.writeShort(-1);
|
||||
assertEquals(3 * 2, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readShort());
|
||||
assertEquals(1, in.readShort());
|
||||
assertEquals(-1, in.readShort());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void intTest(int val) {
|
||||
|
||||
out.reset();
|
||||
out.writeInt(val);
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals((int) val, in.readInt());
|
||||
}
|
||||
|
||||
public void testInt() {
|
||||
|
||||
intTest(0);
|
||||
intTest(1);
|
||||
intTest(-1);
|
||||
intTest(Integer.MAX_VALUE - 1);
|
||||
intTest(Integer.MAX_VALUE);
|
||||
intTest(Integer.MAX_VALUE + 1);
|
||||
intTest(Integer.MIN_VALUE + 1);
|
||||
intTest(Integer.MIN_VALUE);
|
||||
intTest(Integer.MIN_VALUE - 1);
|
||||
intTest(0x7F);
|
||||
intTest(0xFF);
|
||||
intTest(0x7FFF);
|
||||
intTest(0xFFFF);
|
||||
intTest(0x7FFFFFFF);
|
||||
intTest(0xFFFFFFFF);
|
||||
|
||||
out.reset();
|
||||
out.writeInt(0);
|
||||
out.writeInt(1);
|
||||
out.writeInt(-1);
|
||||
assertEquals(3 * 4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readInt());
|
||||
assertEquals(1, in.readInt());
|
||||
assertEquals(-1, in.readInt());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void longTest(long val) {
|
||||
|
||||
out.reset();
|
||||
out.writeLong(val);
|
||||
assertEquals(8, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals((long) val, in.readLong());
|
||||
}
|
||||
|
||||
public void testLong() {
|
||||
|
||||
longTest(0);
|
||||
longTest(1);
|
||||
longTest(-1);
|
||||
longTest(Long.MAX_VALUE - 1);
|
||||
longTest(Long.MAX_VALUE);
|
||||
longTest(Long.MAX_VALUE + 1);
|
||||
longTest(Long.MIN_VALUE + 1);
|
||||
longTest(Long.MIN_VALUE);
|
||||
longTest(Long.MIN_VALUE - 1);
|
||||
longTest(0x7F);
|
||||
longTest(0xFF);
|
||||
longTest(0x7FFF);
|
||||
longTest(0xFFFF);
|
||||
longTest(0x7FFFFFFF);
|
||||
longTest(0xFFFFFFFF);
|
||||
longTest(0x7FFFFFFFFFFFFFFFL);
|
||||
longTest(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
out.reset();
|
||||
out.writeLong(0);
|
||||
out.writeLong(1);
|
||||
out.writeLong(-1);
|
||||
assertEquals(3 * 8, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readLong());
|
||||
assertEquals(1, in.readLong());
|
||||
assertEquals(-1, in.readLong());
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
|
||||
private void floatTest(double val) {
|
||||
|
||||
out.reset();
|
||||
out.writeFloat((float) val);
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
if (Double.isNaN(val)) {
|
||||
assertTrue(Float.isNaN(in.readFloat()));
|
||||
} else {
|
||||
assertEquals((float) val, in.readFloat(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFloat() {
|
||||
|
||||
floatTest(0);
|
||||
floatTest(1);
|
||||
floatTest(-1);
|
||||
floatTest(1.0);
|
||||
floatTest(0.1);
|
||||
floatTest(-1.0);
|
||||
floatTest(-0.1);
|
||||
floatTest(Float.NaN);
|
||||
floatTest(Float.NEGATIVE_INFINITY);
|
||||
floatTest(Float.POSITIVE_INFINITY);
|
||||
floatTest(Short.MAX_VALUE);
|
||||
floatTest(Short.MIN_VALUE);
|
||||
floatTest(Integer.MAX_VALUE);
|
||||
floatTest(Integer.MIN_VALUE);
|
||||
floatTest(Long.MAX_VALUE);
|
||||
floatTest(Long.MIN_VALUE);
|
||||
floatTest(Float.MAX_VALUE);
|
||||
floatTest(Float.MAX_VALUE + 1);
|
||||
floatTest(Float.MIN_VALUE + 1);
|
||||
floatTest(Float.MIN_VALUE);
|
||||
floatTest(Float.MIN_VALUE - 1);
|
||||
floatTest(0x7F);
|
||||
floatTest(0xFF);
|
||||
floatTest(0x7FFF);
|
||||
floatTest(0xFFFF);
|
||||
floatTest(0x7FFFFFFF);
|
||||
floatTest(0xFFFFFFFF);
|
||||
floatTest(0x7FFFFFFFFFFFFFFFL);
|
||||
floatTest(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
out.reset();
|
||||
out.writeFloat(0);
|
||||
out.writeFloat(1);
|
||||
out.writeFloat(-1);
|
||||
assertEquals(3 * 4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readFloat(), 0);
|
||||
assertEquals(1, in.readFloat(), 0);
|
||||
assertEquals(-1, in.readFloat(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
|
||||
private void doubleTest(double val) {
|
||||
|
||||
out.reset();
|
||||
out.writeDouble((double) val);
|
||||
assertEquals(8, out.size());
|
||||
copyOutputToInput();
|
||||
if (Double.isNaN(val)) {
|
||||
assertTrue(Double.isNaN(in.readDouble()));
|
||||
} else {
|
||||
assertEquals((double) val, in.readDouble(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDouble() {
|
||||
|
||||
doubleTest(0);
|
||||
doubleTest(1);
|
||||
doubleTest(-1);
|
||||
doubleTest(1.0);
|
||||
doubleTest(0.1);
|
||||
doubleTest(-1.0);
|
||||
doubleTest(-0.1);
|
||||
doubleTest(Double.NaN);
|
||||
doubleTest(Double.NEGATIVE_INFINITY);
|
||||
doubleTest(Double.POSITIVE_INFINITY);
|
||||
doubleTest(Short.MAX_VALUE);
|
||||
doubleTest(Short.MIN_VALUE);
|
||||
doubleTest(Integer.MAX_VALUE);
|
||||
doubleTest(Integer.MIN_VALUE);
|
||||
doubleTest(Long.MAX_VALUE);
|
||||
doubleTest(Long.MIN_VALUE);
|
||||
doubleTest(Float.MAX_VALUE);
|
||||
doubleTest(Float.MIN_VALUE);
|
||||
doubleTest(Double.MAX_VALUE - 1);
|
||||
doubleTest(Double.MAX_VALUE);
|
||||
doubleTest(Double.MAX_VALUE + 1);
|
||||
doubleTest(Double.MIN_VALUE + 1);
|
||||
doubleTest(Double.MIN_VALUE);
|
||||
doubleTest(Double.MIN_VALUE - 1);
|
||||
doubleTest(0x7F);
|
||||
doubleTest(0xFF);
|
||||
doubleTest(0x7FFF);
|
||||
doubleTest(0xFFFF);
|
||||
doubleTest(0x7FFFFFFF);
|
||||
doubleTest(0xFFFFFFFF);
|
||||
doubleTest(0x7FFFFFFFFFFFFFFFL);
|
||||
doubleTest(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
out.reset();
|
||||
out.writeDouble(0);
|
||||
out.writeDouble(1);
|
||||
out.writeDouble(-1);
|
||||
assertEquals(3 * 8, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readDouble(), 0);
|
||||
assertEquals(1, in.readDouble(), 0);
|
||||
assertEquals(-1, in.readDouble(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
|
||||
private void sortedFloatTest(double val) {
|
||||
|
||||
out.reset();
|
||||
out.writeSortedFloat((float) val);
|
||||
assertEquals(4, out.size());
|
||||
copyOutputToInput();
|
||||
if (Double.isNaN(val)) {
|
||||
assertTrue(Float.isNaN(in.readSortedFloat()));
|
||||
} else {
|
||||
assertEquals((float) val, in.readSortedFloat(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSortedFloat() {
|
||||
|
||||
sortedFloatTest(0);
|
||||
sortedFloatTest(1);
|
||||
sortedFloatTest(-1);
|
||||
sortedFloatTest(1.0);
|
||||
sortedFloatTest(0.1);
|
||||
sortedFloatTest(-1.0);
|
||||
sortedFloatTest(-0.1);
|
||||
sortedFloatTest(Float.NaN);
|
||||
sortedFloatTest(Float.NEGATIVE_INFINITY);
|
||||
sortedFloatTest(Float.POSITIVE_INFINITY);
|
||||
sortedFloatTest(Short.MAX_VALUE);
|
||||
sortedFloatTest(Short.MIN_VALUE);
|
||||
sortedFloatTest(Integer.MAX_VALUE);
|
||||
sortedFloatTest(Integer.MIN_VALUE);
|
||||
sortedFloatTest(Long.MAX_VALUE);
|
||||
sortedFloatTest(Long.MIN_VALUE);
|
||||
sortedFloatTest(Float.MAX_VALUE);
|
||||
sortedFloatTest(Float.MAX_VALUE + 1);
|
||||
sortedFloatTest(Float.MIN_VALUE + 1);
|
||||
sortedFloatTest(Float.MIN_VALUE);
|
||||
sortedFloatTest(Float.MIN_VALUE - 1);
|
||||
sortedFloatTest(0x7F);
|
||||
sortedFloatTest(0xFF);
|
||||
sortedFloatTest(0x7FFF);
|
||||
sortedFloatTest(0xFFFF);
|
||||
sortedFloatTest(0x7FFFFFFF);
|
||||
sortedFloatTest(0xFFFFFFFF);
|
||||
sortedFloatTest(0x7FFFFFFFFFFFFFFFL);
|
||||
sortedFloatTest(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
out.reset();
|
||||
out.writeSortedFloat(0);
|
||||
out.writeSortedFloat(1);
|
||||
out.writeSortedFloat(-1);
|
||||
assertEquals(3 * 4, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readSortedFloat(), 0);
|
||||
assertEquals(1, in.readSortedFloat(), 0);
|
||||
assertEquals(-1, in.readSortedFloat(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
|
||||
private void sortedDoubleTest(double val) {
|
||||
|
||||
out.reset();
|
||||
out.writeSortedDouble((double) val);
|
||||
assertEquals(8, out.size());
|
||||
copyOutputToInput();
|
||||
if (Double.isNaN(val)) {
|
||||
assertTrue(Double.isNaN(in.readSortedDouble()));
|
||||
} else {
|
||||
assertEquals((double) val, in.readSortedDouble(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSortedDouble() {
|
||||
|
||||
sortedDoubleTest(0);
|
||||
sortedDoubleTest(1);
|
||||
sortedDoubleTest(-1);
|
||||
sortedDoubleTest(1.0);
|
||||
sortedDoubleTest(0.1);
|
||||
sortedDoubleTest(-1.0);
|
||||
sortedDoubleTest(-0.1);
|
||||
sortedDoubleTest(Double.NaN);
|
||||
sortedDoubleTest(Double.NEGATIVE_INFINITY);
|
||||
sortedDoubleTest(Double.POSITIVE_INFINITY);
|
||||
sortedDoubleTest(Short.MAX_VALUE);
|
||||
sortedDoubleTest(Short.MIN_VALUE);
|
||||
sortedDoubleTest(Integer.MAX_VALUE);
|
||||
sortedDoubleTest(Integer.MIN_VALUE);
|
||||
sortedDoubleTest(Long.MAX_VALUE);
|
||||
sortedDoubleTest(Long.MIN_VALUE);
|
||||
sortedDoubleTest(Float.MAX_VALUE);
|
||||
sortedDoubleTest(Float.MIN_VALUE);
|
||||
sortedDoubleTest(Double.MAX_VALUE - 1);
|
||||
sortedDoubleTest(Double.MAX_VALUE);
|
||||
sortedDoubleTest(Double.MAX_VALUE + 1);
|
||||
sortedDoubleTest(Double.MIN_VALUE + 1);
|
||||
sortedDoubleTest(Double.MIN_VALUE);
|
||||
sortedDoubleTest(Double.MIN_VALUE - 1);
|
||||
sortedDoubleTest(0x7F);
|
||||
sortedDoubleTest(0xFF);
|
||||
sortedDoubleTest(0x7FFF);
|
||||
sortedDoubleTest(0xFFFF);
|
||||
sortedDoubleTest(0x7FFFFFFF);
|
||||
sortedDoubleTest(0xFFFFFFFF);
|
||||
sortedDoubleTest(0x7FFFFFFFFFFFFFFFL);
|
||||
sortedDoubleTest(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
out.reset();
|
||||
out.writeSortedDouble(0);
|
||||
out.writeSortedDouble(1);
|
||||
out.writeSortedDouble(-1);
|
||||
assertEquals(3 * 8, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(0, in.readSortedDouble(), 0);
|
||||
assertEquals(1, in.readSortedDouble(), 0);
|
||||
assertEquals(-1, in.readSortedDouble(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
|
||||
private void packedIntTest(int val, int size) {
|
||||
|
||||
out.reset();
|
||||
out.writePackedInt(val);
|
||||
assertEquals(size, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(size, in.getPackedIntByteLength());
|
||||
assertEquals(val, in.readPackedInt());
|
||||
}
|
||||
|
||||
public void testPackedInt() {
|
||||
|
||||
/* Exhaustive value testing is in PackedIntTest. */
|
||||
packedIntTest(119, 1);
|
||||
packedIntTest(0xFFFF + 119, 3);
|
||||
packedIntTest(Integer.MAX_VALUE, 5);
|
||||
|
||||
out.reset();
|
||||
out.writePackedInt(119);
|
||||
out.writePackedInt(0xFFFF + 119);
|
||||
out.writePackedInt(Integer.MAX_VALUE);
|
||||
assertEquals(1 + 3 + 5, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(119, in.readPackedInt(), 0);
|
||||
assertEquals(0xFFFF + 119, in.readPackedInt(), 0);
|
||||
assertEquals(Integer.MAX_VALUE, in.readPackedInt(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
|
||||
private void packedLongTest(long val, int size) {
|
||||
|
||||
out.reset();
|
||||
out.writePackedLong(val);
|
||||
assertEquals(size, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(size, in.getPackedLongByteLength());
|
||||
assertEquals(val, in.readPackedLong());
|
||||
}
|
||||
|
||||
public void testPackedLong() {
|
||||
|
||||
/* Exhaustive value testing is in PackedIntTest. */
|
||||
packedLongTest(119, 1);
|
||||
packedLongTest(0xFFFFFFFFL + 119, 5);
|
||||
packedLongTest(Long.MAX_VALUE, 9);
|
||||
|
||||
out.reset();
|
||||
out.writePackedLong(119);
|
||||
out.writePackedLong(0xFFFFFFFFL + 119);
|
||||
out.writePackedLong(Long.MAX_VALUE);
|
||||
assertEquals(1 + 5 + 9, out.size());
|
||||
copyOutputToInput();
|
||||
assertEquals(119, in.readPackedLong(), 0);
|
||||
assertEquals(0xFFFFFFFFL + 119, in.readPackedLong(), 0);
|
||||
assertEquals(Long.MAX_VALUE, in.readPackedLong(), 0);
|
||||
assertEquals(0, in.available(), 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TupleOrderingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.bind.tuple.test;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.tuple.TupleOutput;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TupleOrderingTest extends TestCase {
|
||||
|
||||
private TupleOutput out;
|
||||
private byte[] prevBuf;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(TupleOrderingTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public TupleOrderingTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("TupleOrderingTest." + getName());
|
||||
out = new TupleOutput();
|
||||
prevBuf = null;
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
/* Ensure that GC can cleanup. */
|
||||
out = null;
|
||||
prevBuf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each tuple written must be strictly less than (by comparison of bytes)
|
||||
* the tuple written just before it. The check() method compares bytes
|
||||
* just written to those written before the previous call to check().
|
||||
*/
|
||||
private void check() {
|
||||
|
||||
check(-1);
|
||||
}
|
||||
|
||||
private void check(int dataIndex) {
|
||||
|
||||
byte[] buf = new byte[out.size()];
|
||||
System.arraycopy(out.getBufferBytes(), out.getBufferOffset(),
|
||||
buf, 0, buf.length);
|
||||
if (prevBuf != null) {
|
||||
int errOffset = -1;
|
||||
int len = Math.min(prevBuf.length, buf.length);
|
||||
boolean areEqual = true;
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
int val1 = prevBuf[i] & 0xFF;
|
||||
int val2 = buf[i] & 0xFF;
|
||||
if (val1 < val2) {
|
||||
areEqual = false;
|
||||
break;
|
||||
} else if (val1 > val2) {
|
||||
errOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (areEqual) {
|
||||
if (prevBuf.length < buf.length) {
|
||||
areEqual = false;
|
||||
} else if (prevBuf.length > buf.length) {
|
||||
areEqual = false;
|
||||
errOffset = buf.length + 1;
|
||||
}
|
||||
}
|
||||
if (errOffset != -1 || areEqual) {
|
||||
StringBuffer msg = new StringBuffer();
|
||||
if (errOffset != -1) {
|
||||
msg.append("Left >= right at byte offset " + errOffset);
|
||||
} else if (areEqual) {
|
||||
msg.append("Bytes are equal");
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
msg.append("\nLeft hex bytes: ");
|
||||
for (int i = 0; i < prevBuf.length; i += 1) {
|
||||
msg.append(' ');
|
||||
int val = prevBuf[i] & 0xFF;
|
||||
if ((val & 0xF0) == 0) {
|
||||
msg.append('0');
|
||||
}
|
||||
msg.append(Integer.toHexString(val));
|
||||
}
|
||||
msg.append("\nRight hex bytes:");
|
||||
for (int i = 0; i < buf.length; i += 1) {
|
||||
msg.append(' ');
|
||||
int val = buf[i] & 0xFF;
|
||||
if ((val & 0xF0) == 0) {
|
||||
msg.append('0');
|
||||
}
|
||||
msg.append(Integer.toHexString(val));
|
||||
}
|
||||
if (dataIndex >= 0) {
|
||||
msg.append("\nData index: " + dataIndex);
|
||||
}
|
||||
fail(msg.toString());
|
||||
}
|
||||
}
|
||||
prevBuf = buf;
|
||||
out.reset();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
|
||||
prevBuf = null;
|
||||
out.reset();
|
||||
}
|
||||
|
||||
public void testString() {
|
||||
|
||||
final String[] DATA = {
|
||||
"", "a", "ab", "b", "bb", "bba",
|
||||
new String(new char[] { 0x7F }),
|
||||
new String(new char[] { 0x7F, 0 }),
|
||||
new String(new char[] { 0xFF }),
|
||||
new String(new char[] { Character.MAX_VALUE }),
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeString(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
reset();
|
||||
out.writeString("a");
|
||||
check();
|
||||
out.writeString("a");
|
||||
out.writeString("");
|
||||
check();
|
||||
out.writeString("a");
|
||||
out.writeString("");
|
||||
out.writeString("a");
|
||||
check();
|
||||
out.writeString("a");
|
||||
out.writeString("b");
|
||||
check();
|
||||
out.writeString("aa");
|
||||
check();
|
||||
out.writeString("b");
|
||||
check();
|
||||
}
|
||||
|
||||
public void testFixedString() {
|
||||
|
||||
final char[][] DATA = {
|
||||
{}, {'a'}, {'a', 'b'}, {'b'}, {'b', 'b'}, {0x7F}, {0xFF},
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeString(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testChars() {
|
||||
|
||||
final char[][] DATA = {
|
||||
{}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
|
||||
{0x7F}, {0x7F, 0}, {0xFF}, {0xFF, 0},
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeChars(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBytes() {
|
||||
|
||||
final char[][] DATA = {
|
||||
{}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
|
||||
{0x7F}, {0xFF},
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeBytes(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBoolean() {
|
||||
|
||||
final boolean[] DATA = {
|
||||
false, true
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeBoolean(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnsignedByte() {
|
||||
|
||||
final int[] DATA = {
|
||||
0, 1, 0x7F, 0xFF
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeUnsignedByte(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnsignedShort() {
|
||||
|
||||
final int[] DATA = {
|
||||
0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeUnsignedShort(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnsignedInt() {
|
||||
|
||||
final long[] DATA = {
|
||||
0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF, 0x80000,
|
||||
0x7FFFFFFF, 0x80000000, 0xFFFFFFFF
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeUnsignedInt(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testByte() {
|
||||
|
||||
final byte[] DATA = {
|
||||
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
|
||||
-1, 0, 1,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeByte(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testShort() {
|
||||
|
||||
final short[] DATA = {
|
||||
Short.MIN_VALUE, Short.MIN_VALUE + 1,
|
||||
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
|
||||
-1, 0, 1,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1, Short.MAX_VALUE,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeShort(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInt() {
|
||||
|
||||
final int[] DATA = {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
|
||||
Short.MIN_VALUE, Short.MIN_VALUE + 1,
|
||||
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
|
||||
-1, 0, 1,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1, Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeInt(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testLong() {
|
||||
|
||||
final long[] DATA = {
|
||||
Long.MIN_VALUE, Long.MIN_VALUE + 1,
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
|
||||
Short.MIN_VALUE, Short.MIN_VALUE + 1,
|
||||
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
|
||||
-1, 0, 1,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1, Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
|
||||
Long.MAX_VALUE - 1, Long.MAX_VALUE,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeLong(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFloat() {
|
||||
|
||||
// Only positive floats and doubles are ordered deterministically
|
||||
|
||||
final float[] DATA = {
|
||||
0, Float.MIN_VALUE, 2 * Float.MIN_VALUE,
|
||||
(float) 0.01, (float) 0.02, (float) 0.99,
|
||||
1, (float) 1.01, (float) 1.02, (float) 1.99,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1, Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
Long.MAX_VALUE / 2, Long.MAX_VALUE,
|
||||
Float.MAX_VALUE,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.NaN,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeFloat(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDouble() {
|
||||
|
||||
// Only positive floats and doubles are ordered deterministically
|
||||
|
||||
final double[] DATA = {
|
||||
0, Double.MIN_VALUE, 2 * Double.MIN_VALUE,
|
||||
0.001, 0.002, 0.999,
|
||||
1, 1.001, 1.002, 1.999,
|
||||
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1, Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
|
||||
Long.MAX_VALUE / 2, Long.MAX_VALUE,
|
||||
Float.MAX_VALUE, Double.MAX_VALUE,
|
||||
Double.POSITIVE_INFINITY,
|
||||
Double.NaN,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeDouble(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSortedFloat() {
|
||||
|
||||
final float[] DATA = {
|
||||
Float.NEGATIVE_INFINITY,
|
||||
(- Float.MAX_VALUE),
|
||||
Long.MIN_VALUE,
|
||||
Long.MIN_VALUE / 2,
|
||||
Integer.MIN_VALUE,
|
||||
Short.MIN_VALUE,
|
||||
Short.MIN_VALUE + 1,
|
||||
Byte.MIN_VALUE,
|
||||
Byte.MIN_VALUE + 1,
|
||||
(float) -1.99,
|
||||
(float) -1.02,
|
||||
(float) -1.01,
|
||||
-1,
|
||||
(float) -0.99,
|
||||
(float) -0.02,
|
||||
(float) -0.01,
|
||||
2 * (- Float.MIN_VALUE),
|
||||
(- Float.MIN_VALUE),
|
||||
0,
|
||||
Float.MIN_VALUE,
|
||||
2 * Float.MIN_VALUE,
|
||||
(float) 0.01,
|
||||
(float) 0.02,
|
||||
(float) 0.99,
|
||||
1,
|
||||
(float) 1.01,
|
||||
(float) 1.02,
|
||||
(float) 1.99,
|
||||
Byte.MAX_VALUE - 1,
|
||||
Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1,
|
||||
Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
Long.MAX_VALUE / 2,
|
||||
Long.MAX_VALUE,
|
||||
Float.MAX_VALUE,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.NaN,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeSortedFloat(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSortedDouble() {
|
||||
|
||||
final double[] DATA = {
|
||||
Double.NEGATIVE_INFINITY,
|
||||
(- Double.MAX_VALUE),
|
||||
(- Float.MAX_VALUE),
|
||||
Long.MIN_VALUE,
|
||||
Long.MIN_VALUE / 2,
|
||||
Integer.MIN_VALUE,
|
||||
Short.MIN_VALUE,
|
||||
Short.MIN_VALUE + 1,
|
||||
Byte.MIN_VALUE,
|
||||
Byte.MIN_VALUE + 1,
|
||||
-1.999,
|
||||
-1.002,
|
||||
-1.001,
|
||||
-1,
|
||||
-0.999,
|
||||
-0.002,
|
||||
-0.001,
|
||||
2 * (- Double.MIN_VALUE),
|
||||
(- Double.MIN_VALUE),
|
||||
0,
|
||||
Double.MIN_VALUE,
|
||||
2 * Double.MIN_VALUE,
|
||||
0.001,
|
||||
0.002,
|
||||
0.999,
|
||||
1,
|
||||
1.001,
|
||||
1.002,
|
||||
1.999,
|
||||
Byte.MAX_VALUE - 1,
|
||||
Byte.MAX_VALUE,
|
||||
Short.MAX_VALUE - 1,
|
||||
Short.MAX_VALUE,
|
||||
Integer.MAX_VALUE - 1,
|
||||
Integer.MAX_VALUE,
|
||||
Long.MAX_VALUE / 2,
|
||||
Long.MAX_VALUE,
|
||||
Float.MAX_VALUE,
|
||||
Double.MAX_VALUE,
|
||||
Double.POSITIVE_INFINITY,
|
||||
Double.NaN,
|
||||
};
|
||||
for (int i = 0; i < DATA.length; i += 1) {
|
||||
out.writeSortedDouble(DATA[i]);
|
||||
check(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
443
test/scr024/src/com/sleepycat/collections/KeyRangeTest.java
Normal file
443
test/scr024/src/com/sleepycat/collections/KeyRangeTest.java
Normal file
@@ -0,0 +1,443 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: KeyRangeTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.ByteArrayBinding;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.db.OperationStatus;
|
||||
import com.sleepycat.util.keyrange.KeyRange;
|
||||
import com.sleepycat.util.keyrange.KeyRangeException;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class KeyRangeTest extends TestCase {
|
||||
|
||||
private static boolean VERBOSE = false;
|
||||
|
||||
private static final byte FF = (byte) 0xFF;
|
||||
|
||||
private static final byte[][] KEYS = {
|
||||
/* 0 */ {1},
|
||||
/* 1 */ {FF},
|
||||
/* 2 */ {FF, 0},
|
||||
/* 3 */ {FF, 0x7F},
|
||||
/* 4 */ {FF, FF},
|
||||
/* 5 */ {FF, FF, 0},
|
||||
/* 6 */ {FF, FF, 0x7F},
|
||||
/* 7 */ {FF, FF, FF},
|
||||
};
|
||||
private static byte[][] EXTREME_KEY_BYTES = {
|
||||
/* 0 */ {0},
|
||||
/* 1 */ {FF, FF, FF, FF},
|
||||
};
|
||||
|
||||
private Environment env;
|
||||
private Database store;
|
||||
private DataView view;
|
||||
private DataCursor cursor;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
|
||||
return new TestSuite(KeyRangeTest.class);
|
||||
}
|
||||
|
||||
public KeyRangeTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
|
||||
}
|
||||
|
||||
private void openDb(Comparator comparator)
|
||||
throws Exception {
|
||||
|
||||
File dir = SharedTestUtils.getNewDir();
|
||||
ByteArrayBinding dataBinding = new ByteArrayBinding();
|
||||
EnvironmentConfig envConfig = new EnvironmentConfig();
|
||||
envConfig.setAllowCreate(true);
|
||||
DbCompat.setInitializeCache(envConfig, true);
|
||||
env = new Environment(dir, envConfig);
|
||||
DatabaseConfig dbConfig = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(dbConfig);
|
||||
dbConfig.setAllowCreate(true);
|
||||
if (comparator != null) {
|
||||
DbCompat.setBtreeComparator(dbConfig, comparator);
|
||||
}
|
||||
store = DbCompat.testOpenDatabase
|
||||
(env, null, "test.db", null, dbConfig);
|
||||
view = new DataView(store, dataBinding, dataBinding, null, true, null);
|
||||
}
|
||||
|
||||
private void closeDb()
|
||||
throws Exception {
|
||||
|
||||
store.close();
|
||||
store = null;
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception ignored during close: " + e);
|
||||
}
|
||||
try {
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception ignored during close: " + e);
|
||||
}
|
||||
/* Ensure that GC can cleanup. */
|
||||
env = null;
|
||||
store = null;
|
||||
view = null;
|
||||
cursor = null;
|
||||
}
|
||||
|
||||
public void testScan() throws Exception {
|
||||
openDb(null);
|
||||
doScan(false);
|
||||
closeDb();
|
||||
}
|
||||
|
||||
public void testScanComparator() throws Exception {
|
||||
openDb(new ReverseComparator());
|
||||
doScan(true);
|
||||
closeDb();
|
||||
}
|
||||
|
||||
private void doScan(boolean reversed) throws Exception {
|
||||
|
||||
byte[][] keys = new byte[KEYS.length][];
|
||||
final int end = KEYS.length - 1;
|
||||
cursor = new DataCursor(view, true);
|
||||
for (int i = 0; i <= end; i++) {
|
||||
keys[i] = KEYS[i];
|
||||
cursor.put(keys[i], KEYS[i], null, false);
|
||||
}
|
||||
cursor.close();
|
||||
byte[][] extremeKeys = new byte[EXTREME_KEY_BYTES.length][];
|
||||
for (int i = 0; i < extremeKeys.length; i++) {
|
||||
extremeKeys[i] = EXTREME_KEY_BYTES[i];
|
||||
}
|
||||
|
||||
// with empty range
|
||||
|
||||
cursor = new DataCursor(view, false);
|
||||
expectRange(KEYS, 0, end, reversed);
|
||||
cursor.close();
|
||||
|
||||
// begin key only, inclusive
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
cursor = newCursor(view, keys[i], true, null, false, reversed);
|
||||
expectRange(KEYS, i, end, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// begin key only, exclusive
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
cursor = newCursor(view, keys[i], false, null, false, reversed);
|
||||
expectRange(KEYS, i + 1, end, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// end key only, inclusive
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
cursor = newCursor(view, null, false, keys[i], true, reversed);
|
||||
expectRange(KEYS, 0, i, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// end key only, exclusive
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
cursor = newCursor(view, null, false, keys[i], false, reversed);
|
||||
expectRange(KEYS, 0, i - 1, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// begin and end keys, inclusive and exclusive
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
for (int j = i; j <= end; j++) {
|
||||
// begin inclusive, end inclusive
|
||||
|
||||
cursor = newCursor(view, keys[i], true, keys[j],
|
||||
true, reversed);
|
||||
expectRange(KEYS, i, j, reversed);
|
||||
cursor.close();
|
||||
|
||||
// begin inclusive, end exclusive
|
||||
|
||||
cursor = newCursor(view, keys[i], true, keys[j],
|
||||
false, reversed);
|
||||
expectRange(KEYS, i, j - 1, reversed);
|
||||
cursor.close();
|
||||
|
||||
// begin exclusive, end inclusive
|
||||
|
||||
cursor = newCursor(view, keys[i], false, keys[j],
|
||||
true, reversed);
|
||||
expectRange(KEYS, i + 1, j, reversed);
|
||||
cursor.close();
|
||||
|
||||
// begin exclusive, end exclusive
|
||||
|
||||
cursor = newCursor(view, keys[i], false, keys[j],
|
||||
false, reversed);
|
||||
expectRange(KEYS, i + 1, j - 1, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
// single key range
|
||||
|
||||
for (int i = 0; i <= end; i++) {
|
||||
cursor = new DataCursor(view, false, keys[i]);
|
||||
expectRange(KEYS, i, i, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// start with lower extreme (before any existing key)
|
||||
|
||||
cursor = newCursor(view, extremeKeys[0], true, null, false, reversed);
|
||||
expectRange(KEYS, 0, end, reversed);
|
||||
cursor.close();
|
||||
|
||||
// start with higher extreme (after any existing key)
|
||||
|
||||
cursor = newCursor(view, null, false, extremeKeys[1], true, reversed);
|
||||
expectRange(KEYS, 0, end, reversed);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
private DataCursor newCursor(DataView view,
|
||||
Object beginKey, boolean beginInclusive,
|
||||
Object endKey, boolean endInclusive,
|
||||
boolean reversed)
|
||||
throws Exception {
|
||||
|
||||
if (reversed) {
|
||||
return new DataCursor(view, false,
|
||||
endKey, endInclusive,
|
||||
beginKey, beginInclusive);
|
||||
} else {
|
||||
return new DataCursor(view, false,
|
||||
beginKey, beginInclusive,
|
||||
endKey, endInclusive);
|
||||
}
|
||||
}
|
||||
|
||||
private void expectRange(byte[][] bytes, int first, int last,
|
||||
boolean reversed)
|
||||
throws DatabaseException {
|
||||
|
||||
int i;
|
||||
boolean init;
|
||||
for (init = true, i = first;; i++, init = false) {
|
||||
if (checkRange(bytes, first, last, i <= last,
|
||||
reversed, !reversed, init, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (init = true, i = last;; i--, init = false) {
|
||||
if (checkRange(bytes, first, last, i >= first,
|
||||
reversed, reversed, init, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkRange(byte[][] bytes, int first, int last,
|
||||
boolean inRange, boolean reversed,
|
||||
boolean forward, boolean init,
|
||||
int i)
|
||||
throws DatabaseException {
|
||||
|
||||
OperationStatus s;
|
||||
if (forward) {
|
||||
if (init) {
|
||||
s = cursor.getFirst(false);
|
||||
} else {
|
||||
s = cursor.getNext(false);
|
||||
}
|
||||
} else {
|
||||
if (init) {
|
||||
s = cursor.getLast(false);
|
||||
} else {
|
||||
s = cursor.getPrev(false);
|
||||
}
|
||||
}
|
||||
|
||||
String msg = " " + (forward ? "next" : "prev") + " i=" + i +
|
||||
" first=" + first + " last=" + last +
|
||||
(reversed ? " reversed" : " not reversed");
|
||||
|
||||
// check that moving past ends doesn't move the cursor
|
||||
if (s == OperationStatus.SUCCESS && i == first) {
|
||||
OperationStatus s2 = reversed ? cursor.getNext(false)
|
||||
: cursor.getPrev(false);
|
||||
assertEquals(msg, OperationStatus.NOTFOUND, s2);
|
||||
}
|
||||
if (s == OperationStatus.SUCCESS && i == last) {
|
||||
OperationStatus s2 = reversed ? cursor.getPrev(false)
|
||||
: cursor.getNext(false);
|
||||
assertEquals(msg, OperationStatus.NOTFOUND, s2);
|
||||
}
|
||||
|
||||
byte[] val = (s == OperationStatus.SUCCESS)
|
||||
? ((byte[]) cursor.getCurrentValue())
|
||||
: null;
|
||||
|
||||
if (inRange) {
|
||||
assertNotNull("RangeNotFound" + msg, val);
|
||||
|
||||
if (!Arrays.equals(val, bytes[i])){
|
||||
printBytes(val);
|
||||
printBytes(bytes[i]);
|
||||
fail("RangeKeyNotEqual" + msg);
|
||||
}
|
||||
if (VERBOSE) {
|
||||
System.out.println("GotRange" + msg);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
assertEquals("RangeExceeded" + msg, OperationStatus.NOTFOUND, s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void printBytes(byte[] bytes) {
|
||||
|
||||
for (int i = 0; i < bytes.length; i += 1) {
|
||||
System.out.print(Integer.toHexString(bytes[i] & 0xFF));
|
||||
System.out.print(' ');
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public void testSubRanges() {
|
||||
|
||||
DatabaseEntry begin = new DatabaseEntry();
|
||||
DatabaseEntry begin2 = new DatabaseEntry();
|
||||
DatabaseEntry end = new DatabaseEntry();
|
||||
DatabaseEntry end2 = new DatabaseEntry();
|
||||
KeyRange range = new KeyRange(null);
|
||||
KeyRange range2;
|
||||
|
||||
/* Base range [1, 2] */
|
||||
begin.setData(new byte[] { 1 });
|
||||
end.setData(new byte[] { 2 });
|
||||
range = range.subRange(begin, true, end, true);
|
||||
|
||||
/* Subrange (0, 1] is invalid **. */
|
||||
begin2.setData(new byte[] { 0 });
|
||||
end2.setData(new byte[] { 1 });
|
||||
try {
|
||||
range2 = range.subRange(begin2, false, end2, true);
|
||||
fail();
|
||||
} catch (KeyRangeException expected) {}
|
||||
|
||||
/* Subrange [1, 3) is invalid. */
|
||||
begin2.setData(new byte[] { 1 });
|
||||
end2.setData(new byte[] { 3 });
|
||||
try {
|
||||
range2 = range.subRange(begin2, true, end2, false);
|
||||
fail();
|
||||
} catch (KeyRangeException expected) {}
|
||||
|
||||
/* Subrange [2, 2] is valid. */
|
||||
begin2.setData(new byte[] { 2 });
|
||||
end2.setData(new byte[] { 2 });
|
||||
range2 = range.subRange(begin2, true, end2, true);
|
||||
|
||||
/* Subrange [0, 1] is invalid. */
|
||||
begin2.setData(new byte[] { 0 });
|
||||
end2.setData(new byte[] { 1 });
|
||||
try {
|
||||
range2 = range.subRange(begin2, true, end2, true);
|
||||
fail();
|
||||
} catch (KeyRangeException expected) {}
|
||||
|
||||
/* Subrange (0, 3] is invalid. */
|
||||
begin2.setData(new byte[] { 0 });
|
||||
end2.setData(new byte[] { 3 });
|
||||
try {
|
||||
range2 = range.subRange(begin2, false, end2, true);
|
||||
fail();
|
||||
} catch (KeyRangeException expected) {}
|
||||
|
||||
/* Subrange [3, 3) is invalid. */
|
||||
begin2.setData(new byte[] { 3 });
|
||||
end2.setData(new byte[] { 3 });
|
||||
try {
|
||||
range2 = range.subRange(begin2, true, end2, false);
|
||||
fail();
|
||||
} catch (KeyRangeException expected) {}
|
||||
}
|
||||
|
||||
public static class ReverseComparator implements Comparator {
|
||||
public int compare(Object o1, Object o2) {
|
||||
byte[] d1 = (byte[]) o1;
|
||||
byte[] d2 = (byte[]) o2;
|
||||
int cmp = KeyRange.compareBytes(d1, 0, d1.length,
|
||||
d2, 0, d2.length);
|
||||
if (cmp < 0) {
|
||||
return 1;
|
||||
} else if (cmp > 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3013
test/scr024/src/com/sleepycat/collections/test/CollectionTest.java
Normal file
3013
test/scr024/src/com/sleepycat/collections/test/CollectionTest.java
Normal file
File diff suppressed because it is too large
Load Diff
129
test/scr024/src/com/sleepycat/collections/test/DbTestUtil.java
Normal file
129
test/scr024/src/com/sleepycat/collections/test/DbTestUtil.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: DbTestUtil.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class DbTestUtil {
|
||||
|
||||
public static final DatabaseConfig DBCONFIG_CREATE = new DatabaseConfig();
|
||||
static {
|
||||
DBCONFIG_CREATE.setAllowCreate(true);
|
||||
}
|
||||
|
||||
private static final File TEST_DIR;
|
||||
static {
|
||||
String dir = System.getProperty("testdestdir");
|
||||
if (dir == null || dir.length() == 0) {
|
||||
dir = ".";
|
||||
}
|
||||
TEST_DIR = new File(dir, "tmp");
|
||||
}
|
||||
|
||||
public static void printTestName(String name) {
|
||||
// don't want verbose printing for now
|
||||
// System.out.println(name);
|
||||
}
|
||||
|
||||
public static File getExistingDir(String name)
|
||||
throws IOException {
|
||||
|
||||
File dir = new File(TEST_DIR, name);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException(
|
||||
"Not an existing directory: " + dir);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getNewDir()
|
||||
throws IOException {
|
||||
|
||||
return getNewDir("test-dir");
|
||||
}
|
||||
|
||||
public static File getNewDir(String name)
|
||||
throws IOException {
|
||||
|
||||
File dir = new File(TEST_DIR, name);
|
||||
if (dir.isDirectory()) {
|
||||
String[] files = dir.list();
|
||||
if (files != null) {
|
||||
for (int i = 0; i < files.length; i += 1) {
|
||||
new File(dir, files[i]).delete();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dir.delete();
|
||||
dir.mkdirs();
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getNewFile()
|
||||
throws IOException {
|
||||
|
||||
return getNewFile("test-file");
|
||||
}
|
||||
|
||||
public static File getNewFile(String name)
|
||||
throws IOException {
|
||||
|
||||
return getNewFile(TEST_DIR, name);
|
||||
}
|
||||
|
||||
public static File getNewFile(File dir, String name)
|
||||
throws IOException {
|
||||
|
||||
File file = new File(dir, name);
|
||||
file.delete();
|
||||
return file;
|
||||
}
|
||||
|
||||
public static boolean copyResource(Class cls, String fileName, File toDir)
|
||||
throws IOException {
|
||||
|
||||
InputStream in = cls.getResourceAsStream("testdata/" + fileName);
|
||||
if (in == null) {
|
||||
return false;
|
||||
}
|
||||
in = new BufferedInputStream(in);
|
||||
File file = new File(toDir, fileName);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
out = new BufferedOutputStream(out);
|
||||
int c;
|
||||
while ((c = in.read()) >= 0) out.write(c);
|
||||
in.close();
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String qualifiedTestName(TestCase test) {
|
||||
|
||||
String s = test.getClass().getName();
|
||||
int i = s.lastIndexOf('.');
|
||||
if (i >= 0) {
|
||||
s = s.substring(i + 1);
|
||||
}
|
||||
return s + '.' + test.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ForeignKeyTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.bind.serial.TupleSerialMarshalledKeyCreator;
|
||||
import com.sleepycat.bind.serial.test.MarshalledObject;
|
||||
import com.sleepycat.collections.CurrentTransaction;
|
||||
import com.sleepycat.collections.TupleSerialFactory;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.ForeignKeyDeleteAction;
|
||||
import com.sleepycat.db.SecondaryConfig;
|
||||
import com.sleepycat.db.SecondaryDatabase;
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
import com.sleepycat.util.RuntimeExceptionWrapper;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class ForeignKeyTest extends TestCase {
|
||||
|
||||
private static final ForeignKeyDeleteAction[] ACTIONS = {
|
||||
ForeignKeyDeleteAction.ABORT,
|
||||
ForeignKeyDeleteAction.NULLIFY,
|
||||
ForeignKeyDeleteAction.CASCADE,
|
||||
};
|
||||
private static final String[] ACTION_LABELS = {
|
||||
"ABORT",
|
||||
"NULLIFY",
|
||||
"CASCADE",
|
||||
};
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
|
||||
for (int j = 0; j < ACTIONS.length; j += 1) {
|
||||
suite.addTest(new ForeignKeyTest(TestEnv.ALL[i],
|
||||
ACTIONS[j],
|
||||
ACTION_LABELS[j]));
|
||||
}
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private TestEnv testEnv;
|
||||
private Environment env;
|
||||
private StoredClassCatalog catalog;
|
||||
private TupleSerialFactory factory;
|
||||
private Database store1;
|
||||
private Database store2;
|
||||
private SecondaryDatabase index1;
|
||||
private SecondaryDatabase index2;
|
||||
private Map storeMap1;
|
||||
private Map storeMap2;
|
||||
private Map indexMap1;
|
||||
private Map indexMap2;
|
||||
private ForeignKeyDeleteAction onDelete;
|
||||
|
||||
public ForeignKeyTest(TestEnv testEnv, ForeignKeyDeleteAction onDelete,
|
||||
String onDeleteLabel) {
|
||||
|
||||
super("ForeignKeyTest-" + testEnv.getName() + '-' + onDeleteLabel);
|
||||
|
||||
this.testEnv = testEnv;
|
||||
this.onDelete = onDelete;
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = testEnv.open(getName());
|
||||
|
||||
createDatabase();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (index1 != null) {
|
||||
index1.close();
|
||||
}
|
||||
if (index2 != null) {
|
||||
index2.close();
|
||||
}
|
||||
if (store1 != null) {
|
||||
store1.close();
|
||||
}
|
||||
if (store2 != null) {
|
||||
store2.close();
|
||||
}
|
||||
if (catalog != null) {
|
||||
catalog.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
env = null;
|
||||
testEnv = null;
|
||||
catalog = null;
|
||||
store1 = null;
|
||||
store2 = null;
|
||||
index1 = null;
|
||||
index2 = null;
|
||||
factory = null;
|
||||
storeMap1 = null;
|
||||
storeMap2 = null;
|
||||
indexMap1 = null;
|
||||
indexMap2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
createViews();
|
||||
writeAndRead();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUnwrapper.unwrap(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createDatabase()
|
||||
throws Exception {
|
||||
|
||||
catalog = new StoredClassCatalog(openDb("catalog.db"));
|
||||
factory = new TupleSerialFactory(catalog);
|
||||
assertSame(catalog, factory.getCatalog());
|
||||
|
||||
store1 = openDb("store1.db");
|
||||
store2 = openDb("store2.db");
|
||||
index1 = openSecondaryDb(factory, "1", store1, "index1.db", null);
|
||||
index2 = openSecondaryDb(factory, "2", store2, "index2.db", store1);
|
||||
}
|
||||
|
||||
private Database openDb(String file)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
config.setTransactional(testEnv.isTxnMode());
|
||||
config.setAllowCreate(true);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
private SecondaryDatabase openSecondaryDb(TupleSerialFactory factory,
|
||||
String keyName,
|
||||
Database primary,
|
||||
String file,
|
||||
Database foreignStore)
|
||||
throws Exception {
|
||||
|
||||
TupleSerialMarshalledKeyCreator keyCreator =
|
||||
factory.getKeyCreator(MarshalledObject.class, keyName);
|
||||
|
||||
SecondaryConfig secConfig = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(secConfig);
|
||||
secConfig.setTransactional(testEnv.isTxnMode());
|
||||
secConfig.setAllowCreate(true);
|
||||
secConfig.setKeyCreator(keyCreator);
|
||||
if (foreignStore != null) {
|
||||
secConfig.setForeignKeyDatabase(foreignStore);
|
||||
secConfig.setForeignKeyDeleteAction(onDelete);
|
||||
if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
|
||||
secConfig.setForeignKeyNullifier(keyCreator);
|
||||
}
|
||||
}
|
||||
|
||||
return DbCompat.testOpenSecondaryDatabase
|
||||
(env, null, file, null, primary, secConfig);
|
||||
}
|
||||
|
||||
private void createViews()
|
||||
throws Exception {
|
||||
|
||||
storeMap1 = factory.newMap(store1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
storeMap2 = factory.newMap(store2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap1 = factory.newMap(index1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap2 = factory.newMap(index2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
}
|
||||
|
||||
private void writeAndRead()
|
||||
throws Exception {
|
||||
|
||||
CurrentTransaction txn = CurrentTransaction.getInstance(env);
|
||||
if (txn != null) {
|
||||
txn.beginTransaction(null);
|
||||
}
|
||||
|
||||
MarshalledObject o1 = new MarshalledObject("data1", "pk1", "ik1", "");
|
||||
assertNull(storeMap1.put(null, o1));
|
||||
|
||||
assertEquals(o1, storeMap1.get("pk1"));
|
||||
assertEquals(o1, indexMap1.get("ik1"));
|
||||
|
||||
MarshalledObject o2 = new MarshalledObject("data2", "pk2", "", "pk1");
|
||||
assertNull(storeMap2.put(null, o2));
|
||||
|
||||
assertEquals(o2, storeMap2.get("pk2"));
|
||||
assertEquals(o2, indexMap2.get("pk1"));
|
||||
|
||||
if (txn != null) {
|
||||
txn.commitTransaction();
|
||||
txn.beginTransaction(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* store1 contains o1 with primary key "pk1" and index key "ik1".
|
||||
*
|
||||
* store2 contains o2 with primary key "pk2" and foreign key "pk1",
|
||||
* which is the primary key of store1.
|
||||
*/
|
||||
|
||||
if (onDelete == ForeignKeyDeleteAction.ABORT) {
|
||||
|
||||
/* Test that we abort trying to delete a referenced key. */
|
||||
|
||||
try {
|
||||
storeMap1.remove("pk1");
|
||||
fail();
|
||||
} catch (RuntimeExceptionWrapper expected) {
|
||||
assertTrue(expected.getCause() instanceof DatabaseException);
|
||||
if (txn != null) {
|
||||
txn.abortTransaction();
|
||||
txn.beginTransaction(null);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test that we can put a record into store2 with a null foreign
|
||||
* key value. */
|
||||
|
||||
o2 = new MarshalledObject("data2", "pk2", "", "");
|
||||
assertNotNull(storeMap2.put(null, o2));
|
||||
assertEquals(o2, storeMap2.get("pk2"));
|
||||
|
||||
/* The index2 record should have been deleted since the key was set
|
||||
* to null above. */
|
||||
|
||||
assertNull(indexMap2.get("pk1"));
|
||||
|
||||
/* Test that now we can delete the record in store1, since it is no
|
||||
* longer referenced. */
|
||||
|
||||
assertNotNull(storeMap1.remove("pk1"));
|
||||
assertNull(storeMap1.get("pk1"));
|
||||
assertNull(indexMap1.get("ik1"));
|
||||
|
||||
} else if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
|
||||
|
||||
/* Delete the referenced key. */
|
||||
|
||||
assertNotNull(storeMap1.remove("pk1"));
|
||||
assertNull(storeMap1.get("pk1"));
|
||||
assertNull(indexMap1.get("ik1"));
|
||||
|
||||
/* The store2 record should still exist, but should have an empty
|
||||
* secondary key since it was nullified. */
|
||||
|
||||
o2 = (MarshalledObject) storeMap2.get("pk2");
|
||||
assertNotNull(o2);
|
||||
assertEquals("data2", o2.getData());
|
||||
assertEquals("pk2", o2.getPrimaryKey());
|
||||
assertEquals("", o2.getIndexKey1());
|
||||
assertEquals("", o2.getIndexKey2());
|
||||
|
||||
} else if (onDelete == ForeignKeyDeleteAction.CASCADE) {
|
||||
|
||||
/* Delete the referenced key. */
|
||||
|
||||
assertNotNull(storeMap1.remove("pk1"));
|
||||
assertNull(storeMap1.get("pk1"));
|
||||
assertNull(indexMap1.get("ik1"));
|
||||
|
||||
/* The store2 record should have deleted also. */
|
||||
|
||||
assertNull(storeMap2.get("pk2"));
|
||||
assertNull(indexMap2.get("pk1"));
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a foreign key value may not be used that is not present
|
||||
* in the foreign store. "pk2" is not in store1 in this case.
|
||||
*/
|
||||
assertNull(storeMap1.get("pk2"));
|
||||
MarshalledObject o3 = new MarshalledObject("data3", "pk3", "", "pk2");
|
||||
try {
|
||||
storeMap2.put(null, o3);
|
||||
fail();
|
||||
} catch (RuntimeExceptionWrapper expected) {
|
||||
assertTrue(expected.getCause() instanceof DatabaseException);
|
||||
}
|
||||
|
||||
if (txn != null) {
|
||||
txn.commitTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: IterDeadlockTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.DeadlockException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.bind.ByteArrayBinding;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.collections.StoredIterator;
|
||||
import com.sleepycat.collections.StoredSortedMap;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* Tests the fix for [#10516], where the StoredIterator constructor was not
|
||||
* closing the cursor when an exception occurred. For example, a deadlock
|
||||
* exception might occur if the constructor was unable to move the cursor to
|
||||
* the first element.
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class IterDeadlockTest extends TestCase {
|
||||
|
||||
private static final byte[] ONE = { 1 };
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(IterDeadlockTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
private Database store1;
|
||||
private Database store2;
|
||||
private StoredSortedMap map1;
|
||||
private StoredSortedMap map2;
|
||||
private ByteArrayBinding binding = new ByteArrayBinding();
|
||||
|
||||
public IterDeadlockTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
env = TestEnv.TXN.open("IterDeadlockTest");
|
||||
store1 = openDb("store1.db");
|
||||
store2 = openDb("store2.db");
|
||||
map1 = new StoredSortedMap(store1, binding, binding, true);
|
||||
map2 = new StoredSortedMap(store2, binding, binding, true);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
if (store1 != null) {
|
||||
try {
|
||||
store1.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
if (store2 != null) {
|
||||
try {
|
||||
store2.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
if (env != null) {
|
||||
try {
|
||||
env.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
/* Allow GC of DB objects in the test case. */
|
||||
env = null;
|
||||
store1 = null;
|
||||
store2 = null;
|
||||
map1 = null;
|
||||
map2 = null;
|
||||
}
|
||||
|
||||
private Database openDb(String file)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
config.setTransactional(true);
|
||||
config.setAllowCreate(true);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
public void testIterDeadlock()
|
||||
throws Exception {
|
||||
|
||||
final Object parent = new Object();
|
||||
final Object child1 = new Object();
|
||||
final Object child2 = new Object();
|
||||
final TransactionRunner runner = new TransactionRunner(env);
|
||||
runner.setMaxRetries(0);
|
||||
|
||||
/* Write a record in each db. */
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertNull(map1.put(ONE, ONE));
|
||||
assertNull(map2.put(ONE, ONE));
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* A thread to open iterator 1, then wait to be notified, then open
|
||||
* iterator 2.
|
||||
*/
|
||||
final Thread thread1 = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
synchronized (child1) {
|
||||
ListIterator i1 =
|
||||
(ListIterator) map1.values().iterator();
|
||||
i1.next();
|
||||
i1.set(ONE); /* Write lock. */
|
||||
StoredIterator.close(i1);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
child1.wait();
|
||||
Iterator i2 = map2.values().iterator();
|
||||
assertTrue(i2.hasNext());
|
||||
StoredIterator.close(i2);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (DeadlockException expected) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* A thread to open iterator 2, then wait to be notified, then open
|
||||
* iterator 1.
|
||||
*/
|
||||
final Thread thread2 = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
synchronized (child2) {
|
||||
ListIterator i2 =
|
||||
(ListIterator) map2.values().iterator();
|
||||
i2.next();
|
||||
i2.set(ONE); /* Write lock. */
|
||||
StoredIterator.close(i2);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
child2.wait();
|
||||
Iterator i1 = map1.values().iterator();
|
||||
assertTrue(i1.hasNext());
|
||||
StoredIterator.close(i1);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (DeadlockException expected) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Open iterator 1 in thread 1, then iterator 2 in thread 2, then let
|
||||
* the threads run to open the other iterators and cause a deadlock.
|
||||
*/
|
||||
synchronized (parent) {
|
||||
thread1.start();
|
||||
parent.wait();
|
||||
thread2.start();
|
||||
parent.wait();
|
||||
synchronized (child1) { child1.notify(); }
|
||||
synchronized (child2) { child2.notify(); }
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
}
|
||||
|
||||
/*
|
||||
* Before the fix for [#10516] we would get an exception indicating
|
||||
* that cursors were not closed, when closing the stores below.
|
||||
*/
|
||||
store1.close();
|
||||
store1 = null;
|
||||
store2.close();
|
||||
store2 = null;
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
}
|
||||
233
test/scr024/src/com/sleepycat/collections/test/JoinTest.java
Normal file
233
test/scr024/src/com/sleepycat/collections/test/JoinTest.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: JoinTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.bind.serial.test.MarshalledObject;
|
||||
import com.sleepycat.collections.StoredCollection;
|
||||
import com.sleepycat.collections.StoredContainer;
|
||||
import com.sleepycat.collections.StoredIterator;
|
||||
import com.sleepycat.collections.StoredMap;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.collections.TupleSerialFactory;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.SecondaryConfig;
|
||||
import com.sleepycat.db.SecondaryDatabase;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class JoinTest extends TestCase
|
||||
implements TransactionWorker {
|
||||
|
||||
private static final String MATCH_DATA = "d4"; // matches both keys = "yes"
|
||||
private static final String MATCH_KEY = "k4"; // matches both keys = "yes"
|
||||
private static final String[] VALUES = {"yes", "yes"};
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
return new JoinTest();
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
private TransactionRunner runner;
|
||||
private StoredClassCatalog catalog;
|
||||
private TupleSerialFactory factory;
|
||||
private Database store;
|
||||
private SecondaryDatabase index1;
|
||||
private SecondaryDatabase index2;
|
||||
private StoredMap storeMap;
|
||||
private StoredMap indexMap1;
|
||||
private StoredMap indexMap2;
|
||||
|
||||
public JoinTest() {
|
||||
|
||||
super("JoinTest");
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = TestEnv.TXN.open(getName());
|
||||
runner = new TransactionRunner(env);
|
||||
createDatabase();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (index1 != null) {
|
||||
index1.close();
|
||||
}
|
||||
if (index2 != null) {
|
||||
index2.close();
|
||||
}
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
if (catalog != null) {
|
||||
catalog.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
index1 = null;
|
||||
index2 = null;
|
||||
store = null;
|
||||
catalog = null;
|
||||
env = null;
|
||||
runner = null;
|
||||
factory = null;
|
||||
storeMap = null;
|
||||
indexMap1 = null;
|
||||
indexMap2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
runner.run(this);
|
||||
}
|
||||
|
||||
public void doWork()
|
||||
throws Exception {
|
||||
|
||||
createViews();
|
||||
writeAndRead();
|
||||
}
|
||||
|
||||
private void createDatabase()
|
||||
throws Exception {
|
||||
|
||||
catalog = new StoredClassCatalog(openDb("catalog.db"));
|
||||
factory = new TupleSerialFactory(catalog);
|
||||
assertSame(catalog, factory.getCatalog());
|
||||
|
||||
store = openDb("store.db");
|
||||
index1 = openSecondaryDb(store, "index1.db", "1");
|
||||
index2 = openSecondaryDb(store, "index2.db", "2");
|
||||
}
|
||||
|
||||
private Database openDb(String file)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
config.setTransactional(true);
|
||||
config.setAllowCreate(true);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
private SecondaryDatabase openSecondaryDb(Database primary,
|
||||
String file,
|
||||
String keyName)
|
||||
throws Exception {
|
||||
|
||||
SecondaryConfig secConfig = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(secConfig);
|
||||
secConfig.setTransactional(true);
|
||||
secConfig.setAllowCreate(true);
|
||||
DbCompat.setSortedDuplicates(secConfig, true);
|
||||
secConfig.setKeyCreator(factory.getKeyCreator(MarshalledObject.class,
|
||||
keyName));
|
||||
|
||||
return DbCompat.testOpenSecondaryDatabase
|
||||
(env, null, file, null, primary, secConfig);
|
||||
}
|
||||
|
||||
private void createViews()
|
||||
throws Exception {
|
||||
|
||||
storeMap = factory.newMap(store, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap1 = factory.newMap(index1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap2 = factory.newMap(index2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
}
|
||||
|
||||
private void writeAndRead()
|
||||
throws Exception {
|
||||
|
||||
// write records: Data, PrimaryKey, IndexKey1, IndexKey2
|
||||
assertNull(storeMap.put(null,
|
||||
new MarshalledObject("d1", "k1", "no", "yes")));
|
||||
assertNull(storeMap.put(null,
|
||||
new MarshalledObject("d2", "k2", "no", "no")));
|
||||
assertNull(storeMap.put(null,
|
||||
new MarshalledObject("d3", "k3", "no", "yes")));
|
||||
assertNull(storeMap.put(null,
|
||||
new MarshalledObject("d4", "k4", "yes", "yes")));
|
||||
assertNull(storeMap.put(null,
|
||||
new MarshalledObject("d5", "k5", "yes", "no")));
|
||||
|
||||
Object o;
|
||||
Map.Entry e;
|
||||
|
||||
// join values with index maps
|
||||
o = doJoin((StoredCollection) storeMap.values());
|
||||
assertEquals(MATCH_DATA, ((MarshalledObject) o).getData());
|
||||
|
||||
// join keySet with index maps
|
||||
o = doJoin((StoredCollection) storeMap.keySet());
|
||||
assertEquals(MATCH_KEY, o);
|
||||
|
||||
// join entrySet with index maps
|
||||
o = doJoin((StoredCollection) storeMap.entrySet());
|
||||
e = (Map.Entry) o;
|
||||
assertEquals(MATCH_KEY, e.getKey());
|
||||
assertEquals(MATCH_DATA, ((MarshalledObject) e.getValue()).getData());
|
||||
}
|
||||
|
||||
private Object doJoin(StoredCollection coll) {
|
||||
|
||||
StoredContainer[] indices = { indexMap1, indexMap2 };
|
||||
StoredIterator i = coll.join(indices, VALUES, null);
|
||||
try {
|
||||
assertTrue(i.hasNext());
|
||||
Object result = i.next();
|
||||
assertNotNull(result);
|
||||
assertFalse(i.hasNext());
|
||||
return result;
|
||||
} finally { i.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: NullTransactionRunner.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
|
||||
class NullTransactionRunner extends TransactionRunner {
|
||||
|
||||
NullTransactionRunner(Environment env) {
|
||||
|
||||
super(env);
|
||||
}
|
||||
|
||||
public void run(TransactionWorker worker)
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
worker.doWork();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUnwrapper.unwrap(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: SecondaryDeadlockTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DeadlockException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.TransactionConfig;
|
||||
import com.sleepycat.collections.StoredSortedMap;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* Tests whether secondary access can cause a self-deadlock when reading via a
|
||||
* secondary because the collections API secondary implementation in DB 4.2
|
||||
* opens two cursors. Part of the problem in [#10516] was because the
|
||||
* secondary get() was not done in a txn. This problem should not occur in DB
|
||||
* 4.3 and JE -- an ordinary deadlock occurs instead and is detected.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class SecondaryDeadlockTest extends TestCase {
|
||||
|
||||
private static final Long N_ONE = new Long(1);
|
||||
private static final Long N_101 = new Long(101);
|
||||
private static final int N_ITERS = 20;
|
||||
private static final int MAX_RETRIES = 1000;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(SecondaryDeadlockTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
private Database store;
|
||||
private Database index;
|
||||
private StoredSortedMap storeMap;
|
||||
private StoredSortedMap indexMap;
|
||||
private Exception exception;
|
||||
|
||||
public SecondaryDeadlockTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
env = TestEnv.TXN.open("SecondaryDeadlockTest");
|
||||
store = TestStore.BTREE_UNIQ.open(env, "store.db");
|
||||
index = TestStore.BTREE_UNIQ.openIndex(store, "index.db");
|
||||
storeMap = new StoredSortedMap(store,
|
||||
TestStore.BTREE_UNIQ.getKeyBinding(),
|
||||
TestStore.BTREE_UNIQ.getValueBinding(),
|
||||
true);
|
||||
indexMap = new StoredSortedMap(index,
|
||||
TestStore.BTREE_UNIQ.getKeyBinding(),
|
||||
TestStore.BTREE_UNIQ.getValueBinding(),
|
||||
true);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
if (index != null) {
|
||||
try {
|
||||
index.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
if (store != null) {
|
||||
try {
|
||||
store.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
if (env != null) {
|
||||
try {
|
||||
env.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
}
|
||||
}
|
||||
/* Allow GC of DB objects in the test case. */
|
||||
env = null;
|
||||
store = null;
|
||||
index = null;
|
||||
storeMap = null;
|
||||
indexMap = null;
|
||||
}
|
||||
|
||||
public void testSecondaryDeadlock()
|
||||
throws Exception {
|
||||
|
||||
final TransactionRunner runner = new TransactionRunner(env);
|
||||
runner.setMaxRetries(MAX_RETRIES);
|
||||
|
||||
/*
|
||||
* This test deadlocks a lot at degree 3 serialization. In debugging
|
||||
* this I discovered it was not due to phantom prevention per se but
|
||||
* just to a change in timing.
|
||||
*/
|
||||
TransactionConfig txnConfig = new TransactionConfig();
|
||||
runner.setTransactionConfig(txnConfig);
|
||||
|
||||
/*
|
||||
* A thread to do put() and delete() via the primary, which will lock
|
||||
* the primary first then the secondary. Uses transactions.
|
||||
*/
|
||||
final Thread thread1 = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
/* The TransactionRunner performs retries. */
|
||||
for (int i = 0; i < N_ITERS; i +=1 ) {
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertEquals(null, storeMap.put(N_ONE, N_101));
|
||||
}
|
||||
});
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertEquals(N_101, storeMap.remove(N_ONE));
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
}, "ThreadOne");
|
||||
|
||||
/*
|
||||
* A thread to get() via the secondary, which will lock the secondary
|
||||
* first then the primary. Does not use a transaction.
|
||||
*/
|
||||
final Thread thread2 = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
for (int i = 0; i < N_ITERS; i +=1 ) {
|
||||
for (int j = 0; j < MAX_RETRIES; j += 1) {
|
||||
try {
|
||||
Object value = indexMap.get(N_ONE);
|
||||
assertTrue(value == null ||
|
||||
N_101.equals(value));
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
e = ExceptionUnwrapper.unwrap(e);
|
||||
if (e instanceof DeadlockException) {
|
||||
continue; /* Retry on deadlock. */
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
}, "ThreadTwo");
|
||||
|
||||
thread1.start();
|
||||
thread2.start();
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
|
||||
index.close();
|
||||
index = null;
|
||||
store.close();
|
||||
store = null;
|
||||
env.close();
|
||||
env = null;
|
||||
|
||||
if (exception != null) {
|
||||
fail(exception.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestDataBinding.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import com.sleepycat.bind.EntryBinding;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestDataBinding implements EntryBinding {
|
||||
|
||||
public Object entryToObject(DatabaseEntry data) {
|
||||
|
||||
if (data.getSize() != 1) {
|
||||
throw new IllegalStateException("size=" + data.getSize());
|
||||
}
|
||||
byte val = data.getData()[data.getOffset()];
|
||||
return new Long(val);
|
||||
}
|
||||
|
||||
public void objectToEntry(Object object, DatabaseEntry data) {
|
||||
|
||||
byte val = ((Number) object).byteValue();
|
||||
data.setData(new byte[] { val }, 0, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestEntity.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestEntity {
|
||||
|
||||
int key;
|
||||
int value;
|
||||
|
||||
TestEntity(int key, int value) {
|
||||
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
|
||||
try {
|
||||
TestEntity e = (TestEntity) o;
|
||||
return e.key == key && e.value == value;
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
return "[key " + key + " value " + value + ']';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestEntityBinding.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import com.sleepycat.bind.EntityBinding;
|
||||
import com.sleepycat.bind.RecordNumberBinding;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestEntityBinding implements EntityBinding {
|
||||
|
||||
private boolean isRecNum;
|
||||
|
||||
TestEntityBinding(boolean isRecNum) {
|
||||
|
||||
this.isRecNum = isRecNum;
|
||||
}
|
||||
|
||||
public Object entryToObject(DatabaseEntry key, DatabaseEntry value) {
|
||||
|
||||
byte keyByte;
|
||||
if (isRecNum) {
|
||||
if (key.getSize() != 4) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
keyByte = (byte) RecordNumberBinding.entryToRecordNumber(key);
|
||||
} else {
|
||||
if (key.getSize() != 1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
keyByte = key.getData()[key.getOffset()];
|
||||
}
|
||||
if (value.getSize() != 1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
byte valByte = value.getData()[value.getOffset()];
|
||||
return new TestEntity(keyByte, valByte);
|
||||
}
|
||||
|
||||
public void objectToKey(Object object, DatabaseEntry key) {
|
||||
|
||||
byte val = (byte) ((TestEntity) object).key;
|
||||
if (isRecNum) {
|
||||
RecordNumberBinding.recordNumberToEntry(val, key);
|
||||
} else {
|
||||
key.setData(new byte[] { val }, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void objectToData(Object object, DatabaseEntry value) {
|
||||
|
||||
byte val = (byte) ((TestEntity) object).value;
|
||||
value.setData(new byte[] { val }, 0, 1);
|
||||
}
|
||||
}
|
||||
130
test/scr024/src/com/sleepycat/collections/test/TestEnv.java
Normal file
130
test/scr024/src/com/sleepycat/collections/test/TestEnv.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestEnv.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TestEnv {
|
||||
|
||||
public static final TestEnv BDB;
|
||||
public static final TestEnv CDB;
|
||||
public static final TestEnv TXN;
|
||||
static {
|
||||
EnvironmentConfig config;
|
||||
|
||||
config = newEnvConfig();
|
||||
BDB = new TestEnv("bdb", config);
|
||||
|
||||
if (DbCompat.CDB) {
|
||||
config = newEnvConfig();
|
||||
DbCompat.setInitializeCDB(config, true);
|
||||
CDB = new TestEnv("cdb", config);
|
||||
} else {
|
||||
CDB = null;
|
||||
}
|
||||
|
||||
config = newEnvConfig();
|
||||
config.setTransactional(true);
|
||||
DbCompat.setInitializeLocking(config, true);
|
||||
TXN = new TestEnv("txn", config);
|
||||
}
|
||||
|
||||
private static EnvironmentConfig newEnvConfig() {
|
||||
|
||||
EnvironmentConfig config = new EnvironmentConfig();
|
||||
if (DbCompat.MEMORY_SUBSYSTEM) {
|
||||
DbCompat.setInitializeCache(config, true);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public static final TestEnv[] ALL;
|
||||
static {
|
||||
if (DbCompat.CDB) {
|
||||
ALL = new TestEnv[] { BDB, CDB, TXN };
|
||||
} else {
|
||||
ALL = new TestEnv[] { BDB, TXN };
|
||||
}
|
||||
}
|
||||
|
||||
private String name;
|
||||
private EnvironmentConfig config;
|
||||
|
||||
TestEnv(String name, EnvironmentConfig config) {
|
||||
|
||||
this.name = name;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isTxnMode() {
|
||||
|
||||
return config.getTransactional();
|
||||
}
|
||||
|
||||
public boolean isCdbMode() {
|
||||
|
||||
return DbCompat.getInitializeCDB(config);
|
||||
}
|
||||
|
||||
public Environment open(String testName)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
return open(testName, true);
|
||||
}
|
||||
|
||||
public Environment open(String testName, boolean create)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
config.setAllowCreate(create);
|
||||
/* OLDEST deadlock detection on DB matches the use of timeouts on JE.*/
|
||||
DbCompat.setLockDetectModeOldest(config);
|
||||
File dir = getDirectory(testName, create);
|
||||
return newEnvironment(dir, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is overridden in XACollectionTest.
|
||||
*/
|
||||
protected Environment newEnvironment(File dir, EnvironmentConfig config)
|
||||
throws DatabaseException, IOException {
|
||||
|
||||
return new Environment(dir, config);
|
||||
}
|
||||
|
||||
public File getDirectory(String testName)
|
||||
throws IOException {
|
||||
|
||||
return getDirectory(testName, true);
|
||||
}
|
||||
|
||||
public File getDirectory(String testName, boolean create)
|
||||
throws IOException {
|
||||
|
||||
if (create) {
|
||||
return SharedTestUtils.getNewDir("db-test/" + testName);
|
||||
} else {
|
||||
return SharedTestUtils.getExistingDir("db-test/" + testName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestKeyAssigner.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import com.sleepycat.bind.RecordNumberBinding;
|
||||
import com.sleepycat.collections.PrimaryKeyAssigner;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestKeyAssigner implements PrimaryKeyAssigner {
|
||||
|
||||
private byte next = 1;
|
||||
private boolean isRecNum;
|
||||
|
||||
TestKeyAssigner(boolean isRecNum) {
|
||||
|
||||
this.isRecNum = isRecNum;
|
||||
}
|
||||
|
||||
public void assignKey(DatabaseEntry keyData)
|
||||
throws DatabaseException {
|
||||
|
||||
if (isRecNum) {
|
||||
RecordNumberBinding.recordNumberToEntry(next, keyData);
|
||||
} else {
|
||||
keyData.setData(new byte[] { next }, 0, 1);
|
||||
}
|
||||
next += 1;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
||||
next = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestKeyCreator.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import com.sleepycat.bind.RecordNumberBinding;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.SecondaryDatabase;
|
||||
import com.sleepycat.db.SecondaryKeyCreator;
|
||||
|
||||
/**
|
||||
* Unused until secondaries are available.
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestKeyCreator implements SecondaryKeyCreator {
|
||||
|
||||
private boolean isRecNum;
|
||||
|
||||
TestKeyCreator(boolean isRecNum) {
|
||||
|
||||
this.isRecNum = isRecNum;
|
||||
}
|
||||
|
||||
public boolean createSecondaryKey(SecondaryDatabase db,
|
||||
DatabaseEntry primaryKeyData,
|
||||
DatabaseEntry valueData,
|
||||
DatabaseEntry indexKeyData)
|
||||
throws DatabaseException {
|
||||
|
||||
if (valueData.getSize() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (valueData.getSize() != 1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
byte val = valueData.getData()[valueData.getOffset()];
|
||||
if (val == 0) {
|
||||
return false; // fixed-len pad value
|
||||
}
|
||||
val -= 100;
|
||||
if (isRecNum) {
|
||||
RecordNumberBinding.recordNumberToEntry(val, indexKeyData);
|
||||
} else {
|
||||
indexKeyData.setData(new byte[] { val }, 0, 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void clearIndexKey(DatabaseEntry valueData) {
|
||||
|
||||
throw new RuntimeException("not supported");
|
||||
}
|
||||
}
|
||||
121
test/scr024/src/com/sleepycat/collections/test/TestSR15721.java
Normal file
121
test/scr024/src/com/sleepycat/collections/test/TestSR15721.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestSR15721.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.collections.CurrentTransaction;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Chao Huang
|
||||
*/
|
||||
public class TestSR15721 extends TestCase {
|
||||
|
||||
/**
|
||||
* Runs a command line collection test.
|
||||
* @see #usage
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
if (args.length == 1 &&
|
||||
(args[0].equals("-h") || args[0].equals("-help"))) {
|
||||
usage();
|
||||
} else {
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
|
||||
System.out.println(
|
||||
"Usage: java com.sleepycat.collections.test.TestSR15721"
|
||||
+ " [-h | -help]\n");
|
||||
System.exit(2);
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(TestSR15721.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
private CurrentTransaction currentTxn;
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
env = TestEnv.TXN.open("TestSR15721");
|
||||
currentTxn = CurrentTransaction.getInstance(env);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
try {
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
env = null;
|
||||
currentTxn = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the CurrentTransaction instance doesn't indeed allow GC to
|
||||
* reclaim while attached environment is open. [#15721]
|
||||
*/
|
||||
public void testSR15721Fix()
|
||||
throws Exception {
|
||||
|
||||
int hash = currentTxn.hashCode();
|
||||
int hash2 = -1;
|
||||
|
||||
currentTxn = CurrentTransaction.getInstance(env);
|
||||
hash2 = currentTxn.hashCode();
|
||||
assertTrue(hash == hash2);
|
||||
|
||||
currentTxn.beginTransaction(null);
|
||||
currentTxn = null;
|
||||
hash2 = -1;
|
||||
|
||||
for (int i = 0; i < 10; i += 1) {
|
||||
byte[] x = null;
|
||||
try {
|
||||
x = new byte[Integer.MAX_VALUE - 1];
|
||||
fail();
|
||||
} catch (OutOfMemoryError expected) {
|
||||
}
|
||||
assertNull(x);
|
||||
|
||||
System.gc();
|
||||
}
|
||||
|
||||
currentTxn = CurrentTransaction.getInstance(env);
|
||||
hash2 = currentTxn.hashCode();
|
||||
currentTxn.commitTransaction();
|
||||
|
||||
assertTrue(hash == hash2);
|
||||
}
|
||||
}
|
||||
280
test/scr024/src/com/sleepycat/collections/test/TestStore.java
Normal file
280
test/scr024/src/com/sleepycat/collections/test/TestStore.java
Normal file
@@ -0,0 +1,280 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestStore.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sleepycat.bind.EntityBinding;
|
||||
import com.sleepycat.bind.EntryBinding;
|
||||
import com.sleepycat.bind.RecordNumberBinding;
|
||||
import com.sleepycat.collections.CurrentTransaction;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.SecondaryConfig;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestStore {
|
||||
|
||||
static final TestKeyCreator BYTE_EXTRACTOR = new TestKeyCreator(false);
|
||||
static final TestKeyCreator RECNO_EXTRACTOR = new TestKeyCreator(true);
|
||||
static final EntryBinding VALUE_BINDING = new TestDataBinding();
|
||||
static final EntryBinding BYTE_KEY_BINDING = VALUE_BINDING;
|
||||
static final EntryBinding RECNO_KEY_BINDING = new RecordNumberBinding();
|
||||
static final EntityBinding BYTE_ENTITY_BINDING =
|
||||
new TestEntityBinding(false);
|
||||
static final EntityBinding RECNO_ENTITY_BINDING =
|
||||
new TestEntityBinding(true);
|
||||
static final TestKeyAssigner BYTE_KEY_ASSIGNER =
|
||||
new TestKeyAssigner(false);
|
||||
static final TestKeyAssigner RECNO_KEY_ASSIGNER =
|
||||
new TestKeyAssigner(true);
|
||||
|
||||
static final TestStore BTREE_UNIQ;
|
||||
static final TestStore BTREE_DUP;
|
||||
static final TestStore BTREE_DUPSORT;
|
||||
static final TestStore BTREE_RECNUM;
|
||||
static final TestStore HASH_UNIQ;
|
||||
static final TestStore HASH_DUP;
|
||||
static final TestStore HASH_DUPSORT;
|
||||
static final TestStore QUEUE;
|
||||
static final TestStore RECNO;
|
||||
static final TestStore RECNO_RENUM;
|
||||
|
||||
static final TestStore[] ALL;
|
||||
static {
|
||||
List list = new ArrayList();
|
||||
SecondaryConfig config;
|
||||
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
BTREE_UNIQ = new TestStore("btree-uniq", config);
|
||||
BTREE_UNIQ.indexOf = BTREE_UNIQ;
|
||||
list.add(BTREE_UNIQ);
|
||||
|
||||
if (DbCompat.INSERTION_ORDERED_DUPLICATES) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
DbCompat.setUnsortedDuplicates(config, true);
|
||||
BTREE_DUP = new TestStore("btree-dup", config);
|
||||
BTREE_DUP.indexOf = null; // indexes must use sorted dups
|
||||
list.add(BTREE_DUP);
|
||||
} else {
|
||||
BTREE_DUP = null;
|
||||
}
|
||||
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
DbCompat.setSortedDuplicates(config, true);
|
||||
BTREE_DUPSORT = new TestStore("btree-dupsort", config);
|
||||
BTREE_DUPSORT.indexOf = BTREE_UNIQ;
|
||||
list.add(BTREE_DUPSORT);
|
||||
|
||||
if (DbCompat.BTREE_RECNUM_METHOD) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
DbCompat.setBtreeRecordNumbers(config, true);
|
||||
BTREE_RECNUM = new TestStore("btree-recnum", config);
|
||||
BTREE_RECNUM.indexOf = BTREE_RECNUM;
|
||||
list.add(BTREE_RECNUM);
|
||||
} else {
|
||||
BTREE_RECNUM = null;
|
||||
}
|
||||
|
||||
if (DbCompat.HASH_METHOD) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeHash(config);
|
||||
HASH_UNIQ = new TestStore("hash-uniq", config);
|
||||
HASH_UNIQ.indexOf = HASH_UNIQ;
|
||||
list.add(HASH_UNIQ);
|
||||
|
||||
if (DbCompat.INSERTION_ORDERED_DUPLICATES) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeHash(config);
|
||||
DbCompat.setUnsortedDuplicates(config, true);
|
||||
HASH_DUP = new TestStore("hash-dup", config);
|
||||
HASH_DUP.indexOf = null; // indexes must use sorted dups
|
||||
list.add(HASH_DUP);
|
||||
} else {
|
||||
HASH_DUP = null;
|
||||
}
|
||||
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeHash(config);
|
||||
DbCompat.setSortedDuplicates(config, true);
|
||||
HASH_DUPSORT = new TestStore("hash-dupsort", config);
|
||||
HASH_DUPSORT.indexOf = HASH_UNIQ;
|
||||
list.add(HASH_DUPSORT);
|
||||
} else {
|
||||
HASH_UNIQ = null;
|
||||
HASH_DUP = null;
|
||||
HASH_DUPSORT = null;
|
||||
}
|
||||
|
||||
if (DbCompat.QUEUE_METHOD) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeQueue(config);
|
||||
QUEUE = new TestStore("queue", config);
|
||||
QUEUE.indexOf = QUEUE;
|
||||
list.add(QUEUE);
|
||||
} else {
|
||||
QUEUE = null;
|
||||
}
|
||||
|
||||
if (DbCompat.RECNO_METHOD) {
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeRecno(config);
|
||||
RECNO = new TestStore("recno", config);
|
||||
RECNO.indexOf = RECNO;
|
||||
list.add(RECNO);
|
||||
|
||||
config = new SecondaryConfig();
|
||||
DbCompat.setTypeRecno(config);
|
||||
DbCompat.setRenumbering(config, true);
|
||||
RECNO_RENUM = new TestStore("recno-renum", config);
|
||||
RECNO_RENUM.indexOf = null; // indexes must have stable keys
|
||||
list.add(RECNO_RENUM);
|
||||
} else {
|
||||
RECNO = null;
|
||||
RECNO_RENUM = null;
|
||||
}
|
||||
|
||||
ALL = new TestStore[list.size()];
|
||||
list.toArray(ALL);
|
||||
}
|
||||
|
||||
private String name;
|
||||
private SecondaryConfig config;
|
||||
private TestStore indexOf;
|
||||
private boolean isRecNumFormat;
|
||||
|
||||
private TestStore(String name, SecondaryConfig config) {
|
||||
|
||||
this.name = name;
|
||||
this.config = config;
|
||||
|
||||
isRecNumFormat = isQueueOrRecno() ||
|
||||
(DbCompat.isTypeBtree(config) &&
|
||||
DbCompat.getBtreeRecordNumbers(config));
|
||||
}
|
||||
|
||||
EntryBinding getValueBinding() {
|
||||
|
||||
return VALUE_BINDING;
|
||||
}
|
||||
|
||||
EntryBinding getKeyBinding() {
|
||||
|
||||
return isRecNumFormat ? RECNO_KEY_BINDING : BYTE_KEY_BINDING;
|
||||
}
|
||||
|
||||
EntityBinding getEntityBinding() {
|
||||
|
||||
return isRecNumFormat ? RECNO_ENTITY_BINDING : BYTE_ENTITY_BINDING;
|
||||
}
|
||||
|
||||
TestKeyAssigner getKeyAssigner() {
|
||||
|
||||
if (isQueueOrRecno()) {
|
||||
return null;
|
||||
} else {
|
||||
if (isRecNumFormat) {
|
||||
return RECNO_KEY_ASSIGNER;
|
||||
} else {
|
||||
return BYTE_KEY_ASSIGNER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
boolean isOrdered() {
|
||||
|
||||
return !DbCompat.isTypeHash(config);
|
||||
}
|
||||
|
||||
boolean isQueueOrRecno() {
|
||||
|
||||
return DbCompat.isTypeQueue(config) || DbCompat.isTypeRecno(config);
|
||||
}
|
||||
|
||||
boolean areKeyRangesAllowed() {
|
||||
return isOrdered() && !isQueueOrRecno();
|
||||
}
|
||||
|
||||
boolean areDuplicatesAllowed() {
|
||||
|
||||
return DbCompat.getSortedDuplicates(config) ||
|
||||
DbCompat.getUnsortedDuplicates(config);
|
||||
}
|
||||
|
||||
boolean hasRecNumAccess() {
|
||||
|
||||
return isRecNumFormat;
|
||||
}
|
||||
|
||||
boolean areKeysRenumbered() {
|
||||
|
||||
return hasRecNumAccess() &&
|
||||
(DbCompat.isTypeBtree(config) ||
|
||||
DbCompat.getRenumbering(config));
|
||||
}
|
||||
|
||||
TestStore getIndexOf() {
|
||||
|
||||
return DbCompat.SECONDARIES ? indexOf : null;
|
||||
}
|
||||
|
||||
Database open(Environment env, String fileName)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
int fixedLen = (isQueueOrRecno() ? 1 : 0);
|
||||
return openDb(env, fileName, fixedLen, null);
|
||||
}
|
||||
|
||||
Database openIndex(Database primary, String fileName)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
int fixedLen = (isQueueOrRecno() ? 4 : 0);
|
||||
config.setKeyCreator(isRecNumFormat ? RECNO_EXTRACTOR
|
||||
: BYTE_EXTRACTOR);
|
||||
Environment env = primary.getEnvironment();
|
||||
return openDb(env, fileName, fixedLen, primary);
|
||||
}
|
||||
|
||||
private Database openDb(Environment env, String fileName, int fixedLen,
|
||||
Database primary)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
if (fixedLen > 0) {
|
||||
DbCompat.setRecordLength(config, fixedLen);
|
||||
DbCompat.setRecordPad(config, 0);
|
||||
} else {
|
||||
DbCompat.setRecordLength(config, 0);
|
||||
}
|
||||
config.setAllowCreate(true);
|
||||
DbCompat.setReadUncommitted(config, true);
|
||||
config.setTransactional(CurrentTransaction.getInstance(env) != null);
|
||||
if (primary != null) {
|
||||
return DbCompat.testOpenSecondaryDatabase
|
||||
(env, null, fileName, null, primary, config);
|
||||
} else {
|
||||
return DbCompat.testOpenDatabase
|
||||
(env, null, fileName, null, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,816 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TransactionTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.collections.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.collections.CurrentTransaction;
|
||||
import com.sleepycat.collections.StoredCollections;
|
||||
import com.sleepycat.collections.StoredContainer;
|
||||
import com.sleepycat.collections.StoredIterator;
|
||||
import com.sleepycat.collections.StoredList;
|
||||
import com.sleepycat.collections.StoredSortedMap;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.CursorConfig;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.DatabaseEntry;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.db.TransactionConfig;
|
||||
import com.sleepycat.util.RuntimeExceptionWrapper;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TransactionTest extends TestCase {
|
||||
|
||||
private static final Long ONE = new Long(1);
|
||||
private static final Long TWO = new Long(2);
|
||||
private static final Long THREE = new Long(3);
|
||||
|
||||
/**
|
||||
* Runs a command line collection test.
|
||||
* @see #usage
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
if (args.length == 1 &&
|
||||
(args[0].equals("-h") || args[0].equals("-help"))) {
|
||||
usage();
|
||||
} else {
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
|
||||
System.out.println(
|
||||
"Usage: java com.sleepycat.collections.test.TransactionTest"
|
||||
+ " [-h | -help]\n");
|
||||
System.exit(2);
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(TransactionTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
private CurrentTransaction currentTxn;
|
||||
private Database store;
|
||||
private StoredSortedMap map;
|
||||
private TestStore testStore = TestStore.BTREE_UNIQ;
|
||||
|
||||
public TransactionTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
|
||||
env = TestEnv.TXN.open("TransactionTests");
|
||||
currentTxn = CurrentTransaction.getInstance(env);
|
||||
store = testStore.open(env, dbName(0));
|
||||
map = new StoredSortedMap(store, testStore.getKeyBinding(),
|
||||
testStore.getValueBinding(), true);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
store = null;
|
||||
env = null;
|
||||
currentTxn = null;
|
||||
map = null;
|
||||
testStore = null;
|
||||
}
|
||||
}
|
||||
|
||||
private String dbName(int i) {
|
||||
|
||||
return "txn-test-" + getName() + '-' + i;
|
||||
}
|
||||
|
||||
public void testGetters()
|
||||
throws Exception {
|
||||
|
||||
assertNotNull(env);
|
||||
assertNotNull(currentTxn);
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
currentTxn.beginTransaction(null);
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
currentTxn.commitTransaction();
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
currentTxn.beginTransaction(null);
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
currentTxn.abortTransaction();
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
// read-uncommitted property should be inherited
|
||||
|
||||
assertTrue(!isReadUncommitted(map));
|
||||
assertTrue(!isReadUncommitted(map.values()));
|
||||
assertTrue(!isReadUncommitted(map.keySet()));
|
||||
assertTrue(!isReadUncommitted(map.entrySet()));
|
||||
|
||||
StoredSortedMap other = (StoredSortedMap)
|
||||
StoredCollections.configuredMap
|
||||
(map, CursorConfig.READ_UNCOMMITTED);
|
||||
assertTrue(isReadUncommitted(other));
|
||||
assertTrue(isReadUncommitted(other.values()));
|
||||
assertTrue(isReadUncommitted(other.keySet()));
|
||||
assertTrue(isReadUncommitted(other.entrySet()));
|
||||
assertTrue(!isReadUncommitted(map));
|
||||
assertTrue(!isReadUncommitted(map.values()));
|
||||
assertTrue(!isReadUncommitted(map.keySet()));
|
||||
assertTrue(!isReadUncommitted(map.entrySet()));
|
||||
|
||||
// read-committed property should be inherited
|
||||
|
||||
assertTrue(!isReadCommitted(map));
|
||||
assertTrue(!isReadCommitted(map.values()));
|
||||
assertTrue(!isReadCommitted(map.keySet()));
|
||||
assertTrue(!isReadCommitted(map.entrySet()));
|
||||
|
||||
other = (StoredSortedMap)
|
||||
StoredCollections.configuredMap
|
||||
(map, CursorConfig.READ_COMMITTED);
|
||||
assertTrue(isReadCommitted(other));
|
||||
assertTrue(isReadCommitted(other.values()));
|
||||
assertTrue(isReadCommitted(other.keySet()));
|
||||
assertTrue(isReadCommitted(other.entrySet()));
|
||||
assertTrue(!isReadCommitted(map));
|
||||
assertTrue(!isReadCommitted(map.values()));
|
||||
assertTrue(!isReadCommitted(map.keySet()));
|
||||
assertTrue(!isReadCommitted(map.entrySet()));
|
||||
}
|
||||
|
||||
public void testTransactional()
|
||||
throws Exception {
|
||||
|
||||
// is transactional because DB_AUTO_COMMIT was passed to
|
||||
// Database.open()
|
||||
//
|
||||
assertTrue(map.isTransactional());
|
||||
store.close();
|
||||
store = null;
|
||||
|
||||
// is not transactional
|
||||
//
|
||||
DatabaseConfig dbConfig = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(dbConfig);
|
||||
dbConfig.setAllowCreate(true);
|
||||
Database db = DbCompat.testOpenDatabase
|
||||
(env, null, dbName(1), null, dbConfig);
|
||||
map = new StoredSortedMap(db, testStore.getKeyBinding(),
|
||||
testStore.getValueBinding(), true);
|
||||
assertTrue(!map.isTransactional());
|
||||
map.put(ONE, ONE);
|
||||
readCheck(map, ONE, ONE);
|
||||
db.close();
|
||||
|
||||
// is transactional
|
||||
//
|
||||
dbConfig.setTransactional(true);
|
||||
currentTxn.beginTransaction(null);
|
||||
db = DbCompat.testOpenDatabase
|
||||
(env, currentTxn.getTransaction(), dbName(2), null, dbConfig);
|
||||
currentTxn.commitTransaction();
|
||||
map = new StoredSortedMap(db, testStore.getKeyBinding(),
|
||||
testStore.getValueBinding(), true);
|
||||
assertTrue(map.isTransactional());
|
||||
currentTxn.beginTransaction(null);
|
||||
map.put(ONE, ONE);
|
||||
readCheck(map, ONE, ONE);
|
||||
currentTxn.commitTransaction();
|
||||
db.close();
|
||||
}
|
||||
|
||||
public void testExceptions()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
currentTxn.commitTransaction();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
|
||||
try {
|
||||
currentTxn.abortTransaction();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
}
|
||||
|
||||
public void testNested()
|
||||
throws Exception {
|
||||
|
||||
if (!DbCompat.NESTED_TRANSACTIONS) {
|
||||
return;
|
||||
}
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
Transaction txn1 = currentTxn.beginTransaction(null);
|
||||
assertNotNull(txn1);
|
||||
assertTrue(txn1 == currentTxn.getTransaction());
|
||||
|
||||
assertNull(map.get(ONE));
|
||||
assertNull(map.put(ONE, ONE));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
|
||||
Transaction txn2 = currentTxn.beginTransaction(null);
|
||||
assertNotNull(txn2);
|
||||
assertTrue(txn2 == currentTxn.getTransaction());
|
||||
assertTrue(txn1 != txn2);
|
||||
|
||||
assertNull(map.put(TWO, TWO));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
|
||||
Transaction txn3 = currentTxn.beginTransaction(null);
|
||||
assertNotNull(txn3);
|
||||
assertTrue(txn3 == currentTxn.getTransaction());
|
||||
assertTrue(txn1 != txn2);
|
||||
assertTrue(txn1 != txn3);
|
||||
assertTrue(txn2 != txn3);
|
||||
|
||||
assertNull(map.put(THREE, THREE));
|
||||
assertEquals(THREE, map.get(THREE));
|
||||
|
||||
Transaction txn = currentTxn.abortTransaction();
|
||||
assertTrue(txn == txn2);
|
||||
assertTrue(txn == currentTxn.getTransaction());
|
||||
assertNull(map.get(THREE));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
|
||||
txn3 = currentTxn.beginTransaction(null);
|
||||
assertNotNull(txn3);
|
||||
assertTrue(txn3 == currentTxn.getTransaction());
|
||||
assertTrue(txn1 != txn2);
|
||||
assertTrue(txn1 != txn3);
|
||||
assertTrue(txn2 != txn3);
|
||||
|
||||
assertNull(map.put(THREE, THREE));
|
||||
assertEquals(THREE, map.get(THREE));
|
||||
|
||||
txn = currentTxn.commitTransaction();
|
||||
assertTrue(txn == txn2);
|
||||
assertTrue(txn == currentTxn.getTransaction());
|
||||
assertEquals(THREE, map.get(THREE));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
|
||||
txn = currentTxn.commitTransaction();
|
||||
assertTrue(txn == txn1);
|
||||
assertTrue(txn == currentTxn.getTransaction());
|
||||
assertEquals(THREE, map.get(THREE));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
|
||||
txn = currentTxn.commitTransaction();
|
||||
assertNull(txn);
|
||||
assertNull(currentTxn.getTransaction());
|
||||
assertEquals(THREE, map.get(THREE));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
}
|
||||
|
||||
public void testRunnerCommit()
|
||||
throws Exception {
|
||||
|
||||
commitTest(false);
|
||||
}
|
||||
|
||||
public void testExplicitCommit()
|
||||
throws Exception {
|
||||
|
||||
commitTest(true);
|
||||
}
|
||||
|
||||
private void commitTest(final boolean explicit)
|
||||
throws Exception {
|
||||
|
||||
final TransactionRunner runner = new TransactionRunner(env);
|
||||
runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
|
||||
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
final Transaction txn1 = currentTxn.getTransaction();
|
||||
assertNotNull(txn1);
|
||||
assertNull(map.put(ONE, ONE));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
final Transaction txn2 = currentTxn.getTransaction();
|
||||
assertNotNull(txn2);
|
||||
if (DbCompat.NESTED_TRANSACTIONS) {
|
||||
assertTrue(txn1 != txn2);
|
||||
} else {
|
||||
assertTrue(txn1 == txn2);
|
||||
}
|
||||
assertNull(map.put(TWO, TWO));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
if (DbCompat.NESTED_TRANSACTIONS && explicit) {
|
||||
currentTxn.commitTransaction();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Transaction txn3 = currentTxn.getTransaction();
|
||||
assertSame(txn1, txn3);
|
||||
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
}
|
||||
});
|
||||
|
||||
assertNull(currentTxn.getTransaction());
|
||||
}
|
||||
|
||||
public void testRunnerAbort()
|
||||
throws Exception {
|
||||
|
||||
abortTest(false);
|
||||
}
|
||||
|
||||
public void testExplicitAbort()
|
||||
throws Exception {
|
||||
|
||||
abortTest(true);
|
||||
}
|
||||
|
||||
private void abortTest(final boolean explicit)
|
||||
throws Exception {
|
||||
|
||||
final TransactionRunner runner = new TransactionRunner(env);
|
||||
runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
|
||||
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
final Transaction txn1 = currentTxn.getTransaction();
|
||||
assertNotNull(txn1);
|
||||
assertNull(map.put(ONE, ONE));
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
|
||||
if (DbCompat.NESTED_TRANSACTIONS) {
|
||||
try {
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
final Transaction txn2 =
|
||||
currentTxn.getTransaction();
|
||||
assertNotNull(txn2);
|
||||
assertTrue(txn1 != txn2);
|
||||
assertNull(map.put(TWO, TWO));
|
||||
assertEquals(TWO, map.get(TWO));
|
||||
if (explicit) {
|
||||
currentTxn.abortTransaction();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"test-abort");
|
||||
}
|
||||
}
|
||||
});
|
||||
assertTrue(explicit);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(!explicit);
|
||||
assertEquals("test-abort", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Transaction txn3 = currentTxn.getTransaction();
|
||||
assertSame(txn1, txn3);
|
||||
|
||||
assertEquals(ONE, map.get(ONE));
|
||||
assertNull(map.get(TWO));
|
||||
}
|
||||
});
|
||||
|
||||
assertNull(currentTxn.getTransaction());
|
||||
}
|
||||
|
||||
public void testReadCommittedCollection()
|
||||
throws Exception {
|
||||
|
||||
StoredSortedMap degree2Map = (StoredSortedMap)
|
||||
StoredCollections.configuredSortedMap
|
||||
(map, CursorConfig.READ_COMMITTED);
|
||||
|
||||
// original map is not read-committed
|
||||
assertTrue(!isReadCommitted(map));
|
||||
|
||||
// all read-committed containers are read-uncommitted
|
||||
assertTrue(isReadCommitted(degree2Map));
|
||||
assertTrue(isReadCommitted
|
||||
(StoredCollections.configuredMap
|
||||
(map, CursorConfig.READ_COMMITTED)));
|
||||
assertTrue(isReadCommitted
|
||||
(StoredCollections.configuredCollection
|
||||
(map.values(), CursorConfig.READ_COMMITTED)));
|
||||
assertTrue(isReadCommitted
|
||||
(StoredCollections.configuredSet
|
||||
(map.keySet(), CursorConfig.READ_COMMITTED)));
|
||||
assertTrue(isReadCommitted
|
||||
(StoredCollections.configuredSortedSet
|
||||
((SortedSet) map.keySet(),
|
||||
CursorConfig.READ_COMMITTED)));
|
||||
|
||||
if (DbCompat.RECNO_METHOD) {
|
||||
// create a list just so we can call configuredList()
|
||||
Database listStore = TestStore.RECNO_RENUM.open(env, null);
|
||||
List list = new StoredList(listStore, TestStore.VALUE_BINDING,
|
||||
true);
|
||||
assertTrue(isReadCommitted
|
||||
(StoredCollections.configuredList
|
||||
(list, CursorConfig.READ_COMMITTED)));
|
||||
listStore.close();
|
||||
}
|
||||
|
||||
map.put(ONE, ONE);
|
||||
doReadCommitted(degree2Map, null);
|
||||
}
|
||||
|
||||
private static boolean isReadCommitted(Object container) {
|
||||
StoredContainer storedContainer = (StoredContainer) container;
|
||||
/* We can't use getReadCommitted until is is added to DB core. */
|
||||
return storedContainer.getCursorConfig() != null &&
|
||||
storedContainer.getCursorConfig().getReadCommitted();
|
||||
}
|
||||
|
||||
public void testReadCommittedTransaction()
|
||||
throws Exception {
|
||||
|
||||
TransactionConfig config = new TransactionConfig();
|
||||
config.setReadCommitted(true);
|
||||
doReadCommitted(map, config);
|
||||
}
|
||||
|
||||
private void doReadCommitted(final StoredSortedMap degree2Map,
|
||||
TransactionConfig txnConfig)
|
||||
throws Exception {
|
||||
|
||||
map.put(ONE, ONE);
|
||||
TransactionRunner runner = new TransactionRunner(env);
|
||||
runner.setTransactionConfig(txnConfig);
|
||||
assertNull(currentTxn.getTransaction());
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
|
||||
/* Do a read-committed get(), the lock is not retained. */
|
||||
assertEquals(ONE, degree2Map.get(ONE));
|
||||
|
||||
/*
|
||||
* If we were not using read-committed, the following write of
|
||||
* key ONE with an auto-commit transaction would self-deadlock
|
||||
* since two transactions in the same thread would be
|
||||
* attempting to lock the same key, one for write and one for
|
||||
* read. This test passes if we do not deadlock.
|
||||
*/
|
||||
DatabaseEntry key = new DatabaseEntry();
|
||||
DatabaseEntry value = new DatabaseEntry();
|
||||
testStore.getKeyBinding().objectToEntry(ONE, key);
|
||||
testStore.getValueBinding().objectToEntry(TWO, value);
|
||||
store.put(null, key, value);
|
||||
}
|
||||
});
|
||||
assertNull(currentTxn.getTransaction());
|
||||
}
|
||||
|
||||
public void testReadUncommittedCollection()
|
||||
throws Exception {
|
||||
|
||||
StoredSortedMap dirtyMap = (StoredSortedMap)
|
||||
StoredCollections.configuredSortedMap
|
||||
(map, CursorConfig.READ_UNCOMMITTED);
|
||||
|
||||
// original map is not read-uncommitted
|
||||
assertTrue(!isReadUncommitted(map));
|
||||
|
||||
// all read-uncommitted containers are read-uncommitted
|
||||
assertTrue(isReadUncommitted(dirtyMap));
|
||||
assertTrue(isReadUncommitted
|
||||
(StoredCollections.configuredMap
|
||||
(map, CursorConfig.READ_UNCOMMITTED)));
|
||||
assertTrue(isReadUncommitted
|
||||
(StoredCollections.configuredCollection
|
||||
(map.values(), CursorConfig.READ_UNCOMMITTED)));
|
||||
assertTrue(isReadUncommitted
|
||||
(StoredCollections.configuredSet
|
||||
(map.keySet(), CursorConfig.READ_UNCOMMITTED)));
|
||||
assertTrue(isReadUncommitted
|
||||
(StoredCollections.configuredSortedSet
|
||||
((SortedSet) map.keySet(), CursorConfig.READ_UNCOMMITTED)));
|
||||
|
||||
if (DbCompat.RECNO_METHOD) {
|
||||
// create a list just so we can call configuredList()
|
||||
Database listStore = TestStore.RECNO_RENUM.open(env, null);
|
||||
List list = new StoredList(listStore, TestStore.VALUE_BINDING,
|
||||
true);
|
||||
assertTrue(isReadUncommitted
|
||||
(StoredCollections.configuredList
|
||||
(list, CursorConfig.READ_UNCOMMITTED)));
|
||||
listStore.close();
|
||||
}
|
||||
|
||||
doReadUncommitted(dirtyMap);
|
||||
}
|
||||
|
||||
private static boolean isReadUncommitted(Object container) {
|
||||
StoredContainer storedContainer = (StoredContainer) container;
|
||||
return storedContainer.getCursorConfig() != null &&
|
||||
storedContainer.getCursorConfig().getReadUncommitted();
|
||||
}
|
||||
|
||||
public void testReadUncommittedTransaction()
|
||||
throws Exception {
|
||||
|
||||
TransactionRunner runner = new TransactionRunner(env);
|
||||
TransactionConfig config = new TransactionConfig();
|
||||
config.setReadUncommitted(true);
|
||||
runner.setTransactionConfig(config);
|
||||
assertNull(currentTxn.getTransaction());
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
doReadUncommitted(map);
|
||||
}
|
||||
});
|
||||
assertNull(currentTxn.getTransaction());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the CurrentTransaction static WeakHashMap does indeed allow
|
||||
* GC to reclaim tine environment when it is closed. At one point this was
|
||||
* not working because the value object in the map has a reference to the
|
||||
* environment. This was fixed by wrapping the Environment in a
|
||||
* WeakReference. [#15444]
|
||||
*
|
||||
* This test only succeeds intermittently, probably due to its reliance
|
||||
* on the GC call.
|
||||
*/
|
||||
public void testCurrentTransactionGC()
|
||||
throws Exception {
|
||||
|
||||
/*
|
||||
* This test can have indeterminate results because it depends on
|
||||
* a finalize count, so it's not part of the default run.
|
||||
*/
|
||||
if (!SharedTestUtils.runLongTests()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringBuffer finalizedFlag = new StringBuffer();
|
||||
|
||||
class MyEnv extends Environment {
|
||||
|
||||
MyEnv(File home, EnvironmentConfig config)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
super(home, config);
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
finalizedFlag.append('.');
|
||||
}
|
||||
}
|
||||
|
||||
MyEnv myEnv = new MyEnv(env.getHome(), env.getConfig());
|
||||
CurrentTransaction myCurrTxn = CurrentTransaction.getInstance(myEnv);
|
||||
|
||||
store.close();
|
||||
store = null;
|
||||
map = null;
|
||||
|
||||
env.close();
|
||||
env = null;
|
||||
|
||||
myEnv.close();
|
||||
myEnv = null;
|
||||
|
||||
myCurrTxn = null;
|
||||
currentTxn = null;
|
||||
|
||||
for (int i = 0; i < 10; i += 1) {
|
||||
byte[] x = null;
|
||||
try {
|
||||
x = new byte[Integer.MAX_VALUE - 1];
|
||||
} catch (OutOfMemoryError expected) {
|
||||
}
|
||||
assertNull(x);
|
||||
System.gc();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i += 1) {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
assertTrue(finalizedFlag.length() > 0);
|
||||
}
|
||||
|
||||
private synchronized void doReadUncommitted(StoredSortedMap dirtyMap)
|
||||
throws Exception {
|
||||
|
||||
// start thread one
|
||||
ReadUncommittedThreadOne t1 = new ReadUncommittedThreadOne(env, this);
|
||||
t1.start();
|
||||
wait();
|
||||
|
||||
// put ONE
|
||||
synchronized (t1) { t1.notify(); }
|
||||
wait();
|
||||
readCheck(dirtyMap, ONE, ONE);
|
||||
assertTrue(!dirtyMap.isEmpty());
|
||||
|
||||
// abort ONE
|
||||
synchronized (t1) { t1.notify(); }
|
||||
t1.join();
|
||||
readCheck(dirtyMap, ONE, null);
|
||||
assertTrue(dirtyMap.isEmpty());
|
||||
|
||||
// start thread two
|
||||
ReadUncommittedThreadTwo t2 = new ReadUncommittedThreadTwo(env, this);
|
||||
t2.start();
|
||||
wait();
|
||||
|
||||
// put TWO
|
||||
synchronized (t2) { t2.notify(); }
|
||||
wait();
|
||||
readCheck(dirtyMap, TWO, TWO);
|
||||
assertTrue(!dirtyMap.isEmpty());
|
||||
|
||||
// commit TWO
|
||||
synchronized (t2) { t2.notify(); }
|
||||
t2.join();
|
||||
readCheck(dirtyMap, TWO, TWO);
|
||||
assertTrue(!dirtyMap.isEmpty());
|
||||
}
|
||||
|
||||
private static class ReadUncommittedThreadOne extends Thread {
|
||||
|
||||
private CurrentTransaction currentTxn;
|
||||
private TransactionTest parent;
|
||||
private StoredSortedMap map;
|
||||
|
||||
private ReadUncommittedThreadOne(Environment env,
|
||||
TransactionTest parent) {
|
||||
|
||||
this.currentTxn = CurrentTransaction.getInstance(env);
|
||||
this.parent = parent;
|
||||
this.map = parent.map;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
|
||||
try {
|
||||
assertNull(currentTxn.getTransaction());
|
||||
assertNotNull(currentTxn.beginTransaction(null));
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
readCheck(map, ONE, null);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
wait();
|
||||
|
||||
// put ONE
|
||||
assertNull(map.put(ONE, ONE));
|
||||
readCheck(map, ONE, ONE);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
wait();
|
||||
|
||||
// abort ONE
|
||||
assertNull(currentTxn.abortTransaction());
|
||||
assertNull(currentTxn.getTransaction());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReadUncommittedThreadTwo extends Thread {
|
||||
|
||||
private Environment env;
|
||||
private CurrentTransaction currentTxn;
|
||||
private TransactionTest parent;
|
||||
private StoredSortedMap map;
|
||||
|
||||
private ReadUncommittedThreadTwo(Environment env,
|
||||
TransactionTest parent) {
|
||||
|
||||
this.env = env;
|
||||
this.currentTxn = CurrentTransaction.getInstance(env);
|
||||
this.parent = parent;
|
||||
this.map = parent.map;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
|
||||
try {
|
||||
final TransactionRunner runner = new TransactionRunner(env);
|
||||
final Object thread = this;
|
||||
assertNull(currentTxn.getTransaction());
|
||||
|
||||
runner.run(new TransactionWorker() {
|
||||
public void doWork() throws Exception {
|
||||
assertNotNull(currentTxn.getTransaction());
|
||||
readCheck(map, TWO, null);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
thread.wait();
|
||||
|
||||
// put TWO
|
||||
assertNull(map.put(TWO, TWO));
|
||||
readCheck(map, TWO, TWO);
|
||||
synchronized (parent) { parent.notify(); }
|
||||
thread.wait();
|
||||
|
||||
// commit TWO
|
||||
}
|
||||
});
|
||||
assertNull(currentTxn.getTransaction());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readCheck(StoredSortedMap checkMap, Object key,
|
||||
Object expect) {
|
||||
if (expect == null) {
|
||||
assertNull(checkMap.get(key));
|
||||
assertTrue(checkMap.tailMap(key).isEmpty());
|
||||
assertTrue(!checkMap.tailMap(key).containsKey(key));
|
||||
assertTrue(!checkMap.keySet().contains(key));
|
||||
assertTrue(checkMap.duplicates(key).isEmpty());
|
||||
Iterator i = checkMap.keySet().iterator();
|
||||
try {
|
||||
while (i.hasNext()) {
|
||||
assertTrue(!key.equals(i.next()));
|
||||
}
|
||||
} finally { StoredIterator.close(i); }
|
||||
} else {
|
||||
assertEquals(expect, checkMap.get(key));
|
||||
assertEquals(expect, checkMap.tailMap(key).get(key));
|
||||
assertTrue(!checkMap.tailMap(key).isEmpty());
|
||||
assertTrue(checkMap.tailMap(key).containsKey(key));
|
||||
assertTrue(checkMap.keySet().contains(key));
|
||||
assertTrue(checkMap.values().contains(expect));
|
||||
assertTrue(!checkMap.duplicates(key).isEmpty());
|
||||
assertTrue(checkMap.duplicates(key).contains(expect));
|
||||
Iterator i = checkMap.keySet().iterator();
|
||||
try {
|
||||
boolean found = false;
|
||||
while (i.hasNext()) {
|
||||
if (expect.equals(i.next())) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
assertTrue(found);
|
||||
}
|
||||
finally { StoredIterator.close(i); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: CatalogCornerCaseTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class CatalogCornerCaseTest extends TestCase {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
return new TestSuite(CatalogCornerCaseTest.class);
|
||||
}
|
||||
|
||||
private Environment env;
|
||||
|
||||
public CatalogCornerCaseTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = TestEnv.BDB.open(getName());
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
env = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadOnlyEmptyCatalog()
|
||||
throws Exception {
|
||||
|
||||
String file = "catalog.db";
|
||||
|
||||
/* Create an empty database. */
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setAllowCreate(true);
|
||||
DbCompat.setTypeBtree(config);
|
||||
Database db =
|
||||
DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
db.close();
|
||||
|
||||
/* Open the empty database read-only. */
|
||||
config.setAllowCreate(false);
|
||||
config.setReadOnly(true);
|
||||
db = DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
|
||||
/* Expect exception when creating the catalog. */
|
||||
try {
|
||||
new StoredClassCatalog(db);
|
||||
fail();
|
||||
} catch (IllegalStateException e) { }
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: StoredClassCatalogTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.serial.SerialBinding;
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.collections.StoredMap;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* Runs part two of the StoredClassCatalogTest. This part is run with the
|
||||
* new/updated version of TestSerial in the classpath. It uses the
|
||||
* environment and databases created by StoredClassCatalogTestInit. It
|
||||
* verifies that it can read objects serialized using the old class format,
|
||||
* and that it can create new objects with the new class format.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class StoredClassCatalogTest extends TestCase
|
||||
implements TransactionWorker {
|
||||
|
||||
static final String CATALOG_FILE = "catalogtest-catalog.db";
|
||||
static final String STORE_FILE = "catalogtest-store.db";
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
|
||||
suite.addTest(new StoredClassCatalogTest(TestEnv.ALL[i]));
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private TestEnv testEnv;
|
||||
private Environment env;
|
||||
private StoredClassCatalog catalog;
|
||||
private StoredClassCatalog catalog2;
|
||||
private Database store;
|
||||
private Map map;
|
||||
private TransactionRunner runner;
|
||||
|
||||
public StoredClassCatalogTest(TestEnv testEnv) {
|
||||
|
||||
super(makeTestName(testEnv));
|
||||
this.testEnv = testEnv;
|
||||
}
|
||||
|
||||
static String makeTestName(TestEnv testEnv) {
|
||||
return "StoredClassCatalogTest-" + testEnv.getName();
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = testEnv.open(makeTestName(testEnv), false);
|
||||
runner = new TransactionRunner(env);
|
||||
|
||||
catalog = new StoredClassCatalog(openDb(CATALOG_FILE, false));
|
||||
catalog2 = new StoredClassCatalog(openDb("catalog2.db", true));
|
||||
|
||||
SerialBinding keyBinding = new SerialBinding(catalog,
|
||||
String.class);
|
||||
SerialBinding valueBinding = new SerialBinding(catalog,
|
||||
TestSerial.class);
|
||||
store = openDb(STORE_FILE, false);
|
||||
|
||||
map = new StoredMap(store, keyBinding, valueBinding, true);
|
||||
}
|
||||
|
||||
private Database openDb(String file, boolean create)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
config.setTransactional(testEnv.isTxnMode());
|
||||
config.setAllowCreate(create);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (catalog != null) {
|
||||
catalog.close();
|
||||
catalog.close(); // should have no effect
|
||||
}
|
||||
if (catalog2 != null) {
|
||||
catalog2.close();
|
||||
}
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Ignored exception during tearDown: ");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
catalog = null;
|
||||
catalog2 = null;
|
||||
store = null;
|
||||
env = null;
|
||||
testEnv = null;
|
||||
map = null;
|
||||
runner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
runner.run(this);
|
||||
}
|
||||
|
||||
public void doWork()
|
||||
throws Exception {
|
||||
|
||||
TestSerial one = (TestSerial) map.get("one");
|
||||
TestSerial two = (TestSerial) map.get("two");
|
||||
assertNotNull(one);
|
||||
assertNotNull(two);
|
||||
assertEquals(one, two.getOther());
|
||||
assertNull(one.getStringField());
|
||||
assertNull(two.getStringField());
|
||||
|
||||
TestSerial three = new TestSerial(two);
|
||||
assertNotNull(three.getStringField());
|
||||
map.put("three", three);
|
||||
three = (TestSerial) map.get("three");
|
||||
assertEquals(two, three.getOther());
|
||||
|
||||
ObjectStreamClass desc = ObjectStreamClass.lookup(TestSerial.class);
|
||||
|
||||
assertNotNull(catalog.getClassID(desc));
|
||||
assertNotNull(catalog.getClassID(desc));
|
||||
|
||||
// test with empty catalog
|
||||
assertNotNull(catalog2.getClassID(desc));
|
||||
assertNotNull(catalog2.getClassID(desc));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: StoredClassCatalogTestInit.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.serial.SerialBinding;
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.collections.StoredMap;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* Runs part one of the StoredClassCatalogTest. This part is run with the
|
||||
* old/original version of TestSerial in the classpath. It creates a fresh
|
||||
* environment and databases containing serialized versions of the old class.
|
||||
* When StoredClassCatalogTest is run, it will read these objects from the
|
||||
* database created here.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class StoredClassCatalogTestInit extends TestCase
|
||||
implements TransactionWorker {
|
||||
|
||||
static final String CATALOG_FILE = StoredClassCatalogTest.CATALOG_FILE;
|
||||
static final String STORE_FILE = StoredClassCatalogTest.STORE_FILE;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
|
||||
suite.addTest(new StoredClassCatalogTestInit(TestEnv.ALL[i]));
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private TestEnv testEnv;
|
||||
private Environment env;
|
||||
private StoredClassCatalog catalog;
|
||||
private Database store;
|
||||
private Map map;
|
||||
private TransactionRunner runner;
|
||||
|
||||
public StoredClassCatalogTestInit(TestEnv testEnv) {
|
||||
|
||||
super("StoredClassCatalogTestInit-" + testEnv.getName());
|
||||
this.testEnv = testEnv;
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = testEnv.open(StoredClassCatalogTest.makeTestName(testEnv));
|
||||
runner = new TransactionRunner(env);
|
||||
|
||||
catalog = new StoredClassCatalog(openDb(CATALOG_FILE));
|
||||
|
||||
SerialBinding keyBinding = new SerialBinding(catalog, String.class);
|
||||
SerialBinding valueBinding =
|
||||
new SerialBinding(catalog, TestSerial.class);
|
||||
store = openDb(STORE_FILE);
|
||||
|
||||
map = new StoredMap(store, keyBinding, valueBinding, true);
|
||||
}
|
||||
|
||||
private Database openDb(String file)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DbCompat.setTypeBtree(config);
|
||||
config.setTransactional(testEnv.isTxnMode());
|
||||
config.setAllowCreate(true);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (catalog != null) {
|
||||
catalog.close();
|
||||
catalog.close(); // should have no effect
|
||||
}
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Ignored exception during tearDown: ");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
catalog = null;
|
||||
store = null;
|
||||
env = null;
|
||||
testEnv = null;
|
||||
map = null;
|
||||
runner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
runner.run(this);
|
||||
}
|
||||
|
||||
public void doWork()
|
||||
throws Exception {
|
||||
|
||||
TestSerial one = new TestSerial(null);
|
||||
TestSerial two = new TestSerial(one);
|
||||
assertNull("Likely the classpath contains the wrong version of the" +
|
||||
" TestSerial class, the 'original' version is required",
|
||||
one.getStringField());
|
||||
assertNull(two.getStringField());
|
||||
map.put("one", one);
|
||||
map.put("two", two);
|
||||
one = (TestSerial) map.get("one");
|
||||
two = (TestSerial) map.get("two");
|
||||
assertEquals(one, two.getOther());
|
||||
assertNull(one.getStringField());
|
||||
assertNull(two.getStringField());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestSerial.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
/**
|
||||
* @see StoredClassCatalogTest
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestSerial implements java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = -3738980000390384920L;
|
||||
|
||||
private int i = 123;
|
||||
private TestSerial other;
|
||||
|
||||
// The following field 's' was added after this class was compiled and
|
||||
// serialized instances were saved in resource files. This allows testing
|
||||
// that the original stored instances can be deserialized after changing
|
||||
// the class. The serialVersionUID is needed for this according to Java
|
||||
// serialization rules, and was generated with the serialver tool.
|
||||
//
|
||||
private String s = "string";
|
||||
|
||||
TestSerial(TestSerial other) {
|
||||
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
TestSerial getOther() {
|
||||
|
||||
return other;
|
||||
}
|
||||
|
||||
int getIntField() {
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
String getStringField() {
|
||||
|
||||
return s; // this returned null before field 's' was added.
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
|
||||
try {
|
||||
TestSerial o = (TestSerial) object;
|
||||
if ((o.other == null) ? (this.other != null)
|
||||
: (!o.other.equals(this.other))) {
|
||||
return false;
|
||||
}
|
||||
if (this.i != o.i) {
|
||||
return false;
|
||||
}
|
||||
// the following test was not done before field 's' was added
|
||||
if ((o.s == null) ? (this.s != null)
|
||||
: (!o.s.equals(this.s))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestSerial.java.original,v 12.10 2008/02/07 17:12:32 mark Exp $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
/**
|
||||
* @see StoredClassCatalogTest
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
class TestSerial implements java.io.Serializable
|
||||
{
|
||||
static final long serialVersionUID = -3738980000390384920L;
|
||||
|
||||
private int i = 123;
|
||||
private TestSerial other;
|
||||
|
||||
// The following field 's' was added after this class was compiled and
|
||||
// serialized instances were saved in resource files. This allows testing
|
||||
// that the original stored instances can be deserialized after changing
|
||||
// the class. The serialVersionUID is needed for this according to Java
|
||||
// serialization rules, and was generated with the serialver tool.
|
||||
//
|
||||
//private String s = "string";
|
||||
|
||||
TestSerial(TestSerial other)
|
||||
{
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
TestSerial getOther()
|
||||
{
|
||||
return other;
|
||||
}
|
||||
|
||||
int getIntField()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
String getStringField()
|
||||
{
|
||||
return null; // this returned null before field 's' was added.
|
||||
}
|
||||
|
||||
public boolean equals(Object object)
|
||||
{
|
||||
try
|
||||
{
|
||||
TestSerial o = (TestSerial) object;
|
||||
if ((o.other == null) ? (this.other != null)
|
||||
: (!o.other.equals(this.other)))
|
||||
return false;
|
||||
if (this.i != o.i)
|
||||
return false;
|
||||
// the following test was not done before field 's' was added
|
||||
/*
|
||||
if ((o.s == null) ? (this.s != null)
|
||||
: (!o.s.equals(this.s)))
|
||||
return false;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TupleSerialFactoryTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.collections.test.serial;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.bind.serial.StoredClassCatalog;
|
||||
import com.sleepycat.bind.serial.test.MarshalledObject;
|
||||
import com.sleepycat.collections.TransactionRunner;
|
||||
import com.sleepycat.collections.TransactionWorker;
|
||||
import com.sleepycat.collections.TupleSerialFactory;
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.ForeignKeyDeleteAction;
|
||||
import com.sleepycat.db.SecondaryConfig;
|
||||
import com.sleepycat.db.SecondaryDatabase;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TupleSerialFactoryTest extends TestCase
|
||||
implements TransactionWorker {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
|
||||
for (int sorted = 0; sorted < 2; sorted += 1) {
|
||||
suite.addTest(new TupleSerialFactoryTest(TestEnv.ALL[i],
|
||||
sorted != 0));
|
||||
}
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private TestEnv testEnv;
|
||||
private Environment env;
|
||||
private StoredClassCatalog catalog;
|
||||
private TransactionRunner runner;
|
||||
private TupleSerialFactory factory;
|
||||
private Database store1;
|
||||
private Database store2;
|
||||
private SecondaryDatabase index1;
|
||||
private SecondaryDatabase index2;
|
||||
private boolean isSorted;
|
||||
private Map storeMap1;
|
||||
private Map storeMap2;
|
||||
private Map indexMap1;
|
||||
private Map indexMap2;
|
||||
|
||||
public TupleSerialFactoryTest(TestEnv testEnv, boolean isSorted) {
|
||||
|
||||
super(null);
|
||||
|
||||
this.testEnv = testEnv;
|
||||
this.isSorted = isSorted;
|
||||
|
||||
String name = "TupleSerialFactoryTest-" + testEnv.getName();
|
||||
name += isSorted ? "-sorted" : "-unsorted";
|
||||
setName(name);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
SharedTestUtils.printTestName(getName());
|
||||
env = testEnv.open(getName());
|
||||
runner = new TransactionRunner(env);
|
||||
|
||||
createDatabase();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
|
||||
try {
|
||||
if (index1 != null) {
|
||||
index1.close();
|
||||
}
|
||||
if (index2 != null) {
|
||||
index2.close();
|
||||
}
|
||||
if (store1 != null) {
|
||||
store1.close();
|
||||
}
|
||||
if (store2 != null) {
|
||||
store2.close();
|
||||
}
|
||||
if (catalog != null) {
|
||||
catalog.close();
|
||||
}
|
||||
if (env != null) {
|
||||
env.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Ignored exception during tearDown: " + e);
|
||||
} finally {
|
||||
/* Ensure that GC can cleanup. */
|
||||
index1 = null;
|
||||
index2 = null;
|
||||
store1 = null;
|
||||
store2 = null;
|
||||
catalog = null;
|
||||
env = null;
|
||||
testEnv = null;
|
||||
runner = null;
|
||||
factory = null;
|
||||
storeMap1 = null;
|
||||
storeMap2 = null;
|
||||
indexMap1 = null;
|
||||
indexMap2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Exception {
|
||||
|
||||
runner.run(this);
|
||||
}
|
||||
|
||||
public void doWork()
|
||||
throws Exception {
|
||||
|
||||
createViews();
|
||||
writeAndRead();
|
||||
}
|
||||
|
||||
private void createDatabase()
|
||||
throws Exception {
|
||||
|
||||
catalog = new StoredClassCatalog(openDb("catalog.db"));
|
||||
factory = new TupleSerialFactory(catalog);
|
||||
assertSame(catalog, factory.getCatalog());
|
||||
|
||||
store1 = openDb("store1.db");
|
||||
store2 = openDb("store2.db");
|
||||
index1 = openSecondaryDb(factory, "1", store1, "index1.db", null);
|
||||
index2 = openSecondaryDb(factory, "2", store2, "index2.db", store1);
|
||||
}
|
||||
|
||||
private Database openDb(String file)
|
||||
throws Exception {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setTransactional(testEnv.isTxnMode());
|
||||
config.setAllowCreate(true);
|
||||
DbCompat.setTypeBtree(config);
|
||||
|
||||
return DbCompat.testOpenDatabase(env, null, file, null, config);
|
||||
}
|
||||
|
||||
private SecondaryDatabase openSecondaryDb(TupleSerialFactory factory,
|
||||
String keyName,
|
||||
Database primary,
|
||||
String file,
|
||||
Database foreignStore)
|
||||
throws Exception {
|
||||
|
||||
SecondaryConfig secConfig = new SecondaryConfig();
|
||||
secConfig.setTransactional(testEnv.isTxnMode());
|
||||
secConfig.setAllowCreate(true);
|
||||
DbCompat.setTypeBtree(secConfig);
|
||||
secConfig.setKeyCreator(factory.getKeyCreator(MarshalledObject.class,
|
||||
keyName));
|
||||
if (foreignStore != null) {
|
||||
secConfig.setForeignKeyDatabase(foreignStore);
|
||||
secConfig.setForeignKeyDeleteAction(
|
||||
ForeignKeyDeleteAction.CASCADE);
|
||||
}
|
||||
|
||||
return DbCompat.testOpenSecondaryDatabase
|
||||
(env, null, file, null, primary, secConfig);
|
||||
}
|
||||
|
||||
private void createViews()
|
||||
throws Exception {
|
||||
|
||||
if (isSorted) {
|
||||
storeMap1 = factory.newSortedMap(store1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
storeMap2 = factory.newSortedMap(store2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap1 = factory.newSortedMap(index1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap2 = factory.newSortedMap(index2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
} else {
|
||||
storeMap1 = factory.newMap(store1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
storeMap2 = factory.newMap(store2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap1 = factory.newMap(index1, String.class,
|
||||
MarshalledObject.class, true);
|
||||
indexMap2 = factory.newMap(index2, String.class,
|
||||
MarshalledObject.class, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeAndRead()
|
||||
throws Exception {
|
||||
|
||||
MarshalledObject o1 = new MarshalledObject("data1", "pk1", "ik1", "");
|
||||
assertNull(storeMap1.put(null, o1));
|
||||
|
||||
assertEquals(o1, storeMap1.get("pk1"));
|
||||
assertEquals(o1, indexMap1.get("ik1"));
|
||||
|
||||
MarshalledObject o2 = new MarshalledObject("data2", "pk2", "", "pk1");
|
||||
assertNull(storeMap2.put(null, o2));
|
||||
|
||||
assertEquals(o2, storeMap2.get("pk2"));
|
||||
assertEquals(o2, indexMap2.get("pk1"));
|
||||
|
||||
/*
|
||||
* store1 contains o1 with primary key "pk1" and index key "ik1"
|
||||
* store2 contains o2 with primary key "pk2" and foreign key "pk1"
|
||||
* which is the primary key of store1
|
||||
*/
|
||||
|
||||
storeMap1.remove("pk1");
|
||||
assertNull(storeMap1.get("pk1"));
|
||||
assertNull(indexMap1.get("ik1"));
|
||||
assertNull(storeMap2.get("pk2"));
|
||||
assertNull(indexMap2.get("pk1"));
|
||||
}
|
||||
}
|
||||
2378
test/scr024/src/com/sleepycat/persist/test/BindingTest.java
Normal file
2378
test/scr024/src/com/sleepycat/persist/test/BindingTest.java
Normal file
File diff suppressed because it is too large
Load Diff
36
test/scr024/src/com/sleepycat/persist/test/Enhanced0.java
Normal file
36
test/scr024/src/com/sleepycat/persist/test/Enhanced0.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: Enhanced0.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
|
||||
/**
|
||||
* For running ASMifier -- before any enhancements.
|
||||
*/
|
||||
@Entity
|
||||
class Enhanced0 {
|
||||
|
||||
@PrimaryKey
|
||||
private String f1;
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private int f2;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private String f3;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private String f4;
|
||||
|
||||
private int f5;
|
||||
private String f6;
|
||||
private String f7;
|
||||
}
|
||||
252
test/scr024/src/com/sleepycat/persist/test/Enhanced1.java
Normal file
252
test/scr024/src/com/sleepycat/persist/test/Enhanced1.java
Normal file
@@ -0,0 +1,252 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: Enhanced1.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
|
||||
import com.sleepycat.persist.impl.Enhanced;
|
||||
import com.sleepycat.persist.impl.EnhancedAccessor;
|
||||
import com.sleepycat.persist.impl.EntityInput;
|
||||
import com.sleepycat.persist.impl.EntityOutput;
|
||||
import com.sleepycat.persist.impl.Format;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
|
||||
/**
|
||||
* For running ASMifier -- adds minimal enhancements.
|
||||
*/
|
||||
@Entity
|
||||
class Enhanced1 implements Enhanced {
|
||||
|
||||
@PrimaryKey
|
||||
private String f1;
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private int f2;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private String f3;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private String f4;
|
||||
|
||||
private int f5;
|
||||
private String f6;
|
||||
private String f7;
|
||||
private int f8;
|
||||
private int f9;
|
||||
private int f10;
|
||||
private int f11;
|
||||
private int f12;
|
||||
|
||||
static {
|
||||
EnhancedAccessor.registerClass(null, new Enhanced1());
|
||||
}
|
||||
|
||||
public Object bdbNewInstance() {
|
||||
return new Enhanced1();
|
||||
}
|
||||
|
||||
public Object bdbNewArray(int len) {
|
||||
return new Enhanced1[len];
|
||||
}
|
||||
|
||||
public boolean bdbIsPriKeyFieldNullOrZero() {
|
||||
return f1 == null;
|
||||
}
|
||||
|
||||
public void bdbWritePriKeyField(EntityOutput output, Format format) {
|
||||
output.writeKeyObject(f1, format);
|
||||
}
|
||||
|
||||
public void bdbReadPriKeyField(EntityInput input, Format format) {
|
||||
f1 = (String) input.readKeyObject(format);
|
||||
}
|
||||
|
||||
public void bdbWriteSecKeyFields(EntityOutput output) {
|
||||
/* If primary key is an object: */
|
||||
output.registerPriKeyObject(f1);
|
||||
/* Always: */
|
||||
output.writeInt(f2);
|
||||
output.writeObject(f3, null);
|
||||
output.writeObject(f4, null);
|
||||
}
|
||||
|
||||
public void bdbReadSecKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
/* If primary key is an object: */
|
||||
input.registerPriKeyObject(f1);
|
||||
|
||||
if (superLevel <= 0) {
|
||||
switch (startField) {
|
||||
case 0:
|
||||
f2 = input.readInt();
|
||||
if (endField == 0) break;
|
||||
case 1:
|
||||
f3 = (String) input.readObject();
|
||||
if (endField == 1) break;
|
||||
case 2:
|
||||
f4 = (String) input.readObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void bdbWriteNonKeyFields(EntityOutput output) {
|
||||
output.writeInt(f5);
|
||||
output.writeObject(f6, null);
|
||||
output.writeObject(f7, null);
|
||||
output.writeInt(f8);
|
||||
output.writeInt(f9);
|
||||
output.writeInt(f10);
|
||||
output.writeInt(f11);
|
||||
output.writeInt(f12);
|
||||
}
|
||||
|
||||
public void bdbReadNonKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
if (superLevel <= 0) {
|
||||
switch (startField) {
|
||||
case 0:
|
||||
f5 = input.readInt();
|
||||
if (endField == 0) break;
|
||||
case 1:
|
||||
f6 = (String) input.readObject();
|
||||
if (endField == 1) break;
|
||||
case 2:
|
||||
f7 = (String) input.readObject();
|
||||
if (endField == 2) break;
|
||||
case 3:
|
||||
f8 = input.readInt();
|
||||
if (endField == 3) break;
|
||||
case 4:
|
||||
f9 = input.readInt();
|
||||
if (endField == 4) break;
|
||||
case 5:
|
||||
f10 = input.readInt();
|
||||
if (endField == 5) break;
|
||||
case 6:
|
||||
f11 = input.readInt();
|
||||
if (endField == 6) break;
|
||||
case 7:
|
||||
f12 = input.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean bdbNullifyKeyField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object keyElement) {
|
||||
if (superLevel > 0) {
|
||||
return false;
|
||||
} else if (isSecField) {
|
||||
switch (field) {
|
||||
case 1:
|
||||
if (f3 != null) {
|
||||
f3 = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case 2:
|
||||
if (f4 != null) {
|
||||
f4 = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
switch (field) {
|
||||
case 1:
|
||||
if (f6 != null) {
|
||||
f6 = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case 2:
|
||||
if (f7 != null) {
|
||||
f7 = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object bdbGetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField) {
|
||||
if (superLevel > 0) {
|
||||
} else if (isSecField) {
|
||||
switch (field) {
|
||||
case 0:
|
||||
return Integer.valueOf(f2);
|
||||
case 1:
|
||||
return f3;
|
||||
case 2:
|
||||
return f4;
|
||||
}
|
||||
} else {
|
||||
switch (field) {
|
||||
case 0:
|
||||
return Integer.valueOf(f5);
|
||||
case 1:
|
||||
return f6;
|
||||
case 2:
|
||||
return f7;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void bdbSetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object value) {
|
||||
if (superLevel > 0) {
|
||||
} else if (isSecField) {
|
||||
switch (field) {
|
||||
case 0:
|
||||
f2 = ((Integer) value).intValue();
|
||||
return;
|
||||
case 1:
|
||||
f3 = (String) value;
|
||||
return;
|
||||
case 2:
|
||||
f4 = (String) value;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch (field) {
|
||||
case 0:
|
||||
f5 = ((Integer) value).intValue();
|
||||
return;
|
||||
case 1:
|
||||
f6 = (String) value;
|
||||
return;
|
||||
case 2:
|
||||
f7 = (String) value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
test/scr024/src/com/sleepycat/persist/test/Enhanced2.java
Normal file
110
test/scr024/src/com/sleepycat/persist/test/Enhanced2.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: Enhanced2.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import com.sleepycat.persist.impl.EnhancedAccessor;
|
||||
import com.sleepycat.persist.impl.EntityInput;
|
||||
import com.sleepycat.persist.impl.EntityOutput;
|
||||
import com.sleepycat.persist.impl.Format;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
|
||||
/**
|
||||
* For running ASMifier -- entity sublcass.
|
||||
*/
|
||||
@Persistent
|
||||
class Enhanced2 extends Enhanced1 {
|
||||
|
||||
static {
|
||||
EnhancedAccessor.registerClass(null, new Enhanced2());
|
||||
}
|
||||
|
||||
public Object bdbNewInstance() {
|
||||
return new Enhanced2();
|
||||
}
|
||||
|
||||
public Object bdbNewArray(int len) {
|
||||
return new Enhanced2[len];
|
||||
}
|
||||
|
||||
public boolean bdbIsPriKeyFieldNullOrZero() {
|
||||
return super.bdbIsPriKeyFieldNullOrZero();
|
||||
}
|
||||
|
||||
public void bdbWritePriKeyField(EntityOutput output, Format format) {
|
||||
super.bdbWritePriKeyField(output, format);
|
||||
}
|
||||
|
||||
public void bdbReadPriKeyField(EntityInput input, Format format) {
|
||||
super.bdbReadPriKeyField(input, format);
|
||||
}
|
||||
|
||||
public void bdbWriteSecKeyFields(EntityOutput output) {
|
||||
super.bdbWriteSecKeyFields(output);
|
||||
}
|
||||
|
||||
public void bdbReadSecKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
if (superLevel != 0) {
|
||||
super.bdbReadSecKeyFields
|
||||
(input, startField, endField, superLevel - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void bdbWriteNonKeyFields(EntityOutput output) {
|
||||
super.bdbWriteNonKeyFields(output);
|
||||
}
|
||||
|
||||
public void bdbReadNonKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
if (superLevel != 0) {
|
||||
super.bdbReadNonKeyFields
|
||||
(input, startField, endField, superLevel - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean bdbNullifyKeyField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object keyElement) {
|
||||
if (superLevel > 0) {
|
||||
return super.bdbNullifyKeyField
|
||||
(o, field, superLevel - 1, isSecField, keyElement);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Object bdbGetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField) {
|
||||
if (superLevel > 0) {
|
||||
return super.bdbGetField
|
||||
(o, field, superLevel - 1, isSecField);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void bdbSetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object value) {
|
||||
if (superLevel > 0) {
|
||||
super.bdbSetField
|
||||
(o, field, superLevel - 1, isSecField, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
test/scr024/src/com/sleepycat/persist/test/Enhanced3.java
Normal file
161
test/scr024/src/com/sleepycat/persist/test/Enhanced3.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: Enhanced3.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
/*
|
||||
import java.math.BigIngeter;
|
||||
import java.math.BigDecimal;
|
||||
*/
|
||||
import java.util.Date;
|
||||
|
||||
import com.sleepycat.persist.impl.Enhanced;
|
||||
import com.sleepycat.persist.impl.EnhancedAccessor;
|
||||
import com.sleepycat.persist.impl.EntityInput;
|
||||
import com.sleepycat.persist.impl.EntityOutput;
|
||||
import com.sleepycat.persist.impl.Format;
|
||||
import com.sleepycat.persist.model.KeyField;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
|
||||
/**
|
||||
* For running ASMifier -- a composite key class using all simple data types,
|
||||
* does not follow from previous EnhancedN.java files
|
||||
*/
|
||||
@Persistent
|
||||
class Enhanced3 implements Enhanced {
|
||||
|
||||
@KeyField(1) boolean z;
|
||||
@KeyField(2) char c;
|
||||
@KeyField(3) byte b;
|
||||
@KeyField(4) short s;
|
||||
@KeyField(5) int i;
|
||||
@KeyField(6) long l;
|
||||
@KeyField(7) float f;
|
||||
@KeyField(8) double d;
|
||||
|
||||
@KeyField(9) Boolean zw;
|
||||
@KeyField(10) Character cw;
|
||||
@KeyField(11) Byte bw;
|
||||
@KeyField(12) Short sw;
|
||||
@KeyField(13) Integer iw;
|
||||
@KeyField(14) Long lw;
|
||||
@KeyField(15) Float fw;
|
||||
@KeyField(16) Double dw;
|
||||
|
||||
@KeyField(17) Date date;
|
||||
@KeyField(18) String str;
|
||||
/*
|
||||
@KeyField(19) BigIngeter bigint;
|
||||
@KeyField(20) BigDecimal bigdec;
|
||||
*/
|
||||
|
||||
static {
|
||||
EnhancedAccessor.registerClass(null, new Enhanced3());
|
||||
}
|
||||
|
||||
public Object bdbNewInstance() {
|
||||
return new Enhanced3();
|
||||
}
|
||||
|
||||
public Object bdbNewArray(int len) {
|
||||
return new Enhanced3[len];
|
||||
}
|
||||
|
||||
public boolean bdbIsPriKeyFieldNullOrZero() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void bdbWritePriKeyField(EntityOutput output, Format format) {
|
||||
}
|
||||
|
||||
public void bdbReadPriKeyField(EntityInput input, Format format) {
|
||||
}
|
||||
|
||||
public void bdbWriteSecKeyFields(EntityOutput output) {
|
||||
}
|
||||
|
||||
public void bdbReadSecKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
}
|
||||
|
||||
public void bdbWriteNonKeyFields(EntityOutput output) {
|
||||
output.writeBoolean(z);
|
||||
output.writeChar(c);
|
||||
output.writeByte(b);
|
||||
output.writeShort(s);
|
||||
output.writeInt(i);
|
||||
output.writeLong(l);
|
||||
output.writeSortedFloat(f);
|
||||
output.writeSortedDouble(d);
|
||||
|
||||
output.writeBoolean(zw.booleanValue());
|
||||
output.writeChar(cw.charValue());
|
||||
output.writeByte(bw.byteValue());
|
||||
output.writeShort(sw.shortValue());
|
||||
output.writeInt(iw.intValue());
|
||||
output.writeLong(lw.longValue());
|
||||
output.writeSortedFloat(fw.floatValue());
|
||||
output.writeSortedDouble(dw.doubleValue());
|
||||
|
||||
output.writeLong(date.getTime());
|
||||
output.writeString(str);
|
||||
}
|
||||
|
||||
public void bdbReadNonKeyFields(EntityInput input,
|
||||
int startField,
|
||||
int endField,
|
||||
int superLevel) {
|
||||
z = input.readBoolean();
|
||||
c = input.readChar();
|
||||
b = input.readByte();
|
||||
s = input.readShort();
|
||||
i = input.readInt();
|
||||
l = input.readLong();
|
||||
f = input.readSortedFloat();
|
||||
d = input.readSortedDouble();
|
||||
|
||||
zw = Boolean.valueOf(input.readBoolean());
|
||||
cw = Character.valueOf(input.readChar());
|
||||
bw = Byte.valueOf(input.readByte());
|
||||
sw = Short.valueOf(input.readShort());
|
||||
iw = Integer.valueOf(input.readInt());
|
||||
lw = Long.valueOf(input.readLong());
|
||||
fw = Float.valueOf(input.readSortedFloat());
|
||||
dw = Double.valueOf(input.readSortedDouble());
|
||||
|
||||
date = new Date(input.readLong());
|
||||
str = input.readString();
|
||||
}
|
||||
|
||||
public boolean bdbNullifyKeyField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object keyElement) {
|
||||
// Didn't bother with this one.
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object bdbGetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField) {
|
||||
// Didn't bother with this one.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void bdbSetField(Object o,
|
||||
int field,
|
||||
int superLevel,
|
||||
boolean isSecField,
|
||||
Object value) {
|
||||
// Didn't bother with this one.
|
||||
}
|
||||
}
|
||||
193
test/scr024/src/com/sleepycat/persist/test/EvolveCase.java
Normal file
193
test/scr024/src/com/sleepycat/persist/test/EvolveCase.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: EvolveCase.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.evolve.Mutations;
|
||||
import com.sleepycat.persist.model.ClassMetadata;
|
||||
import com.sleepycat.persist.model.EntityModel;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.raw.RawStore;
|
||||
import com.sleepycat.persist.raw.RawType;
|
||||
|
||||
@Persistent
|
||||
abstract class EvolveCase {
|
||||
|
||||
static final String STORE_NAME = "foo";
|
||||
|
||||
transient boolean updated;
|
||||
|
||||
Mutations getMutations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void configure(EntityModel model, StoreConfig config) {
|
||||
}
|
||||
|
||||
String getStoreOpenException() {
|
||||
return null;
|
||||
}
|
||||
|
||||
int getNRecordsExpected() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void checkUnevolvedModel(EntityModel model, Environment env) {
|
||||
}
|
||||
|
||||
void checkEvolvedModel(EntityModel model,
|
||||
Environment env,
|
||||
boolean oldTypesExist) {
|
||||
}
|
||||
|
||||
void writeObjects(EntityStore store)
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
void readObjects(EntityStore store, boolean doUpdate)
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
void readRawObjects(RawStore store,
|
||||
boolean expectEvolved,
|
||||
boolean expectUpdated)
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
void copyRawObjects(RawStore rawStore, EntityStore newStore)
|
||||
throws DatabaseException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for equality and prints the entire values rather than
|
||||
* abbreviated values like TestCase.assertEquals does.
|
||||
*/
|
||||
static void checkEquals(Object expected, Object got) {
|
||||
if ((expected != null) ? (!expected.equals(got)) : (got != null)) {
|
||||
TestCase.fail("Expected:\n" + expected + "\nBut got:\n" + got);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts than an entity database exists or does not exist.
|
||||
*/
|
||||
static void assertDbExists(boolean expectExists,
|
||||
Environment env,
|
||||
String entityClassName) {
|
||||
assertDbExists(expectExists, env, entityClassName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that an entity class exists or does not exist.
|
||||
*/
|
||||
static void checkEntity(boolean exists,
|
||||
EntityModel model,
|
||||
Environment env,
|
||||
String className,
|
||||
int version,
|
||||
String secKeyName) {
|
||||
if (exists) {
|
||||
TestCase.assertNotNull(model.getEntityMetadata(className));
|
||||
ClassMetadata meta = model.getClassMetadata(className);
|
||||
TestCase.assertNotNull(meta);
|
||||
TestCase.assertEquals(version, meta.getVersion());
|
||||
TestCase.assertTrue(meta.isEntityClass());
|
||||
|
||||
RawType raw = model.getRawType(className);
|
||||
TestCase.assertNotNull(raw);
|
||||
TestCase.assertEquals(version, raw.getVersion());
|
||||
} else {
|
||||
TestCase.assertNull(model.getEntityMetadata(className));
|
||||
TestCase.assertNull(model.getClassMetadata(className));
|
||||
TestCase.assertNull(model.getRawType(className));
|
||||
}
|
||||
|
||||
assertDbExists(exists, env, className);
|
||||
if (secKeyName != null) {
|
||||
assertDbExists(exists, env, className, secKeyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a non-entity class exists or does not exist.
|
||||
*/
|
||||
static void checkNonEntity(boolean exists,
|
||||
EntityModel model,
|
||||
Environment env,
|
||||
String className,
|
||||
int version) {
|
||||
if (exists) {
|
||||
ClassMetadata meta = model.getClassMetadata(className);
|
||||
TestCase.assertNotNull(meta);
|
||||
TestCase.assertEquals(version, meta.getVersion());
|
||||
TestCase.assertTrue(!meta.isEntityClass());
|
||||
|
||||
RawType raw = model.getRawType(className);
|
||||
TestCase.assertNotNull(raw);
|
||||
TestCase.assertEquals(version, raw.getVersion());
|
||||
} else {
|
||||
TestCase.assertNull(model.getClassMetadata(className));
|
||||
TestCase.assertNull(model.getRawType(className));
|
||||
}
|
||||
|
||||
TestCase.assertNull(model.getEntityMetadata(className));
|
||||
assertDbExists(false, env, className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts than a database expectExists or does not exist. If keyName is
|
||||
* null, checks an entity database. If keyName is non-null, checks a
|
||||
* secondary database.
|
||||
*/
|
||||
static void assertDbExists(boolean expectExists,
|
||||
Environment env,
|
||||
String entityClassName,
|
||||
String keyName) {
|
||||
PersistTestUtils.assertDbExists
|
||||
(expectExists, env, STORE_NAME, entityClassName, keyName);
|
||||
}
|
||||
|
||||
static void checkVersions(EntityModel model, String name, int version) {
|
||||
checkVersions(model, new String[] {name}, new int[] {version});
|
||||
}
|
||||
|
||||
static void checkVersions(EntityModel model,
|
||||
String name1,
|
||||
int version1,
|
||||
String name2,
|
||||
int version2) {
|
||||
checkVersions
|
||||
(model, new String[] {name1, name2},
|
||||
new int[] {version1, version2});
|
||||
}
|
||||
|
||||
private static void checkVersions(EntityModel model,
|
||||
String[] names,
|
||||
int[] versions) {
|
||||
List<RawType> all = model.getAllRawTypeVersions(names[0]);
|
||||
TestCase.assertNotNull(all);
|
||||
|
||||
assert names.length == versions.length;
|
||||
TestCase.assertEquals(names.length, all.size());
|
||||
|
||||
Iterator<RawType> iter = all.iterator();
|
||||
for (int i = 0; i < names.length; i += 1) {
|
||||
RawType type = iter.next();
|
||||
TestCase.assertEquals(versions[i], type.getVersion());
|
||||
TestCase.assertEquals(names[i], type.getClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
6115
test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java
Normal file
6115
test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
235
test/scr024/src/com/sleepycat/persist/test/EvolveTest.java
Normal file
235
test/scr024/src/com/sleepycat/persist/test/EvolveTest.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: EvolveTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.persist.evolve.EvolveConfig;
|
||||
import com.sleepycat.persist.evolve.EvolveEvent;
|
||||
import com.sleepycat.persist.evolve.EvolveListener;
|
||||
import com.sleepycat.persist.evolve.EvolveStats;
|
||||
import com.sleepycat.persist.impl.PersistCatalog;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* Runs part two of the EvolveTest. This part is run with the new/updated
|
||||
* version of EvolveClasses in the classpath. It uses the environment and
|
||||
* store created by EvolveTestInit. It verifies that it can read/write/evolve
|
||||
* objects serialized using the old class format, and that it can create new
|
||||
* objects with the new class format.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class EvolveTest extends EvolveTestBase {
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
return getSuite(EvolveTest.class);
|
||||
}
|
||||
|
||||
private int evolveNRead;
|
||||
private int evolveNConverted;
|
||||
|
||||
boolean useEvolvedClass() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
throws IOException {
|
||||
|
||||
/* Copy the log files created by EvolveTestInit. */
|
||||
envHome = getTestInitHome(true /*evolved*/);
|
||||
envHome.mkdirs();
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
SharedTestUtils.copyFiles(getTestInitHome(false /*evolved*/), envHome);
|
||||
}
|
||||
|
||||
public void testLazyEvolve()
|
||||
throws Exception {
|
||||
|
||||
openEnv();
|
||||
|
||||
/*
|
||||
* Open in raw mode to check unevolved raw object and formats. This
|
||||
* is possible whether or not we can open the store further below to
|
||||
* evolve formats without errors.
|
||||
*/
|
||||
openRawStore();
|
||||
caseObj.checkUnevolvedModel(rawStore.getModel(), env);
|
||||
caseObj.readRawObjects
|
||||
(rawStore, false /*expectEvolved*/, false /*expectUpdated*/);
|
||||
closeRawStore();
|
||||
|
||||
if (openStoreReadWrite()) {
|
||||
|
||||
/*
|
||||
* When opening read-write, formats are evolved lazily. Check by
|
||||
* reading evolved objects.
|
||||
*/
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readObjects(store, false /*doUpdate*/);
|
||||
closeStore();
|
||||
|
||||
/*
|
||||
* Read raw objects again to check that the evolved objects are
|
||||
* returned even though the stored objects were not evolved.
|
||||
*/
|
||||
openRawStore();
|
||||
caseObj.checkEvolvedModel
|
||||
(rawStore.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readRawObjects
|
||||
(rawStore, true /*expectEvolved*/, false /*expectUpdated*/);
|
||||
closeRawStore();
|
||||
|
||||
/*
|
||||
* Open read-only to ensure that the catalog does not need to
|
||||
* change (evolve formats) unnecessarily.
|
||||
*/
|
||||
PersistCatalog.expectNoClassChanges = true;
|
||||
try {
|
||||
openStoreReadOnly();
|
||||
} finally {
|
||||
PersistCatalog.expectNoClassChanges = false;
|
||||
}
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readObjects(store, false /*doUpdate*/);
|
||||
closeStore();
|
||||
|
||||
/*
|
||||
* Open read-write to update objects and store them in evolved
|
||||
* format.
|
||||
*/
|
||||
openStoreReadWrite();
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readObjects(store, true /*doUpdate*/);
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
closeStore();
|
||||
|
||||
/*
|
||||
* Check raw objects again after the evolved objects were stored.
|
||||
*/
|
||||
openRawStore();
|
||||
caseObj.checkEvolvedModel
|
||||
(rawStore.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readRawObjects
|
||||
(rawStore, true /*expectEvolved*/, true /*expectUpdated*/);
|
||||
closeRawStore();
|
||||
}
|
||||
|
||||
closeAll();
|
||||
}
|
||||
|
||||
public void testEagerEvolve()
|
||||
throws Exception {
|
||||
|
||||
/* If the store cannot be opened, this test is not appropriate. */
|
||||
if (caseObj.getStoreOpenException() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EvolveConfig config = new EvolveConfig();
|
||||
config.setEvolveListener(new EvolveListener() {
|
||||
public boolean evolveProgress(EvolveEvent event) {
|
||||
EvolveStats stats = event.getStats();
|
||||
evolveNRead = stats.getNRead();
|
||||
evolveNConverted = stats.getNConverted();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
openEnv();
|
||||
|
||||
openStoreReadWrite();
|
||||
|
||||
/*
|
||||
* Evolve and expect that the expected number of entities are
|
||||
* converted.
|
||||
*/
|
||||
int nExpected = caseObj.getNRecordsExpected();
|
||||
evolveNRead = 0;
|
||||
evolveNConverted = 0;
|
||||
PersistCatalog.unevolvedFormatsEncountered = false;
|
||||
EvolveStats stats = store.evolve(config);
|
||||
if (nExpected > 0) {
|
||||
assertTrue(PersistCatalog.unevolvedFormatsEncountered);
|
||||
}
|
||||
assertTrue(evolveNRead == nExpected);
|
||||
assertTrue(evolveNConverted == nExpected);
|
||||
assertTrue(evolveNConverted >= evolveNRead);
|
||||
assertEquals(evolveNRead, stats.getNRead());
|
||||
assertEquals(evolveNConverted, stats.getNConverted());
|
||||
|
||||
/* Evolve again and expect that no entities are converted. */
|
||||
evolveNRead = 0;
|
||||
evolveNConverted = 0;
|
||||
PersistCatalog.unevolvedFormatsEncountered = false;
|
||||
stats = store.evolve(config);
|
||||
assertTrue(!PersistCatalog.unevolvedFormatsEncountered);
|
||||
assertTrue(evolveNRead == 0);
|
||||
assertTrue(evolveNConverted == 0);
|
||||
assertEquals(0, stats.getNRead());
|
||||
assertEquals(0, stats.getNConverted());
|
||||
|
||||
/* Ensure that we can read all entities without evolution. */
|
||||
PersistCatalog.unevolvedFormatsEncountered = false;
|
||||
caseObj.readObjects(store, false /*doUpdate*/);
|
||||
assertTrue(!PersistCatalog.unevolvedFormatsEncountered);
|
||||
|
||||
/*
|
||||
* When automatic unused type deletion is implemented in the future the
|
||||
* oldTypesExist parameters below should be changed to false.
|
||||
*/
|
||||
|
||||
/* Open again and try an update. */
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readObjects(store, true /*doUpdate*/);
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
closeStore();
|
||||
|
||||
/* Open read-only and double check that everything is OK. */
|
||||
openStoreReadOnly();
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readObjects(store, false /*doUpdate*/);
|
||||
caseObj.checkEvolvedModel
|
||||
(store.getModel(), env, true /*oldTypesExist*/);
|
||||
closeStore();
|
||||
|
||||
/* Check raw objects. */
|
||||
openRawStore();
|
||||
caseObj.checkEvolvedModel
|
||||
(rawStore.getModel(), env, true /*oldTypesExist*/);
|
||||
caseObj.readRawObjects
|
||||
(rawStore, true /*expectEvolved*/, true /*expectUpdated*/);
|
||||
|
||||
/*
|
||||
* Test copy raw object to new store via convertRawObject. In this
|
||||
* test we can pass false for oldTypesExist because newStore starts
|
||||
* with the new/evolved class model.
|
||||
*/
|
||||
openNewStore();
|
||||
caseObj.copyRawObjects(rawStore, newStore);
|
||||
caseObj.readObjects(newStore, true /*doUpdate*/);
|
||||
caseObj.checkEvolvedModel
|
||||
(newStore.getModel(), env, false /*oldTypesExist*/);
|
||||
closeNewStore();
|
||||
closeRawStore();
|
||||
|
||||
closeAll();
|
||||
}
|
||||
}
|
||||
420
test/scr024/src/com/sleepycat/persist/test/EvolveTestBase.java
Normal file
420
test/scr024/src/com/sleepycat/persist/test/EvolveTestBase.java
Normal file
@@ -0,0 +1,420 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: EvolveTestBase.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.AnnotationModel;
|
||||
import com.sleepycat.persist.model.EntityModel;
|
||||
import com.sleepycat.persist.raw.RawStore;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* Base class for EvolveTest and EvolveTestInit.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public abstract class EvolveTestBase extends TestCase {
|
||||
|
||||
/*
|
||||
* When adding a evolve test class, three places need to be changed:
|
||||
* 1) Add the unmodified class to EvolveClass.java.original.
|
||||
* 2) Add the modified class to EvolveClass.java.
|
||||
* 3) Add the class name to the ALL list below as a pair of strings. The
|
||||
* first string in each pair is the name of the original class, and the
|
||||
* second string is the name of the evolved class or null if the evolved
|
||||
* name is the same as the original. The index in the list identifies a
|
||||
* test case, and the class at that position identifies the old and new
|
||||
* class to use for the test.
|
||||
*/
|
||||
private static final String[] ALL = {
|
||||
"DeletedEntity1_ClassRemoved",
|
||||
"DeletedEntity1_ClassRemoved_NoMutation",
|
||||
"DeletedEntity2_ClassRemoved",
|
||||
"DeletedEntity2_ClassRemoved_WithDeleter",
|
||||
"DeletedEntity3_AnnotRemoved_NoMutation",
|
||||
null,
|
||||
"DeletedEntity4_AnnotRemoved_WithDeleter",
|
||||
null,
|
||||
"DeletedEntity5_EntityToPersist_NoMutation",
|
||||
null,
|
||||
"DeletedEntity6_EntityToPersist_WithDeleter",
|
||||
null,
|
||||
"DeletedPersist1_ClassRemoved_NoMutation",
|
||||
null,
|
||||
"DeletedPersist2_ClassRemoved_WithDeleter",
|
||||
null,
|
||||
"DeletedPersist3_AnnotRemoved_NoMutation",
|
||||
null,
|
||||
"DeletedPersist4_AnnotRemoved_WithDeleter",
|
||||
null,
|
||||
"DeletedPersist5_PersistToEntity_NoMutation",
|
||||
null,
|
||||
"DeletedPersist6_PersistToEntity_WithDeleter",
|
||||
null,
|
||||
"RenamedEntity1_NewEntityName",
|
||||
"RenamedEntity1_NewEntityName_NoMutation",
|
||||
"RenamedEntity2_NewEntityName",
|
||||
"RenamedEntity2_NewEntityName_WithRenamer",
|
||||
"DeleteSuperclass1_NoMutation",
|
||||
null,
|
||||
"DeleteSuperclass2_WithConverter",
|
||||
null,
|
||||
"DeleteSuperclass3_WithDeleter",
|
||||
null,
|
||||
"DeleteSuperclass4_NoFields",
|
||||
null,
|
||||
"DeleteSuperclass5_Top",
|
||||
null,
|
||||
"InsertSuperclass1_Between",
|
||||
null,
|
||||
"InsertSuperclass2_Top",
|
||||
null,
|
||||
"DisallowNonKeyField_PrimitiveToObject",
|
||||
null,
|
||||
"DisallowNonKeyField_ObjectToPrimitive",
|
||||
null,
|
||||
"DisallowNonKeyField_ObjectToSubtype",
|
||||
null,
|
||||
"DisallowNonKeyField_ObjectToUnrelatedSimple",
|
||||
null,
|
||||
"DisallowNonKeyField_ObjectToUnrelatedOther",
|
||||
null,
|
||||
"DisallowNonKeyField_byte2boolean",
|
||||
null,
|
||||
"DisallowNonKeyField_short2byte",
|
||||
null,
|
||||
"DisallowNonKeyField_int2short",
|
||||
null,
|
||||
"DisallowNonKeyField_long2int",
|
||||
null,
|
||||
"DisallowNonKeyField_float2long",
|
||||
null,
|
||||
"DisallowNonKeyField_double2float",
|
||||
null,
|
||||
"DisallowNonKeyField_Byte2byte",
|
||||
null,
|
||||
"DisallowNonKeyField_Character2char",
|
||||
null,
|
||||
"DisallowNonKeyField_Short2short",
|
||||
null,
|
||||
"DisallowNonKeyField_Integer2int",
|
||||
null,
|
||||
"DisallowNonKeyField_Long2long",
|
||||
null,
|
||||
"DisallowNonKeyField_Float2float",
|
||||
null,
|
||||
"DisallowNonKeyField_Double2double",
|
||||
null,
|
||||
"DisallowNonKeyField_float2BigInt",
|
||||
null,
|
||||
"DisallowNonKeyField_BigInt2long",
|
||||
null,
|
||||
"DisallowSecKeyField_byte2short",
|
||||
null,
|
||||
"DisallowSecKeyField_char2int",
|
||||
null,
|
||||
"DisallowSecKeyField_short2int",
|
||||
null,
|
||||
"DisallowSecKeyField_int2long",
|
||||
null,
|
||||
"DisallowSecKeyField_long2float",
|
||||
null,
|
||||
"DisallowSecKeyField_float2double",
|
||||
null,
|
||||
"DisallowSecKeyField_Byte2short2",
|
||||
null,
|
||||
"DisallowSecKeyField_Character2int",
|
||||
null,
|
||||
"DisallowSecKeyField_Short2int2",
|
||||
null,
|
||||
"DisallowSecKeyField_Integer2long",
|
||||
null,
|
||||
"DisallowSecKeyField_Long2float2",
|
||||
null,
|
||||
"DisallowSecKeyField_Float2double2",
|
||||
null,
|
||||
"DisallowSecKeyField_int2BigInt",
|
||||
null,
|
||||
"DisallowPriKeyField_byte2short",
|
||||
null,
|
||||
"DisallowPriKeyField_char2int",
|
||||
null,
|
||||
"DisallowPriKeyField_short2int",
|
||||
null,
|
||||
"DisallowPriKeyField_int2long",
|
||||
null,
|
||||
"DisallowPriKeyField_long2float",
|
||||
null,
|
||||
"DisallowPriKeyField_float2double",
|
||||
null,
|
||||
"DisallowPriKeyField_Byte2short2",
|
||||
null,
|
||||
"DisallowPriKeyField_Character2int",
|
||||
null,
|
||||
"DisallowPriKeyField_Short2int2",
|
||||
null,
|
||||
"DisallowPriKeyField_Integer2long",
|
||||
null,
|
||||
"DisallowPriKeyField_Long2float2",
|
||||
null,
|
||||
"DisallowPriKeyField_Float2double2",
|
||||
null,
|
||||
"DisallowPriKeyField_Long2BigInt",
|
||||
null,
|
||||
"DisallowCompositeKeyField_byte2short",
|
||||
null,
|
||||
"AllowPriKeyField_Byte2byte2",
|
||||
null,
|
||||
"AllowPriKeyField_byte2Byte",
|
||||
null,
|
||||
"AllowFieldTypeChanges",
|
||||
null,
|
||||
"ConvertExample1_Entity",
|
||||
null,
|
||||
"ConvertExample2_Person",
|
||||
null,
|
||||
"ConvertExample3_Person",
|
||||
null,
|
||||
"ConvertExample4_Entity",
|
||||
null,
|
||||
"ConvertExample5_Entity",
|
||||
null,
|
||||
"AllowFieldAddDelete",
|
||||
null,
|
||||
"ProxiedClass_Entity",
|
||||
null,
|
||||
"DisallowChangeProxyFor",
|
||||
null,
|
||||
"DisallowDeleteProxyFor",
|
||||
null,
|
||||
"ArrayNameChange_Entity",
|
||||
null,
|
||||
"AddEnumConstant_Entity",
|
||||
null,
|
||||
"DeleteEnumConstant_NoMutation",
|
||||
null,
|
||||
"DisallowChangeKeyRelate",
|
||||
null,
|
||||
"AllowChangeKeyMetadata",
|
||||
null,
|
||||
"AllowAddSecondary",
|
||||
null,
|
||||
"FieldAddAndConvert",
|
||||
null,
|
||||
};
|
||||
|
||||
File envHome;
|
||||
Environment env;
|
||||
EntityStore store;
|
||||
RawStore rawStore;
|
||||
EntityStore newStore;
|
||||
String caseClsName;
|
||||
Class caseCls;
|
||||
EvolveCase caseObj;
|
||||
String caseLabel;
|
||||
|
||||
static TestSuite getSuite(Class testClass)
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < ALL.length; i += 2) {
|
||||
String originalClsName = ALL[i];
|
||||
String evolvedClsName = ALL[i + 1];
|
||||
if (evolvedClsName == null) {
|
||||
evolvedClsName = originalClsName;
|
||||
}
|
||||
TestSuite baseSuite = new TestSuite(testClass);
|
||||
Enumeration e = baseSuite.tests();
|
||||
while (e.hasMoreElements()) {
|
||||
EvolveTestBase test = (EvolveTestBase) e.nextElement();
|
||||
test.init(originalClsName, evolvedClsName);
|
||||
suite.addTest(test);
|
||||
}
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private void init(String originalClsName,
|
||||
String evolvedClsName)
|
||||
throws Exception {
|
||||
|
||||
String caseClsName = useEvolvedClass() ?
|
||||
evolvedClsName : originalClsName;
|
||||
caseClsName = "com.sleepycat.persist.test.EvolveClasses$" +
|
||||
caseClsName;
|
||||
|
||||
this.caseClsName = caseClsName;
|
||||
this.caseCls = Class.forName(caseClsName);
|
||||
this.caseObj = (EvolveCase) caseCls.newInstance();
|
||||
this.caseLabel = evolvedClsName;
|
||||
}
|
||||
|
||||
abstract boolean useEvolvedClass();
|
||||
|
||||
File getTestInitHome(boolean evolved) {
|
||||
return new File
|
||||
(System.getProperty("testevolvedir"),
|
||||
(evolved ? "evolved" : "original") + '/' + caseLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
|
||||
/* Set test name for reporting; cannot be done in the ctor or setUp. */
|
||||
setName(caseLabel + '-' + getName());
|
||||
|
||||
if (env != null) {
|
||||
try {
|
||||
closeAll();
|
||||
} catch (Throwable e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
}
|
||||
envHome = null;
|
||||
env = null;
|
||||
store = null;
|
||||
caseCls = null;
|
||||
caseObj = null;
|
||||
caseLabel = null;
|
||||
|
||||
/* Do not delete log files so they can be used by 2nd phase of test. */
|
||||
}
|
||||
|
||||
void openEnv()
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
EnvironmentConfig config = TestEnv.TXN.getConfig();
|
||||
config.setAllowCreate(true);
|
||||
env = new Environment(envHome, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the store was opened successfully. Returns false if the
|
||||
* store could not be opened because an exception was expected -- this is
|
||||
* not a test failure but no further tests for an EntityStore may be run.
|
||||
*/
|
||||
private boolean openStore(StoreConfig config)
|
||||
throws Exception {
|
||||
|
||||
config.setTransactional(true);
|
||||
config.setMutations(caseObj.getMutations());
|
||||
|
||||
EntityModel model = new AnnotationModel();
|
||||
config.setModel(model);
|
||||
caseObj.configure(model, config);
|
||||
|
||||
String expectException = caseObj.getStoreOpenException();
|
||||
try {
|
||||
store = new EntityStore(env, EvolveCase.STORE_NAME, config);
|
||||
if (expectException != null) {
|
||||
fail("Expected: " + expectException);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (expectException != null) {
|
||||
//e.printStackTrace();
|
||||
EvolveCase.checkEquals(expectException, e.toString());
|
||||
return false;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean openStoreReadOnly()
|
||||
throws Exception {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setReadOnly(true);
|
||||
return openStore(config);
|
||||
}
|
||||
|
||||
boolean openStoreReadWrite()
|
||||
throws Exception {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(true);
|
||||
return openStore(config);
|
||||
}
|
||||
|
||||
void openRawStore()
|
||||
throws DatabaseException {
|
||||
|
||||
rawStore = new RawStore(env, EvolveCase.STORE_NAME, null);
|
||||
}
|
||||
|
||||
void closeStore()
|
||||
throws DatabaseException {
|
||||
|
||||
if (store != null) {
|
||||
store.close();
|
||||
store = null;
|
||||
}
|
||||
}
|
||||
|
||||
void openNewStore()
|
||||
throws Exception {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(true);
|
||||
config.setTransactional(true);
|
||||
|
||||
EntityModel model = new AnnotationModel();
|
||||
config.setModel(model);
|
||||
caseObj.configure(model, config);
|
||||
|
||||
newStore = new EntityStore(env, "new", config);
|
||||
}
|
||||
|
||||
void closeNewStore()
|
||||
throws DatabaseException {
|
||||
|
||||
if (newStore != null) {
|
||||
newStore.close();
|
||||
newStore = null;
|
||||
}
|
||||
}
|
||||
|
||||
void closeRawStore()
|
||||
throws DatabaseException {
|
||||
|
||||
if (rawStore != null) {
|
||||
rawStore.close();
|
||||
rawStore = null;
|
||||
}
|
||||
}
|
||||
|
||||
void closeEnv()
|
||||
throws DatabaseException {
|
||||
|
||||
if (env != null) {
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
}
|
||||
|
||||
void closeAll()
|
||||
throws DatabaseException {
|
||||
|
||||
closeStore();
|
||||
closeRawStore();
|
||||
closeNewStore();
|
||||
closeEnv();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: EvolveTestInit.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* Runs part one of the EvolveTest. This part is run with the old/original
|
||||
* version of EvolveClasses in the classpath. It creates a fresh environment
|
||||
* and store containing instances of the original class. When EvolveTest is
|
||||
* run, it will read/write/evolve these objects from the store created here.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class EvolveTestInit extends EvolveTestBase {
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
return getSuite(EvolveTestInit.class);
|
||||
}
|
||||
|
||||
boolean useEvolvedClass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
throws IOException {
|
||||
|
||||
envHome = getTestInitHome(false /*evolved*/);
|
||||
envHome.mkdirs();
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
}
|
||||
|
||||
public void testInit()
|
||||
throws Exception {
|
||||
|
||||
openEnv();
|
||||
if (!openStoreReadWrite()) {
|
||||
fail();
|
||||
}
|
||||
caseObj.writeObjects(store);
|
||||
caseObj.checkUnevolvedModel(store.getModel(), env);
|
||||
closeAll();
|
||||
}
|
||||
}
|
||||
324
test/scr024/src/com/sleepycat/persist/test/ForeignKeyTest.java
Normal file
324
test/scr024/src/com/sleepycat/persist/test/ForeignKeyTest.java
Normal file
@@ -0,0 +1,324 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ForeignKeyTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.DeleteAction.ABORT;
|
||||
import static com.sleepycat.persist.model.DeleteAction.CASCADE;
|
||||
import static com.sleepycat.persist.model.DeleteAction.NULLIFY;
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.SecondaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.DeleteAction;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.util.test.TxnTestCase;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class ForeignKeyTest extends TxnTestCase {
|
||||
|
||||
private static final DeleteAction[] ACTIONS = {
|
||||
ABORT,
|
||||
NULLIFY,
|
||||
CASCADE,
|
||||
};
|
||||
|
||||
private static final String[] ACTION_LABELS = {
|
||||
"ABORT",
|
||||
"NULLIFY",
|
||||
"CASCADE",
|
||||
};
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < ACTIONS.length; i += 1) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
TestSuite txnSuite = txnTestSuite
|
||||
(ForeignKeyTest.class, null, null);
|
||||
Enumeration e = txnSuite.tests();
|
||||
while (e.hasMoreElements()) {
|
||||
ForeignKeyTest test = (ForeignKeyTest) e.nextElement();
|
||||
test.onDelete = ACTIONS[i];
|
||||
test.onDeleteLabel = ACTION_LABELS[i];
|
||||
test.useSubclass = (j == 0);
|
||||
test.useSubclassLabel =
|
||||
(j == 0) ? "UseSubclass" : "UseBaseclass";
|
||||
suite.addTest(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private EntityStore store;
|
||||
private PrimaryIndex<String,Entity1> pri1;
|
||||
private PrimaryIndex<String,Entity2> pri2;
|
||||
private SecondaryIndex<String,String,Entity1> sec1;
|
||||
private SecondaryIndex<String,String,Entity2> sec2;
|
||||
private DeleteAction onDelete;
|
||||
private String onDeleteLabel;
|
||||
private boolean useSubclass;
|
||||
private String useSubclassLabel;
|
||||
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
super.tearDown();
|
||||
setName(getName() + '-' + onDeleteLabel + "-" + useSubclassLabel);
|
||||
}
|
||||
|
||||
private void open()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(envConfig.getAllowCreate());
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
|
||||
store = new EntityStore(env, "test", config);
|
||||
|
||||
pri1 = store.getPrimaryIndex(String.class, Entity1.class);
|
||||
sec1 = store.getSecondaryIndex(pri1, String.class, "sk");
|
||||
pri2 = store.getPrimaryIndex(String.class, Entity2.class);
|
||||
sec2 = store.getSecondaryIndex
|
||||
(pri2, String.class, "sk_" + onDeleteLabel);
|
||||
}
|
||||
|
||||
private void close()
|
||||
throws DatabaseException {
|
||||
|
||||
store.close();
|
||||
}
|
||||
|
||||
public void testForeignKeys()
|
||||
throws Exception {
|
||||
|
||||
open();
|
||||
Transaction txn = txnBegin();
|
||||
|
||||
Entity1 o1 = new Entity1("pk1", "sk1");
|
||||
assertNull(pri1.put(txn, o1));
|
||||
|
||||
assertEquals(o1, pri1.get(txn, "pk1", null));
|
||||
assertEquals(o1, sec1.get(txn, "sk1", null));
|
||||
|
||||
Entity2 o2 = (useSubclass ?
|
||||
new Entity3("pk2", "pk1", onDelete) :
|
||||
new Entity2("pk2", "pk1", onDelete));
|
||||
assertNull(pri2.put(txn, o2));
|
||||
|
||||
assertEquals(o2, pri2.get(txn, "pk2", null));
|
||||
assertEquals(o2, sec2.get(txn, "pk1", null));
|
||||
|
||||
txnCommit(txn);
|
||||
txn = txnBegin();
|
||||
|
||||
/*
|
||||
* pri1 contains o1 with primary key "pk1" and index key "sk1".
|
||||
*
|
||||
* pri2 contains o2 with primary key "pk2" and foreign key "pk1",
|
||||
* which is the primary key of pri1.
|
||||
*/
|
||||
if (onDelete == ABORT) {
|
||||
|
||||
/* Test that we abort trying to delete a referenced key. */
|
||||
|
||||
try {
|
||||
pri1.delete(txn, "pk1");
|
||||
fail();
|
||||
} catch (DatabaseException expected) {
|
||||
txnAbort(txn);
|
||||
txn = txnBegin();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that we can put a record into store2 with a null foreign
|
||||
* key value.
|
||||
*/
|
||||
o2 = (useSubclass ?
|
||||
new Entity3("pk2", null, onDelete) :
|
||||
new Entity2("pk2", null, onDelete));
|
||||
assertNotNull(pri2.put(txn, o2));
|
||||
assertEquals(o2, pri2.get(txn, "pk2", null));
|
||||
|
||||
/*
|
||||
* The index2 record should have been deleted since the key was set
|
||||
* to null above.
|
||||
*/
|
||||
assertNull(sec2.get(txn, "pk1", null));
|
||||
|
||||
/*
|
||||
* Test that now we can delete the record in store1, since it is no
|
||||
* longer referenced.
|
||||
*/
|
||||
assertNotNull(pri1.delete(txn, "pk1"));
|
||||
assertNull(pri1.get(txn, "pk1", null));
|
||||
assertNull(sec1.get(txn, "sk1", null));
|
||||
|
||||
} else if (onDelete == NULLIFY) {
|
||||
|
||||
/* Delete the referenced key. */
|
||||
assertNotNull(pri1.delete(txn, "pk1"));
|
||||
assertNull(pri1.get(txn, "pk1", null));
|
||||
assertNull(sec1.get(txn, "sk1", null));
|
||||
|
||||
/*
|
||||
* The store2 record should still exist, but should have an empty
|
||||
* secondary key since it was nullified.
|
||||
*/
|
||||
o2 = pri2.get(txn, "pk2", null);
|
||||
assertNotNull(o2);
|
||||
assertEquals("pk2", o2.pk);
|
||||
assertEquals(null, o2.getSk(onDelete));
|
||||
|
||||
} else if (onDelete == CASCADE) {
|
||||
|
||||
/* Delete the referenced key. */
|
||||
assertNotNull(pri1.delete(txn, "pk1"));
|
||||
assertNull(pri1.get(txn, "pk1", null));
|
||||
assertNull(sec1.get(txn, "sk1", null));
|
||||
|
||||
/* The store2 record should have deleted also. */
|
||||
assertNull(pri2.get(txn, "pk2", null));
|
||||
assertNull(sec2.get(txn, "pk1", null));
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a foreign key value may not be used that is not present in
|
||||
* the foreign store. "pk2" is not in store1 in this case.
|
||||
*/
|
||||
Entity2 o3 = (useSubclass ?
|
||||
new Entity3("pk3", "pk2", onDelete) :
|
||||
new Entity2("pk3", "pk2", onDelete));
|
||||
try {
|
||||
pri2.put(txn, o3);
|
||||
fail();
|
||||
} catch (DatabaseException expected) {
|
||||
}
|
||||
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class Entity1 {
|
||||
|
||||
@PrimaryKey
|
||||
String pk;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE)
|
||||
String sk;
|
||||
|
||||
private Entity1() {}
|
||||
|
||||
Entity1(String pk, String sk) {
|
||||
this.pk = pk;
|
||||
this.sk = sk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
Entity1 o = (Entity1) other;
|
||||
return nullOrEqual(pk, o.pk) &&
|
||||
nullOrEqual(sk, o.sk);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class Entity2 {
|
||||
|
||||
@PrimaryKey
|
||||
String pk;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
|
||||
onRelatedEntityDelete=ABORT)
|
||||
String sk_ABORT;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
|
||||
onRelatedEntityDelete=CASCADE)
|
||||
String sk_CASCADE;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
|
||||
onRelatedEntityDelete=NULLIFY)
|
||||
String sk_NULLIFY;
|
||||
|
||||
private Entity2() {}
|
||||
|
||||
Entity2(String pk, String sk, DeleteAction action) {
|
||||
this.pk = pk;
|
||||
switch (action) {
|
||||
case ABORT:
|
||||
sk_ABORT = sk;
|
||||
break;
|
||||
case CASCADE:
|
||||
sk_CASCADE = sk;
|
||||
break;
|
||||
case NULLIFY:
|
||||
sk_NULLIFY = sk;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
String getSk(DeleteAction action) {
|
||||
switch (action) {
|
||||
case ABORT:
|
||||
return sk_ABORT;
|
||||
case CASCADE:
|
||||
return sk_CASCADE;
|
||||
case NULLIFY:
|
||||
return sk_NULLIFY;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
Entity2 o = (Entity2) other;
|
||||
return nullOrEqual(pk, o.pk) &&
|
||||
nullOrEqual(sk_ABORT, o.sk_ABORT) &&
|
||||
nullOrEqual(sk_CASCADE, o.sk_CASCADE) &&
|
||||
nullOrEqual(sk_NULLIFY, o.sk_NULLIFY);
|
||||
}
|
||||
}
|
||||
|
||||
@Persistent
|
||||
static class Entity3 extends Entity2 {
|
||||
Entity3() {}
|
||||
|
||||
Entity3(String pk, String sk, DeleteAction action) {
|
||||
super(pk, sk, action);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean nullOrEqual(Object o1, Object o2) {
|
||||
if (o1 == null) {
|
||||
return o2 == null;
|
||||
} else {
|
||||
return o1.equals(o2);
|
||||
}
|
||||
}
|
||||
}
|
||||
864
test/scr024/src/com/sleepycat/persist/test/IndexTest.java
Normal file
864
test/scr024/src/com/sleepycat/persist/test/IndexTest.java
Normal file
@@ -0,0 +1,864 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: IndexTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY;
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.collections.MapEntryParameter;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.persist.EntityCursor;
|
||||
import com.sleepycat.persist.EntityIndex;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.SecondaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.persist.raw.RawObject;
|
||||
import com.sleepycat.persist.raw.RawStore;
|
||||
import com.sleepycat.persist.raw.RawType;
|
||||
import com.sleepycat.util.test.TxnTestCase;
|
||||
|
||||
/**
|
||||
* Tests EntityIndex and EntityCursor in all their permutations.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class IndexTest extends TxnTestCase {
|
||||
|
||||
private static final int N_RECORDS = 5;
|
||||
private static final int THREE_TO_ONE = 3;
|
||||
|
||||
public static Test suite() {
|
||||
return txnTestSuite(IndexTest.class, null,
|
||||
null);
|
||||
//new String[] { TxnTestCase.TXN_NULL});
|
||||
}
|
||||
|
||||
private EntityStore store;
|
||||
private PrimaryIndex<Integer,MyEntity> primary;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> oneToOne;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> manyToOne;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> oneToMany;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> manyToMany;
|
||||
private RawStore rawStore;
|
||||
private RawType entityType;
|
||||
private PrimaryIndex<Object,RawObject> primaryRaw;
|
||||
private SecondaryIndex<Object,Object,RawObject> oneToOneRaw;
|
||||
private SecondaryIndex<Object,Object,RawObject> manyToOneRaw;
|
||||
private SecondaryIndex<Object,Object,RawObject> oneToManyRaw;
|
||||
private SecondaryIndex<Object,Object,RawObject> manyToManyRaw;
|
||||
|
||||
/**
|
||||
* Opens the store.
|
||||
*/
|
||||
private void open()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(envConfig.getAllowCreate());
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
|
||||
store = new EntityStore(env, "test", config);
|
||||
|
||||
primary = store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
oneToOne =
|
||||
store.getSecondaryIndex(primary, Integer.class, "oneToOne");
|
||||
manyToOne =
|
||||
store.getSecondaryIndex(primary, Integer.class, "manyToOne");
|
||||
oneToMany =
|
||||
store.getSecondaryIndex(primary, Integer.class, "oneToMany");
|
||||
manyToMany =
|
||||
store.getSecondaryIndex(primary, Integer.class, "manyToMany");
|
||||
|
||||
assertNotNull(primary);
|
||||
assertNotNull(oneToOne);
|
||||
assertNotNull(manyToOne);
|
||||
assertNotNull(oneToMany);
|
||||
assertNotNull(manyToMany);
|
||||
|
||||
rawStore = new RawStore(env, "test", config);
|
||||
String clsName = MyEntity.class.getName();
|
||||
entityType = rawStore.getModel().getRawType(clsName);
|
||||
assertNotNull(entityType);
|
||||
|
||||
primaryRaw = rawStore.getPrimaryIndex(clsName);
|
||||
oneToOneRaw = rawStore.getSecondaryIndex(clsName, "oneToOne");
|
||||
manyToOneRaw = rawStore.getSecondaryIndex(clsName, "manyToOne");
|
||||
oneToManyRaw = rawStore.getSecondaryIndex(clsName, "oneToMany");
|
||||
manyToManyRaw = rawStore.getSecondaryIndex(clsName, "manyToMany");
|
||||
|
||||
assertNotNull(primaryRaw);
|
||||
assertNotNull(oneToOneRaw);
|
||||
assertNotNull(manyToOneRaw);
|
||||
assertNotNull(oneToManyRaw);
|
||||
assertNotNull(manyToManyRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the store.
|
||||
*/
|
||||
private void close()
|
||||
throws DatabaseException {
|
||||
|
||||
store.close();
|
||||
store = null;
|
||||
rawStore.close();
|
||||
rawStore = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The store must be closed before closing the environment.
|
||||
*/
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
if (rawStore != null) {
|
||||
rawStore.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
try {
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
store = null;
|
||||
rawStore = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary keys: {0, 1, 2, 3, 4}
|
||||
*/
|
||||
public void testPrimary()
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expected =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
SortedSet<Integer> values = new TreeSet<Integer>();
|
||||
values.add(priKey);
|
||||
expected.put(priKey, values);
|
||||
}
|
||||
|
||||
open();
|
||||
addEntities(primary);
|
||||
checkIndex(primary, expected, keyGetter, entityGetter);
|
||||
checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter);
|
||||
|
||||
/* Close and reopen, then recheck indices. */
|
||||
close();
|
||||
open();
|
||||
checkIndex(primary, expected, keyGetter, entityGetter);
|
||||
checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter);
|
||||
|
||||
/* Check primary delete, last key first for variety. */
|
||||
for (int priKey = N_RECORDS - 1; priKey >= 0; priKey -= 1) {
|
||||
boolean useRaw = ((priKey & 1) != 0);
|
||||
Transaction txn = txnBegin();
|
||||
if (useRaw) {
|
||||
primaryRaw.delete(txn, priKey);
|
||||
} else {
|
||||
primary.delete(txn, priKey);
|
||||
}
|
||||
txnCommit(txn);
|
||||
expected.remove(priKey);
|
||||
checkIndex(primary, expected, keyGetter, entityGetter);
|
||||
}
|
||||
checkAllEmpty();
|
||||
|
||||
/* Check PrimaryIndex put operations. */
|
||||
MyEntity e;
|
||||
Transaction txn = txnBegin();
|
||||
/* put() */
|
||||
e = primary.put(txn, new MyEntity(1));
|
||||
assertNull(e);
|
||||
e = primary.get(txn, 1, null);
|
||||
assertEquals(1, e.key);
|
||||
/* putNoReturn() */
|
||||
primary.putNoReturn(txn, new MyEntity(2));
|
||||
e = primary.get(txn, 2, null);
|
||||
assertEquals(2, e.key);
|
||||
/* putNoOverwrite */
|
||||
assertTrue(!primary.putNoOverwrite(txn, new MyEntity(1)));
|
||||
assertTrue(!primary.putNoOverwrite(txn, new MyEntity(2)));
|
||||
assertTrue(primary.putNoOverwrite(txn, new MyEntity(3)));
|
||||
e = primary.get(txn, 3, null);
|
||||
assertEquals(3, e.key);
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 }
|
||||
*/
|
||||
public void testOneToOne()
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expected =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
SortedSet<Integer> values = new TreeSet<Integer>();
|
||||
values.add(priKey);
|
||||
Integer secKey = (-priKey);
|
||||
expected.put(secKey, values);
|
||||
}
|
||||
|
||||
open();
|
||||
addEntities(primary);
|
||||
checkSecondary(oneToOne, oneToOneRaw, expected);
|
||||
checkDelete(oneToOne, oneToOneRaw, expected);
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* { 0:0, 1:1, 2:2, 3:0, 4:1 }
|
||||
*/
|
||||
public void testManyToOne()
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expected =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
Integer secKey = priKey % THREE_TO_ONE;
|
||||
SortedSet<Integer> values = expected.get(secKey);
|
||||
if (values == null) {
|
||||
values = new TreeSet<Integer>();
|
||||
expected.put(secKey, values);
|
||||
}
|
||||
values.add(priKey);
|
||||
}
|
||||
|
||||
open();
|
||||
addEntities(primary);
|
||||
checkSecondary(manyToOne, manyToOneRaw, expected);
|
||||
checkDelete(manyToOne, manyToOneRaw, expected);
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43}
|
||||
*/
|
||||
public void testOneToMany()
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expected =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
for (int i = 0; i < priKey; i += 1) {
|
||||
Integer secKey = (N_RECORDS * priKey) + i;
|
||||
SortedSet<Integer> values = expected.get(secKey);
|
||||
if (values == null) {
|
||||
values = new TreeSet<Integer>();
|
||||
expected.put(secKey, values);
|
||||
}
|
||||
values.add(priKey);
|
||||
}
|
||||
}
|
||||
|
||||
open();
|
||||
addEntities(primary);
|
||||
checkSecondary(oneToMany, oneToManyRaw, expected);
|
||||
checkDelete(oneToMany, oneToManyRaw, expected);
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3}
|
||||
*/
|
||||
public void testManyToMany()
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expected =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
for (int i = 0; i < priKey; i += 1) {
|
||||
Integer secKey = i;
|
||||
SortedSet<Integer> values = expected.get(secKey);
|
||||
if (values == null) {
|
||||
values = new TreeSet<Integer>();
|
||||
expected.put(secKey, values);
|
||||
}
|
||||
values.add(priKey);
|
||||
}
|
||||
}
|
||||
|
||||
open();
|
||||
addEntities(primary);
|
||||
checkSecondary(manyToMany, manyToManyRaw, expected);
|
||||
checkDelete(manyToMany, manyToManyRaw, expected);
|
||||
close();
|
||||
}
|
||||
|
||||
private void addEntities(PrimaryIndex<Integer,MyEntity> primary)
|
||||
throws DatabaseException {
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
MyEntity prev = primary.put(txn, new MyEntity(priKey));
|
||||
assertNull(prev);
|
||||
}
|
||||
txnCommit(txn);
|
||||
}
|
||||
|
||||
private void checkDelete(SecondaryIndex<Integer,Integer,MyEntity> index,
|
||||
SecondaryIndex<Object,Object,RawObject> indexRaw,
|
||||
SortedMap<Integer,SortedSet<Integer>> expected)
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expectedSubIndex =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
while (expected.size() > 0) {
|
||||
Integer delSecKey = expected.firstKey();
|
||||
SortedSet<Integer> deletedPriKeys = expected.remove(delSecKey);
|
||||
for (SortedSet<Integer> priKeys : expected.values()) {
|
||||
priKeys.removeAll(deletedPriKeys);
|
||||
}
|
||||
Transaction txn = txnBegin();
|
||||
boolean deleted = index.delete(txn, delSecKey);
|
||||
assertEquals(deleted, !deletedPriKeys.isEmpty());
|
||||
deleted = index.delete(txn, delSecKey);
|
||||
assertTrue(!deleted);
|
||||
assertNull(index.get(txn, delSecKey, null));
|
||||
txnCommit(txn);
|
||||
checkSecondary(index, indexRaw, expected);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete remaining records so that the primary index is empty. Use
|
||||
* the RawStore for variety.
|
||||
*/
|
||||
Transaction txn = txnBegin();
|
||||
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
|
||||
primaryRaw.delete(txn, priKey);
|
||||
}
|
||||
txnCommit(txn);
|
||||
checkAllEmpty();
|
||||
}
|
||||
|
||||
private void checkSecondary(SecondaryIndex<Integer,Integer,MyEntity> index,
|
||||
SecondaryIndex<Object,Object,RawObject>
|
||||
indexRaw,
|
||||
SortedMap<Integer,SortedSet<Integer>> expected)
|
||||
throws DatabaseException {
|
||||
|
||||
checkIndex(index, expected, keyGetter, entityGetter);
|
||||
checkIndex(index.keysIndex(), expected, keyGetter, keyGetter);
|
||||
|
||||
checkIndex(indexRaw, expected, rawKeyGetter, rawEntityGetter);
|
||||
checkIndex(indexRaw.keysIndex(), expected, rawKeyGetter, rawKeyGetter);
|
||||
|
||||
SortedMap<Integer,SortedSet<Integer>> expectedSubIndex =
|
||||
new TreeMap<Integer,SortedSet<Integer>>();
|
||||
|
||||
for (Integer secKey : expected.keySet()) {
|
||||
expectedSubIndex.clear();
|
||||
for (Integer priKey : expected.get(secKey)) {
|
||||
SortedSet<Integer> values = new TreeSet<Integer>();
|
||||
values.add(priKey);
|
||||
expectedSubIndex.put(priKey, values);
|
||||
}
|
||||
checkIndex(index.subIndex(secKey),
|
||||
expectedSubIndex,
|
||||
keyGetter,
|
||||
entityGetter);
|
||||
checkIndex(indexRaw.subIndex(secKey),
|
||||
expectedSubIndex,
|
||||
rawKeyGetter,
|
||||
rawEntityGetter);
|
||||
}
|
||||
}
|
||||
|
||||
private <K,V> void checkIndex(EntityIndex<K,V> index,
|
||||
SortedMap<Integer,SortedSet<Integer>>
|
||||
expected,
|
||||
Getter<K> kGetter,
|
||||
Getter<V> vGetter)
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<K,V> map = index.sortedMap();
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
for (int i : expected.keySet()) {
|
||||
K k = kGetter.fromInt(i);
|
||||
SortedSet<Integer> dups = expected.get(i);
|
||||
if (dups.isEmpty()) {
|
||||
|
||||
/* EntityIndex */
|
||||
V v = index.get(txn, k, null);
|
||||
assertNull(v);
|
||||
assertTrue(!index.contains(txn, k, null));
|
||||
|
||||
/* Map/Collection */
|
||||
v = map.get(i);
|
||||
assertNull(v);
|
||||
assertTrue(!map.containsKey(i));
|
||||
} else {
|
||||
int j = dups.first();
|
||||
|
||||
/* EntityIndex */
|
||||
V v = index.get(txn, k, null);
|
||||
assertNotNull(v);
|
||||
assertEquals(j, vGetter.getKey(v));
|
||||
assertTrue(index.contains(txn, k, null));
|
||||
|
||||
/* Map/Collection */
|
||||
v = map.get(i);
|
||||
assertNotNull(v);
|
||||
assertEquals(j, vGetter.getKey(v));
|
||||
assertTrue(map.containsKey(i));
|
||||
assertTrue("" + i + ' ' + j + ' ' + v + ' ' + map,
|
||||
map.containsValue(v));
|
||||
assertTrue(map.keySet().contains(i));
|
||||
assertTrue(map.values().contains(v));
|
||||
assertTrue
|
||||
(map.entrySet().contains(new MapEntryParameter(i, v)));
|
||||
}
|
||||
}
|
||||
txnCommit(txn);
|
||||
|
||||
int keysSize = expandKeySize(expected);
|
||||
int valuesSize = expandValueSize(expected);
|
||||
|
||||
/* EntityIndex.count */
|
||||
assertEquals("keysSize=" + keysSize, (long) valuesSize, index.count());
|
||||
|
||||
/* Map/Collection size */
|
||||
assertEquals(valuesSize, map.size());
|
||||
assertEquals(valuesSize, map.values().size());
|
||||
assertEquals(valuesSize, map.entrySet().size());
|
||||
assertEquals(keysSize, map.keySet().size());
|
||||
|
||||
/* Map/Collection isEmpty */
|
||||
assertEquals(valuesSize == 0, map.isEmpty());
|
||||
assertEquals(valuesSize == 0, map.values().isEmpty());
|
||||
assertEquals(valuesSize == 0, map.entrySet().isEmpty());
|
||||
assertEquals(keysSize == 0, map.keySet().isEmpty());
|
||||
|
||||
txn = txnBeginCursor();
|
||||
|
||||
/* Unconstrained cursors. */
|
||||
checkCursor
|
||||
(index.keys(txn, null),
|
||||
map.keySet(), true,
|
||||
expandKeys(expected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, null),
|
||||
map.values(), false,
|
||||
expandValues(expected), vGetter);
|
||||
|
||||
/* Range cursors. */
|
||||
if (expected.isEmpty()) {
|
||||
checkOpenRanges(txn, 0, index, expected, kGetter, vGetter);
|
||||
checkClosedRanges(txn, 0, 1, index, expected, kGetter, vGetter);
|
||||
} else {
|
||||
int firstKey = expected.firstKey();
|
||||
int lastKey = expected.lastKey();
|
||||
for (int i = firstKey - 1; i <= lastKey + 1; i += 1) {
|
||||
checkOpenRanges(txn, i, index, expected, kGetter, vGetter);
|
||||
int j = i + 1;
|
||||
if (j < lastKey + 1) {
|
||||
checkClosedRanges
|
||||
(txn, i, j, index, expected, kGetter, vGetter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txnCommit(txn);
|
||||
}
|
||||
|
||||
private <K,V> void checkOpenRanges(Transaction txn, int i,
|
||||
EntityIndex<K,V> index,
|
||||
SortedMap<Integer,SortedSet<Integer>>
|
||||
expected,
|
||||
Getter<K> kGetter,
|
||||
Getter<V> vGetter)
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<K,V> map = index.sortedMap();
|
||||
SortedMap<Integer,SortedSet<Integer>> rangeExpected;
|
||||
K k = kGetter.fromInt(i);
|
||||
K kPlusOne = kGetter.fromInt(i + 1);
|
||||
|
||||
/* Head range exclusive. */
|
||||
rangeExpected = expected.headMap(i);
|
||||
checkCursor
|
||||
(index.keys(txn, null, false, k, false, null),
|
||||
map.headMap(k).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, null, false, k, false, null),
|
||||
map.headMap(k).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
|
||||
/* Head range inclusive. */
|
||||
rangeExpected = expected.headMap(i + 1);
|
||||
checkCursor
|
||||
(index.keys(txn, null, false, k, true, null),
|
||||
map.headMap(kPlusOne).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, null, false, k, true, null),
|
||||
map.headMap(kPlusOne).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
|
||||
/* Tail range exclusive. */
|
||||
rangeExpected = expected.tailMap(i + 1);
|
||||
checkCursor
|
||||
(index.keys(txn, k, false, null, false, null),
|
||||
map.tailMap(kPlusOne).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, k, false, null, false, null),
|
||||
map.tailMap(kPlusOne).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
|
||||
/* Tail range inclusive. */
|
||||
rangeExpected = expected.tailMap(i);
|
||||
checkCursor
|
||||
(index.keys(txn, k, true, null, false, null),
|
||||
map.tailMap(k).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, k, true, null, false, null),
|
||||
map.tailMap(k).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
}
|
||||
|
||||
private <K,V> void checkClosedRanges(Transaction txn, int i, int j,
|
||||
EntityIndex<K,V> index,
|
||||
SortedMap<Integer,SortedSet<Integer>>
|
||||
expected,
|
||||
Getter<K> kGetter,
|
||||
Getter<V> vGetter)
|
||||
throws DatabaseException {
|
||||
|
||||
SortedMap<K,V> map = index.sortedMap();
|
||||
SortedMap<Integer,SortedSet<Integer>> rangeExpected;
|
||||
K k = kGetter.fromInt(i);
|
||||
K kPlusOne = kGetter.fromInt(i + 1);
|
||||
K l = kGetter.fromInt(j);
|
||||
K lPlusOne = kGetter.fromInt(j + 1);
|
||||
|
||||
/* Sub range exclusive. */
|
||||
rangeExpected = expected.subMap(i + 1, j);
|
||||
checkCursor
|
||||
(index.keys(txn, k, false, l, false, null),
|
||||
map.subMap(kPlusOne, l).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, k, false, l, false, null),
|
||||
map.subMap(kPlusOne, l).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
|
||||
/* Sub range inclusive. */
|
||||
rangeExpected = expected.subMap(i, j + 1);
|
||||
checkCursor
|
||||
(index.keys(txn, k, true, l, true, null),
|
||||
map.subMap(k, lPlusOne).keySet(), true,
|
||||
expandKeys(rangeExpected), kGetter);
|
||||
checkCursor
|
||||
(index.entities(txn, k, true, l, true, null),
|
||||
map.subMap(k, lPlusOne).values(), false,
|
||||
expandValues(rangeExpected), vGetter);
|
||||
}
|
||||
|
||||
private List<List<Integer>>
|
||||
expandKeys(SortedMap<Integer,SortedSet<Integer>> map) {
|
||||
|
||||
List<List<Integer>> list = new ArrayList<List<Integer>>();
|
||||
for (Integer key : map.keySet()) {
|
||||
SortedSet<Integer> values = map.get(key);
|
||||
List<Integer> dups = new ArrayList<Integer>();
|
||||
for (int i = 0; i < values.size(); i += 1) {
|
||||
dups.add(key);
|
||||
}
|
||||
list.add(dups);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<List<Integer>>
|
||||
expandValues(SortedMap<Integer,SortedSet<Integer>> map) {
|
||||
|
||||
List<List<Integer>> list = new ArrayList<List<Integer>>();
|
||||
for (SortedSet<Integer> values : map.values()) {
|
||||
list.add(new ArrayList<Integer>(values));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private int expandKeySize(SortedMap<Integer,SortedSet<Integer>> map) {
|
||||
|
||||
int size = 0;
|
||||
for (SortedSet<Integer> values : map.values()) {
|
||||
if (values.size() > 0) {
|
||||
size += 1;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private int expandValueSize(SortedMap<Integer,SortedSet<Integer>> map) {
|
||||
|
||||
int size = 0;
|
||||
for (SortedSet<Integer> values : map.values()) {
|
||||
size += values.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private <T> void checkCursor(EntityCursor<T> cursor,
|
||||
Collection<T> collection,
|
||||
boolean collectionIsKeySet,
|
||||
List<List<Integer>> expected,
|
||||
Getter<T> getter)
|
||||
throws DatabaseException {
|
||||
|
||||
boolean first;
|
||||
boolean firstDup;
|
||||
Iterator<T> iterator = collection.iterator();
|
||||
|
||||
for (List<Integer> dups : expected) {
|
||||
for (int i : dups) {
|
||||
T o = cursor.next();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
/* Value iterator over duplicates. */
|
||||
if (!collectionIsKeySet) {
|
||||
assertTrue(iterator.hasNext());
|
||||
o = iterator.next();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
for (List<Integer> dups : expected) {
|
||||
firstDup = true;
|
||||
for (int i : dups) {
|
||||
T o = first ? cursor.first()
|
||||
: (firstDup ? cursor.next() : cursor.nextDup());
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
first = false;
|
||||
firstDup = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
for (List<Integer> dups : expected) {
|
||||
if (!dups.isEmpty()) {
|
||||
int i = dups.get(0);
|
||||
T o = first ? cursor.first() : cursor.nextNoDup();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
/* Key iterator over non-duplicates. */
|
||||
if (collectionIsKeySet) {
|
||||
assertTrue(iterator.hasNext());
|
||||
o = iterator.next();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
List<List<Integer>> reversed = new ArrayList<List<Integer>>();
|
||||
for (List<Integer> dups : expected) {
|
||||
ArrayList<Integer> reversedDups = new ArrayList<Integer>(dups);
|
||||
Collections.reverse(reversedDups);
|
||||
reversed.add(reversedDups);
|
||||
}
|
||||
Collections.reverse(reversed);
|
||||
|
||||
first = true;
|
||||
for (List<Integer> dups : reversed) {
|
||||
for (int i : dups) {
|
||||
T o = first ? cursor.last() : cursor.prev();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
for (List<Integer> dups : reversed) {
|
||||
firstDup = true;
|
||||
for (int i : dups) {
|
||||
T o = first ? cursor.last()
|
||||
: (firstDup ? cursor.prev() : cursor.prevDup());
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
first = false;
|
||||
firstDup = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
for (List<Integer> dups : reversed) {
|
||||
if (!dups.isEmpty()) {
|
||||
int i = dups.get(0);
|
||||
T o = first ? cursor.last() : cursor.prevNoDup();
|
||||
assertNotNull(o);
|
||||
assertEquals(i, getter.getKey(o));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
private void checkAllEmpty()
|
||||
throws DatabaseException {
|
||||
|
||||
checkEmpty(primary);
|
||||
checkEmpty(oneToOne);
|
||||
checkEmpty(oneToMany);
|
||||
checkEmpty(manyToOne);
|
||||
checkEmpty(manyToMany);
|
||||
}
|
||||
|
||||
private <K,V> void checkEmpty(EntityIndex<K,V> index)
|
||||
throws DatabaseException {
|
||||
|
||||
EntityCursor<K> keys = index.keys();
|
||||
assertNull(keys.next());
|
||||
assertTrue(!keys.iterator().hasNext());
|
||||
keys.close();
|
||||
EntityCursor<V> entities = index.entities();
|
||||
assertNull(entities.next());
|
||||
assertTrue(!entities.iterator().hasNext());
|
||||
entities.close();
|
||||
}
|
||||
|
||||
private interface Getter<T> {
|
||||
int getKey(T o);
|
||||
T fromInt(int i);
|
||||
}
|
||||
|
||||
private static Getter<MyEntity> entityGetter =
|
||||
new Getter<MyEntity>() {
|
||||
public int getKey(MyEntity o) {
|
||||
return o.key;
|
||||
}
|
||||
public MyEntity fromInt(int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
private static Getter<Integer> keyGetter =
|
||||
new Getter<Integer>() {
|
||||
public int getKey(Integer o) {
|
||||
return o;
|
||||
}
|
||||
public Integer fromInt(int i) {
|
||||
return Integer.valueOf(i);
|
||||
}
|
||||
};
|
||||
|
||||
private static Getter<RawObject> rawEntityGetter =
|
||||
new Getter<RawObject>() {
|
||||
public int getKey(RawObject o) {
|
||||
Object val = o.getValues().get("key");
|
||||
return ((Integer) val).intValue();
|
||||
}
|
||||
public RawObject fromInt(int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
private static Getter<Object> rawKeyGetter =
|
||||
new Getter<Object>() {
|
||||
public int getKey(Object o) {
|
||||
return ((Integer) o).intValue();
|
||||
}
|
||||
public Object fromInt(int i) {
|
||||
return Integer.valueOf(i);
|
||||
}
|
||||
};
|
||||
|
||||
@Entity
|
||||
private static class MyEntity {
|
||||
|
||||
@PrimaryKey
|
||||
private int key;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE)
|
||||
private int oneToOne;
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private int manyToOne;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_MANY)
|
||||
private Set<Integer> oneToMany = new TreeSet<Integer>();
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_MANY)
|
||||
private Set<Integer> manyToMany = new TreeSet<Integer>();
|
||||
|
||||
private MyEntity() {}
|
||||
|
||||
private MyEntity(int key) {
|
||||
|
||||
/* example keys: {0, 1, 2, 3, 4} */
|
||||
this.key = key;
|
||||
|
||||
/* { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 } */
|
||||
oneToOne = -key;
|
||||
|
||||
/* { 0:0, 1:1, 2:2, 3:0, 4:1 } */
|
||||
manyToOne = key % THREE_TO_ONE;
|
||||
|
||||
/* { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43} */
|
||||
for (int i = 0; i < key; i += 1) {
|
||||
oneToMany.add((N_RECORDS * key) + i);
|
||||
}
|
||||
|
||||
/* { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3} */
|
||||
for (int i = 0; i < key; i += 1) {
|
||||
manyToMany.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MyEntity " + key;
|
||||
}
|
||||
}
|
||||
}
|
||||
174
test/scr024/src/com/sleepycat/persist/test/JoinTest.java
Normal file
174
test/scr024/src/com/sleepycat/persist/test/JoinTest.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: JoinTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.persist.EntityJoin;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.ForwardCursor;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.SecondaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.util.test.TxnTestCase;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class JoinTest extends TxnTestCase {
|
||||
|
||||
private static final int N_RECORDS = 5;
|
||||
|
||||
public static Test suite() {
|
||||
return txnTestSuite(JoinTest.class, null, null);
|
||||
}
|
||||
|
||||
private EntityStore store;
|
||||
private PrimaryIndex<Integer,MyEntity> primary;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> sec1;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> sec2;
|
||||
private SecondaryIndex<Integer,Integer,MyEntity> sec3;
|
||||
|
||||
/**
|
||||
* Opens the store.
|
||||
*/
|
||||
private void open()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(envConfig.getAllowCreate());
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
|
||||
store = new EntityStore(env, "test", config);
|
||||
|
||||
primary = store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
sec1 = store.getSecondaryIndex(primary, Integer.class, "k1");
|
||||
sec2 = store.getSecondaryIndex(primary, Integer.class, "k2");
|
||||
sec3 = store.getSecondaryIndex(primary, Integer.class, "k3");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the store.
|
||||
*/
|
||||
private void close()
|
||||
throws DatabaseException {
|
||||
|
||||
store.close();
|
||||
}
|
||||
|
||||
public void testJoin()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
/*
|
||||
* Primary keys: { 0, 1, 2, 3, 4 }
|
||||
* Secondary k1: { 0:0, 0:1, 0:2, 0:3, 0:4 }
|
||||
* Secondary k2: { 0:0, 1:1, 0:2, 1:3, 0:4 }
|
||||
* Secondary k3: { 0:0, 1:1, 2:2, 0:3, 1:4 }
|
||||
*/
|
||||
Transaction txn = txnBegin();
|
||||
for (int i = 0; i < N_RECORDS; i += 1) {
|
||||
MyEntity e = new MyEntity(i, 0, i % 2, i % 3);
|
||||
boolean ok = primary.putNoOverwrite(txn, e);
|
||||
assertTrue(ok);
|
||||
}
|
||||
txnCommit(txn);
|
||||
|
||||
/*
|
||||
* k1, k2, k3, -> { primary keys }
|
||||
* -1 means don't include the key in the join.
|
||||
*/
|
||||
doJoin( 0, 0, 0, new int[] { 0 });
|
||||
doJoin( 0, 0, 1, new int[] { 4 });
|
||||
doJoin( 0, 0, -1, new int[] { 0, 2, 4 });
|
||||
doJoin(-1, 1, 1, new int[] { 1 });
|
||||
doJoin(-1, 2, 2, new int[] { });
|
||||
doJoin(-1, -1, 2, new int[] { 2 });
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
private void doJoin(int k1, int k2, int k3, int[] expectKeys)
|
||||
throws DatabaseException {
|
||||
|
||||
List<Integer> expect = new ArrayList<Integer>();
|
||||
for (int i : expectKeys) {
|
||||
expect.add(i);
|
||||
}
|
||||
EntityJoin join = new EntityJoin(primary);
|
||||
if (k1 >= 0) {
|
||||
join.addCondition(sec1, k1);
|
||||
}
|
||||
if (k2 >= 0) {
|
||||
join.addCondition(sec2, k2);
|
||||
}
|
||||
if (k3 >= 0) {
|
||||
join.addCondition(sec3, k3);
|
||||
}
|
||||
List<Integer> found;
|
||||
Transaction txn = txnBegin();
|
||||
|
||||
/* Keys */
|
||||
found = new ArrayList<Integer>();
|
||||
ForwardCursor<Integer> keys = join.keys(txn, null);
|
||||
for (int i : keys) {
|
||||
found.add(i);
|
||||
}
|
||||
keys.close();
|
||||
assertEquals(expect, found);
|
||||
|
||||
/* Entities */
|
||||
found = new ArrayList<Integer>();
|
||||
ForwardCursor<MyEntity> entities = join.entities(txn, null);
|
||||
for (MyEntity e : entities) {
|
||||
found.add(e.id);
|
||||
}
|
||||
entities.close();
|
||||
assertEquals(expect, found);
|
||||
|
||||
txnCommit(txn);
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class MyEntity {
|
||||
@PrimaryKey
|
||||
int id;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
int k1;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
int k2;
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
int k3;
|
||||
|
||||
private MyEntity() {}
|
||||
|
||||
MyEntity(int id, int k1, int k2, int k3) {
|
||||
this.id = id;
|
||||
this.k1 = k1;
|
||||
this.k2 = k2;
|
||||
this.k3 = k3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MyEntity " + id + ' ' + k1 + ' ' + k2 + ' ' + k3;
|
||||
}
|
||||
}
|
||||
}
|
||||
299
test/scr024/src/com/sleepycat/persist/test/NegativeTest.java
Normal file
299
test/scr024/src/com/sleepycat/persist/test/NegativeTest.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: NegativeTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.KeyField;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.util.test.TxnTestCase;
|
||||
|
||||
/**
|
||||
* Negative tests.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class NegativeTest extends TxnTestCase {
|
||||
|
||||
public static Test suite() {
|
||||
return txnTestSuite(NegativeTest.class, null, null);
|
||||
}
|
||||
|
||||
private EntityStore store;
|
||||
|
||||
private void open()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(envConfig.getAllowCreate());
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
|
||||
store = new EntityStore(env, "test", config);
|
||||
}
|
||||
|
||||
private void close()
|
||||
throws DatabaseException {
|
||||
|
||||
store.close();
|
||||
store = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
if (store != null) {
|
||||
try {
|
||||
store.close();
|
||||
} catch (Throwable e) {
|
||||
System.out.println("tearDown: " + e);
|
||||
}
|
||||
store = null;
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testBadKeyClass1()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
try {
|
||||
PrimaryIndex<BadKeyClass1,UseBadKeyClass1> index =
|
||||
store.getPrimaryIndex
|
||||
(BadKeyClass1.class, UseBadKeyClass1.class);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().indexOf("@KeyField") >= 0);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
/** Missing @KeyField in composite key class. */
|
||||
@Persistent
|
||||
static class BadKeyClass1 {
|
||||
|
||||
private int f1;
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class UseBadKeyClass1 {
|
||||
|
||||
@PrimaryKey
|
||||
private BadKeyClass1 f1 = new BadKeyClass1();
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE)
|
||||
private BadKeyClass1 f2 = new BadKeyClass1();
|
||||
}
|
||||
|
||||
public void testBadSequenceKeys()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
try {
|
||||
PrimaryIndex<Boolean,BadSequenceKeyEntity1> index =
|
||||
store.getPrimaryIndex
|
||||
(Boolean.class, BadSequenceKeyEntity1.class);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().indexOf
|
||||
("Type not allowed for sequence") >= 0);
|
||||
}
|
||||
try {
|
||||
PrimaryIndex<BadSequenceKeyEntity2.Key,
|
||||
BadSequenceKeyEntity2> index =
|
||||
store.getPrimaryIndex
|
||||
(BadSequenceKeyEntity2.Key.class,
|
||||
BadSequenceKeyEntity2.class);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().indexOf
|
||||
("Type not allowed for sequence") >= 0);
|
||||
}
|
||||
try {
|
||||
PrimaryIndex<BadSequenceKeyEntity3.Key,
|
||||
BadSequenceKeyEntity3> index =
|
||||
store.getPrimaryIndex
|
||||
(BadSequenceKeyEntity3.Key.class,
|
||||
BadSequenceKeyEntity3.class);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().indexOf
|
||||
("A composite key class used with a sequence may contain " +
|
||||
"only a single integer key field")>= 0);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
/** Boolean not allowed for sequence key. */
|
||||
@Entity
|
||||
static class BadSequenceKeyEntity1 {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
private boolean key;
|
||||
}
|
||||
|
||||
/** Composite key with non-integer field not allowed for sequence key. */
|
||||
@Entity
|
||||
static class BadSequenceKeyEntity2 {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
private Key key;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
boolean key;
|
||||
}
|
||||
}
|
||||
|
||||
/** Composite key with multiple key fields not allowed for sequence key. */
|
||||
@Entity
|
||||
static class BadSequenceKeyEntity3 {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
private Key key;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
int key;
|
||||
@KeyField(2)
|
||||
int key2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A proxied object may not current contain a field that references the
|
||||
* parent proxy. [#15815]
|
||||
*/
|
||||
public void testProxyNestedRef()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
PrimaryIndex<Integer,ProxyNestedRef> index = store.getPrimaryIndex
|
||||
(Integer.class, ProxyNestedRef.class);
|
||||
ProxyNestedRef entity = new ProxyNestedRef();
|
||||
entity.list.add(entity.list);
|
||||
try {
|
||||
index.put(entity);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().indexOf
|
||||
("Cannot embed a reference to a proxied object") >= 0);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class ProxyNestedRef {
|
||||
|
||||
@PrimaryKey
|
||||
private int key;
|
||||
|
||||
ArrayList<Object> list = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallow primary keys on entity subclasses. [#15757]
|
||||
*/
|
||||
public void testEntitySubclassWithPrimaryKey()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
PrimaryIndex<Integer,EntitySuperClass> index = store.getPrimaryIndex
|
||||
(Integer.class, EntitySuperClass.class);
|
||||
EntitySuperClass e1 = new EntitySuperClass(1, "one");
|
||||
index.put(e1);
|
||||
assertEquals(e1, index.get(1));
|
||||
EntitySubClass e2 = new EntitySubClass(2, "two", "foo", 9);
|
||||
try {
|
||||
index.put(e2);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains
|
||||
("PrimaryKey may not appear on an Entity subclass"));
|
||||
}
|
||||
assertEquals(e1, index.get(1));
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class EntitySuperClass {
|
||||
|
||||
@PrimaryKey
|
||||
private int x;
|
||||
|
||||
private String y;
|
||||
|
||||
EntitySuperClass(int x, String y) {
|
||||
assert y != null;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
private EntitySuperClass() {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "x=" + x + " y=" + y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof EntitySuperClass) {
|
||||
EntitySuperClass o = (EntitySuperClass) other;
|
||||
return x == o.x && y.equals(o.y);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Persistent
|
||||
static class EntitySubClass extends EntitySuperClass {
|
||||
|
||||
@PrimaryKey
|
||||
private String foo;
|
||||
|
||||
private int z;
|
||||
|
||||
EntitySubClass(int x, String y, String foo, int z) {
|
||||
super(x, y);
|
||||
assert foo != null;
|
||||
this.foo = foo;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
private EntitySubClass() {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " z=" + z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof EntitySubClass) {
|
||||
EntitySubClass o = (EntitySubClass) other;
|
||||
return super.equals(o) && z == o.z;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
879
test/scr024/src/com/sleepycat/persist/test/OperationTest.java
Normal file
879
test/scr024/src/com/sleepycat/persist/test/OperationTest.java
Normal file
@@ -0,0 +1,879 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: OperationTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
|
||||
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
|
||||
import static com.sleepycat.persist.model.DeleteAction.CASCADE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.persist.EntityCursor;
|
||||
import com.sleepycat.persist.EntityIndex;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.SecondaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.impl.Store;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.KeyField;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.persist.raw.RawStore;
|
||||
import com.sleepycat.util.test.TxnTestCase;
|
||||
|
||||
/**
|
||||
* Tests misc store and index operations that are not tested by IndexTest.
|
||||
*
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class OperationTest extends TxnTestCase {
|
||||
|
||||
private static final String STORE_NAME = "test";
|
||||
|
||||
public static Test suite() {
|
||||
return txnTestSuite(OperationTest.class, null, null);
|
||||
}
|
||||
|
||||
private EntityStore store;
|
||||
|
||||
private void openReadOnly()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setReadOnly(true);
|
||||
open(config);
|
||||
}
|
||||
|
||||
private void open()
|
||||
throws DatabaseException {
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(envConfig.getAllowCreate());
|
||||
open(config);
|
||||
}
|
||||
|
||||
private void open(StoreConfig config)
|
||||
throws DatabaseException {
|
||||
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
store = new EntityStore(env, STORE_NAME, config);
|
||||
}
|
||||
|
||||
private void close()
|
||||
throws DatabaseException {
|
||||
|
||||
store.close();
|
||||
store = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The store must be closed before closing the environment.
|
||||
*/
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
if (store != null) {
|
||||
store.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
store = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testReadOnly()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
PrimaryIndex<Integer,SharedSequenceEntity1> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
|
||||
Transaction txn = txnBegin();
|
||||
SharedSequenceEntity1 e = new SharedSequenceEntity1();
|
||||
priIndex.put(txn, e);
|
||||
assertEquals(1, e.key);
|
||||
txnCommit(txn);
|
||||
close();
|
||||
|
||||
/*
|
||||
* Check that we can open the store read-only and read the records
|
||||
* written above.
|
||||
*/
|
||||
openReadOnly();
|
||||
priIndex =
|
||||
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
|
||||
e = priIndex.get(1);
|
||||
assertNotNull(e);
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
public void testUninitializedCursor()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,MyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
|
||||
Transaction txn = txnBeginCursor();
|
||||
|
||||
MyEntity e = new MyEntity();
|
||||
e.priKey = 1;
|
||||
e.secKey = 1;
|
||||
priIndex.put(txn, e);
|
||||
|
||||
EntityCursor<MyEntity> entities = priIndex.entities(txn, null);
|
||||
try {
|
||||
entities.nextDup();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
try {
|
||||
entities.prevDup();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
try {
|
||||
entities.current();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
try {
|
||||
entities.delete();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
try {
|
||||
entities.update(e);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
try {
|
||||
entities.count();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {}
|
||||
|
||||
entities.close();
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
public void testCursorCount()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,MyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
|
||||
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
|
||||
|
||||
Transaction txn = txnBeginCursor();
|
||||
|
||||
MyEntity e = new MyEntity();
|
||||
e.priKey = 1;
|
||||
e.secKey = 1;
|
||||
priIndex.put(txn, e);
|
||||
|
||||
EntityCursor<MyEntity> cursor = secIndex.entities(txn, null);
|
||||
cursor.next();
|
||||
assertEquals(1, cursor.count());
|
||||
cursor.close();
|
||||
|
||||
e.priKey = 2;
|
||||
priIndex.put(txn, e);
|
||||
cursor = secIndex.entities(txn, null);
|
||||
cursor.next();
|
||||
assertEquals(2, cursor.count());
|
||||
cursor.close();
|
||||
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
public void testCursorUpdate()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,MyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
|
||||
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
|
||||
|
||||
Transaction txn = txnBeginCursor();
|
||||
|
||||
Integer k;
|
||||
MyEntity e = new MyEntity();
|
||||
e.priKey = 1;
|
||||
e.secKey = 2;
|
||||
priIndex.put(txn, e);
|
||||
|
||||
/* update() with primary entity cursor. */
|
||||
EntityCursor<MyEntity> entities = priIndex.entities(txn, null);
|
||||
e = entities.next();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
assertEquals(Integer.valueOf(2), e.secKey);
|
||||
e.secKey = null;
|
||||
assertTrue(entities.update(e));
|
||||
e = entities.current();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
assertEquals(null, e.secKey);
|
||||
e.secKey = 3;
|
||||
assertTrue(entities.update(e));
|
||||
e = entities.current();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
assertEquals(Integer.valueOf(3), e.secKey);
|
||||
entities.close();
|
||||
|
||||
/* update() with primary keys cursor. */
|
||||
EntityCursor<Integer> keys = priIndex.keys(txn, null);
|
||||
k = keys.next();
|
||||
assertNotNull(k);
|
||||
assertEquals(Integer.valueOf(1), k);
|
||||
try {
|
||||
keys.update(2);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
keys.close();
|
||||
|
||||
/* update() with secondary entity cursor. */
|
||||
entities = secIndex.entities(txn, null);
|
||||
e = entities.next();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
assertEquals(Integer.valueOf(3), e.secKey);
|
||||
try {
|
||||
entities.update(e);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
} catch (IllegalArgumentException expectedForDbCore) {
|
||||
}
|
||||
entities.close();
|
||||
|
||||
/* update() with secondary keys cursor. */
|
||||
keys = secIndex.keys(txn, null);
|
||||
k = keys.next();
|
||||
assertNotNull(k);
|
||||
assertEquals(Integer.valueOf(3), k);
|
||||
try {
|
||||
keys.update(k);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
keys.close();
|
||||
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
public void testCursorDelete()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,MyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
|
||||
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
|
||||
|
||||
Transaction txn = txnBeginCursor();
|
||||
|
||||
/* delete() with primary and secondary entities cursor. */
|
||||
|
||||
for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) {
|
||||
|
||||
MyEntity e = new MyEntity();
|
||||
e.priKey = 1;
|
||||
e.secKey = 1;
|
||||
priIndex.put(txn, e);
|
||||
e.priKey = 2;
|
||||
priIndex.put(txn, e);
|
||||
|
||||
EntityCursor<MyEntity> cursor = index.entities(txn, null);
|
||||
|
||||
e = cursor.next();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
e = cursor.current();
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.priKey);
|
||||
assertTrue(cursor.delete());
|
||||
assertTrue(!cursor.delete());
|
||||
assertNull(cursor.current());
|
||||
|
||||
e = cursor.next();
|
||||
assertNotNull(e);
|
||||
assertEquals(2, e.priKey);
|
||||
e = cursor.current();
|
||||
assertNotNull(e);
|
||||
assertEquals(2, e.priKey);
|
||||
assertTrue(cursor.delete());
|
||||
assertTrue(!cursor.delete());
|
||||
assertNull(cursor.current());
|
||||
|
||||
e = cursor.next();
|
||||
assertNull(e);
|
||||
|
||||
if (index == priIndex) {
|
||||
e = new MyEntity();
|
||||
e.priKey = 2;
|
||||
e.secKey = 1;
|
||||
assertTrue(!cursor.update(e));
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
/* delete() with primary and secondary keys cursor. */
|
||||
|
||||
for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) {
|
||||
|
||||
MyEntity e = new MyEntity();
|
||||
e.priKey = 1;
|
||||
e.secKey = 1;
|
||||
priIndex.put(txn, e);
|
||||
e.priKey = 2;
|
||||
priIndex.put(txn, e);
|
||||
|
||||
EntityCursor<Integer> cursor = index.keys(txn, null);
|
||||
|
||||
Integer k = cursor.next();
|
||||
assertNotNull(k);
|
||||
assertEquals(1, k.intValue());
|
||||
k = cursor.current();
|
||||
assertNotNull(k);
|
||||
assertEquals(1, k.intValue());
|
||||
assertTrue(cursor.delete());
|
||||
assertTrue(!cursor.delete());
|
||||
assertNull(cursor.current());
|
||||
|
||||
int expectKey = (index == priIndex) ? 2 : 1;
|
||||
k = cursor.next();
|
||||
assertNotNull(k);
|
||||
assertEquals(expectKey, k.intValue());
|
||||
k = cursor.current();
|
||||
assertNotNull(k);
|
||||
assertEquals(expectKey, k.intValue());
|
||||
assertTrue(cursor.delete());
|
||||
assertTrue(!cursor.delete());
|
||||
assertNull(cursor.current());
|
||||
|
||||
k = cursor.next();
|
||||
assertNull(k);
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
public void testDeleteFromSubIndex()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,MyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
|
||||
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
MyEntity e = new MyEntity();
|
||||
e.secKey = 1;
|
||||
e.priKey = 1;
|
||||
priIndex.put(txn, e);
|
||||
e.priKey = 2;
|
||||
priIndex.put(txn, e);
|
||||
e.priKey = 3;
|
||||
priIndex.put(txn, e);
|
||||
e.priKey = 4;
|
||||
priIndex.put(txn, e);
|
||||
txnCommit(txn);
|
||||
|
||||
EntityIndex<Integer,MyEntity> subIndex = secIndex.subIndex(1);
|
||||
txn = txnBeginCursor();
|
||||
e = subIndex.get(txn, 1, null);
|
||||
assertEquals(1, e.priKey);
|
||||
assertEquals(Integer.valueOf(1), e.secKey);
|
||||
e = subIndex.get(txn, 2, null);
|
||||
assertEquals(2, e.priKey);
|
||||
assertEquals(Integer.valueOf(1), e.secKey);
|
||||
e = subIndex.get(txn, 3, null);
|
||||
assertEquals(3, e.priKey);
|
||||
assertEquals(Integer.valueOf(1), e.secKey);
|
||||
e = subIndex.get(txn, 5, null);
|
||||
assertNull(e);
|
||||
|
||||
boolean deleted = subIndex.delete(txn, 1);
|
||||
assertTrue(deleted);
|
||||
assertNull(subIndex.get(txn, 1, null));
|
||||
assertNotNull(subIndex.get(txn, 2, null));
|
||||
|
||||
EntityCursor<MyEntity> cursor = subIndex.entities(txn, null);
|
||||
boolean saw4 = false;
|
||||
for (MyEntity e2 = cursor.first(); e2 != null; e2 = cursor.next()) {
|
||||
if (e2.priKey == 3) {
|
||||
cursor.delete();
|
||||
}
|
||||
if (e2.priKey == 4) {
|
||||
saw4 = true;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
assertTrue(saw4);
|
||||
assertNull(subIndex.get(txn, 1, null));
|
||||
assertNull(subIndex.get(txn, 3, null));
|
||||
assertNotNull(subIndex.get(txn, 2, null));
|
||||
assertNotNull(subIndex.get(txn, 4, null));
|
||||
|
||||
txnCommit(txn);
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class MyEntity {
|
||||
|
||||
@PrimaryKey
|
||||
private int priKey;
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
private Integer secKey;
|
||||
|
||||
private MyEntity() {}
|
||||
}
|
||||
|
||||
public void testSharedSequence()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,SharedSequenceEntity1> priIndex1 =
|
||||
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
|
||||
|
||||
PrimaryIndex<Integer,SharedSequenceEntity2> priIndex2 =
|
||||
store.getPrimaryIndex(Integer.class, SharedSequenceEntity2.class);
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
SharedSequenceEntity1 e1 = new SharedSequenceEntity1();
|
||||
SharedSequenceEntity2 e2 = new SharedSequenceEntity2();
|
||||
priIndex1.put(txn, e1);
|
||||
assertEquals(1, e1.key);
|
||||
priIndex2.putNoOverwrite(txn, e2);
|
||||
assertEquals(Integer.valueOf(2), e2.key);
|
||||
e1.key = 0;
|
||||
priIndex1.putNoOverwrite(txn, e1);
|
||||
assertEquals(3, e1.key);
|
||||
e2.key = null;
|
||||
priIndex2.put(txn, e2);
|
||||
assertEquals(Integer.valueOf(4), e2.key);
|
||||
txnCommit(txn);
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SharedSequenceEntity1 {
|
||||
|
||||
@PrimaryKey(sequence="shared")
|
||||
private int key;
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SharedSequenceEntity2 {
|
||||
|
||||
@PrimaryKey(sequence="shared")
|
||||
private Integer key;
|
||||
}
|
||||
|
||||
public void testSeparateSequence()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,SeparateSequenceEntity1> priIndex1 =
|
||||
store.getPrimaryIndex
|
||||
(Integer.class, SeparateSequenceEntity1.class);
|
||||
|
||||
PrimaryIndex<Integer,SeparateSequenceEntity2> priIndex2 =
|
||||
store.getPrimaryIndex
|
||||
(Integer.class, SeparateSequenceEntity2.class);
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
SeparateSequenceEntity1 e1 = new SeparateSequenceEntity1();
|
||||
SeparateSequenceEntity2 e2 = new SeparateSequenceEntity2();
|
||||
priIndex1.put(txn, e1);
|
||||
assertEquals(1, e1.key);
|
||||
priIndex2.putNoOverwrite(txn, e2);
|
||||
assertEquals(Integer.valueOf(1), e2.key);
|
||||
e1.key = 0;
|
||||
priIndex1.putNoOverwrite(txn, e1);
|
||||
assertEquals(2, e1.key);
|
||||
e2.key = null;
|
||||
priIndex2.put(txn, e2);
|
||||
assertEquals(Integer.valueOf(2), e2.key);
|
||||
txnCommit(txn);
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SeparateSequenceEntity1 {
|
||||
|
||||
@PrimaryKey(sequence="seq1")
|
||||
private int key;
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SeparateSequenceEntity2 {
|
||||
|
||||
@PrimaryKey(sequence="seq2")
|
||||
private Integer key;
|
||||
}
|
||||
|
||||
public void testCompositeSequence()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<CompositeSequenceEntity1.Key,CompositeSequenceEntity1>
|
||||
priIndex1 =
|
||||
store.getPrimaryIndex
|
||||
(CompositeSequenceEntity1.Key.class,
|
||||
CompositeSequenceEntity1.class);
|
||||
|
||||
PrimaryIndex<CompositeSequenceEntity2.Key,CompositeSequenceEntity2>
|
||||
priIndex2 =
|
||||
store.getPrimaryIndex
|
||||
(CompositeSequenceEntity2.Key.class,
|
||||
CompositeSequenceEntity2.class);
|
||||
|
||||
Transaction txn = txnBegin();
|
||||
CompositeSequenceEntity1 e1 = new CompositeSequenceEntity1();
|
||||
CompositeSequenceEntity2 e2 = new CompositeSequenceEntity2();
|
||||
priIndex1.put(txn, e1);
|
||||
assertEquals(1, e1.key.key);
|
||||
priIndex2.putNoOverwrite(txn, e2);
|
||||
assertEquals(Integer.valueOf(1), e2.key.key);
|
||||
e1.key = null;
|
||||
priIndex1.putNoOverwrite(txn, e1);
|
||||
assertEquals(2, e1.key.key);
|
||||
e2.key = null;
|
||||
priIndex2.put(txn, e2);
|
||||
assertEquals(Integer.valueOf(2), e2.key.key);
|
||||
txnCommit(txn);
|
||||
|
||||
EntityCursor<CompositeSequenceEntity1> c1 = priIndex1.entities();
|
||||
e1 = c1.next();
|
||||
assertEquals(2, e1.key.key);
|
||||
e1 = c1.next();
|
||||
assertEquals(1, e1.key.key);
|
||||
e1 = c1.next();
|
||||
assertNull(e1);
|
||||
c1.close();
|
||||
|
||||
EntityCursor<CompositeSequenceEntity2> c2 = priIndex2.entities();
|
||||
e2 = c2.next();
|
||||
assertEquals(Integer.valueOf(2), e2.key.key);
|
||||
e2 = c2.next();
|
||||
assertEquals(Integer.valueOf(1), e2.key.key);
|
||||
e2 = c2.next();
|
||||
assertNull(e2);
|
||||
c2.close();
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class CompositeSequenceEntity1 {
|
||||
|
||||
@Persistent
|
||||
static class Key implements Comparable<Key> {
|
||||
|
||||
@KeyField(1)
|
||||
private int key;
|
||||
|
||||
public int compareTo(Key o) {
|
||||
/* Reverse the natural order. */
|
||||
return o.key - key;
|
||||
}
|
||||
}
|
||||
|
||||
@PrimaryKey(sequence="seq1")
|
||||
private Key key;
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class CompositeSequenceEntity2 {
|
||||
|
||||
@Persistent
|
||||
static class Key implements Comparable<Key> {
|
||||
|
||||
@KeyField(1)
|
||||
private Integer key;
|
||||
|
||||
public int compareTo(Key o) {
|
||||
/* Reverse the natural order. */
|
||||
return o.key - key;
|
||||
}
|
||||
}
|
||||
|
||||
@PrimaryKey(sequence="seq2")
|
||||
private Key key;
|
||||
}
|
||||
|
||||
/**
|
||||
* When opening read-only, secondaries are not opened when the primary is
|
||||
* opened, causing a different code path to be used for opening
|
||||
* secondaries. For a RawStore in particular, this caused an unreported
|
||||
* NullPointerException in JE 3.0.12. No SR was created because the use
|
||||
* case is very obscure and was discovered by code inspection.
|
||||
*/
|
||||
public void testOpenRawStoreReadOnly()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
store.getPrimaryIndex(Integer.class, MyEntity.class);
|
||||
close();
|
||||
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setReadOnly(true);
|
||||
config.setTransactional(envConfig.getTransactional());
|
||||
RawStore rawStore = new RawStore(env, "test", config);
|
||||
|
||||
String clsName = MyEntity.class.getName();
|
||||
rawStore.getSecondaryIndex(clsName, "secKey");
|
||||
|
||||
rawStore.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* When opening an X_TO_MANY secondary that has a persistent key class, the
|
||||
* key class was not recognized as being persistent if it was never before
|
||||
* referenced when getSecondaryIndex was called. This was a bug in JE
|
||||
* 3.0.12, reported on OTN. [#15103]
|
||||
*/
|
||||
public void testToManyKeyClass()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
|
||||
PrimaryIndex<Integer,ToManyKeyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
|
||||
SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, ToManyKey.class, "key2");
|
||||
|
||||
priIndex.put(new ToManyKeyEntity());
|
||||
secIndex.get(new ToManyKey());
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a fix for a bug where opening a TO_MANY secondary index would fail
|
||||
* fail with "IllegalArgumentException: Wrong secondary key class: ..."
|
||||
* when the store was opened read-only. [#15156]
|
||||
*/
|
||||
public void testToManyReadOnly()
|
||||
throws DatabaseException {
|
||||
|
||||
open();
|
||||
PrimaryIndex<Integer,ToManyKeyEntity> priIndex =
|
||||
store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
|
||||
priIndex.put(new ToManyKeyEntity());
|
||||
close();
|
||||
|
||||
openReadOnly();
|
||||
priIndex = store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
|
||||
SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex =
|
||||
store.getSecondaryIndex(priIndex, ToManyKey.class, "key2");
|
||||
secIndex.get(new ToManyKey());
|
||||
close();
|
||||
}
|
||||
|
||||
@Persistent
|
||||
static class ToManyKey {
|
||||
|
||||
@KeyField(1)
|
||||
int value = 99;
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class ToManyKeyEntity {
|
||||
|
||||
@PrimaryKey
|
||||
int key = 88;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_MANY)
|
||||
Set<ToManyKey> key2;
|
||||
|
||||
ToManyKeyEntity() {
|
||||
key2 = new HashSet<ToManyKey>();
|
||||
key2.add(new ToManyKey());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When Y is opened and X has a key with relatedEntity=Y.class, X should
|
||||
* be opened automatically. If X is not opened, foreign key constraints
|
||||
* will not be enforced. [#15358]
|
||||
*/
|
||||
public void testAutoOpenRelatedEntity()
|
||||
throws DatabaseException {
|
||||
|
||||
PrimaryIndex<Integer,RelatedY> priY;
|
||||
PrimaryIndex<Integer,RelatedX> priX;
|
||||
|
||||
/* Opening X should create (and open) Y and enforce constraints. */
|
||||
open();
|
||||
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
|
||||
PersistTestUtils.assertDbExists
|
||||
(true, env, STORE_NAME, RelatedY.class.getName(), null);
|
||||
try {
|
||||
priX.put(new RelatedX());
|
||||
fail();
|
||||
} catch (DatabaseException e) {
|
||||
assertTrue
|
||||
("" + e.getMessage(), (e.getMessage().indexOf
|
||||
("foreign key not allowed: it is not present") >= 0) ||
|
||||
(e.getMessage().indexOf("DB_FOREIGN_CONFLICT") >= 0));
|
||||
}
|
||||
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
|
||||
priY.put(new RelatedY());
|
||||
priX.put(new RelatedX());
|
||||
close();
|
||||
|
||||
/* Delete should cascade even when X is not opened explicitly. */
|
||||
open();
|
||||
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
|
||||
assertEquals(1, priY.count());
|
||||
priY.delete(88);
|
||||
assertEquals(0, priY.count());
|
||||
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
|
||||
assertEquals(0, priX.count()); /* Failed prior to [#15358] fix. */
|
||||
close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class RelatedX {
|
||||
|
||||
@PrimaryKey
|
||||
int key = 99;
|
||||
|
||||
@SecondaryKey(relate=ONE_TO_ONE,
|
||||
relatedEntity=RelatedY.class,
|
||||
onRelatedEntityDelete=CASCADE)
|
||||
int key2 = 88;
|
||||
|
||||
RelatedX() {
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class RelatedY {
|
||||
|
||||
@PrimaryKey
|
||||
int key = 88;
|
||||
|
||||
RelatedY() {
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecondaryBulkLoad1()
|
||||
throws DatabaseException {
|
||||
|
||||
doSecondaryBulkLoad(true);
|
||||
}
|
||||
|
||||
public void testSecondaryBulkLoad2()
|
||||
throws DatabaseException {
|
||||
|
||||
doSecondaryBulkLoad(false);
|
||||
}
|
||||
|
||||
private void doSecondaryBulkLoad(boolean closeAndOpenNormally)
|
||||
throws DatabaseException {
|
||||
|
||||
PrimaryIndex<Integer,RelatedX> priX;
|
||||
PrimaryIndex<Integer,RelatedY> priY;
|
||||
SecondaryIndex<Integer,Integer,RelatedX> secX;
|
||||
|
||||
/* Open priX with SecondaryBulkLoad=true. */
|
||||
StoreConfig config = new StoreConfig();
|
||||
config.setAllowCreate(true);
|
||||
config.setSecondaryBulkLoad(true);
|
||||
open(config);
|
||||
|
||||
/* Getting priX should not create the secondary index. */
|
||||
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
|
||||
PersistTestUtils.assertDbExists
|
||||
(false, env, STORE_NAME, RelatedX.class.getName(), "key2");
|
||||
|
||||
/* We can put records that violate the secondary key constraint. */
|
||||
priX.put(new RelatedX());
|
||||
|
||||
if (closeAndOpenNormally) {
|
||||
/* Open normally and the secondary will be populated. */
|
||||
close();
|
||||
open();
|
||||
try {
|
||||
/* Before adding the foreign key, constraint is violated. */
|
||||
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
|
||||
} catch (DatabaseException e) {
|
||||
assertTrue(e.toString(),
|
||||
e.toString().contains("foreign key not allowed"));
|
||||
}
|
||||
/* Add the foreign key to avoid the constraint error. */
|
||||
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
|
||||
priY.put(new RelatedY());
|
||||
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
|
||||
PersistTestUtils.assertDbExists
|
||||
(true, env, STORE_NAME, RelatedX.class.getName(), "key2");
|
||||
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
|
||||
} else {
|
||||
/* Get secondary index explicitly and it will be populated. */
|
||||
try {
|
||||
/* Before adding the foreign key, constraint is violated. */
|
||||
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
|
||||
} catch (DatabaseException e) {
|
||||
assertTrue(e.toString(),
|
||||
e.toString().contains("foreign key not allowed"));
|
||||
}
|
||||
/* Add the foreign key. */
|
||||
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
|
||||
priY.put(new RelatedY());
|
||||
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
|
||||
PersistTestUtils.assertDbExists
|
||||
(true, env, STORE_NAME, RelatedX.class.getName(), "key2");
|
||||
}
|
||||
|
||||
RelatedX x = secX.get(88);
|
||||
assertNotNull(x);
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2000,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: PersistTestUtils.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.Database;
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
import com.sleepycat.db.Environment;
|
||||
|
||||
class PersistTestUtils {
|
||||
|
||||
/**
|
||||
* Asserts than a database expectExists or does not exist. If keyName is
|
||||
* null, checks an entity database. If keyName is non-null, checks a
|
||||
* secondary database.
|
||||
*/
|
||||
static void assertDbExists(boolean expectExists,
|
||||
Environment env,
|
||||
String storeName,
|
||||
String entityClassName,
|
||||
String keyName) {
|
||||
String fileName;
|
||||
String dbName;
|
||||
if (DbCompat.SEPARATE_DATABASE_FILES) {
|
||||
fileName = storeName + '-' + entityClassName;
|
||||
if (keyName != null) {
|
||||
fileName += "-" + keyName;
|
||||
}
|
||||
dbName = null;
|
||||
} else {
|
||||
fileName = null;
|
||||
dbName = "persist#" + storeName + '#' + entityClassName;
|
||||
if (keyName != null) {
|
||||
dbName += "#" + keyName;
|
||||
}
|
||||
}
|
||||
boolean exists;
|
||||
try {
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setReadOnly(true);
|
||||
Database db = DbCompat.openDatabase
|
||||
(env, null/*txn*/, fileName, dbName, config);
|
||||
db.close();
|
||||
exists = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
exists = false;
|
||||
} catch (Exception e) {
|
||||
/* Any other exception means the DB does exist. */
|
||||
exists = true;
|
||||
}
|
||||
if (expectExists != exists) {
|
||||
TestCase.fail
|
||||
((expectExists ? "Does not exist: " : "Does exist: ") +
|
||||
dbName);
|
||||
}
|
||||
}
|
||||
}
|
||||
477
test/scr024/src/com/sleepycat/persist/test/SequenceTest.java
Normal file
477
test/scr024/src/com/sleepycat/persist/test/SequenceTest.java
Normal file
@@ -0,0 +1,477 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: SequenceTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.KeyField;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class SequenceTest extends TestCase {
|
||||
|
||||
private File envHome;
|
||||
private Environment env;
|
||||
|
||||
public void setUp()
|
||||
throws IOException {
|
||||
|
||||
envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR));
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
}
|
||||
|
||||
public void tearDown()
|
||||
throws IOException {
|
||||
|
||||
if (env != null) {
|
||||
try {
|
||||
env.close();
|
||||
} catch (DatabaseException e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
} catch (Error e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
envHome = null;
|
||||
env = null;
|
||||
}
|
||||
|
||||
public void testSequenceKeys()
|
||||
throws Exception {
|
||||
|
||||
Class[] classes = {
|
||||
SequenceEntity_Long.class,
|
||||
SequenceEntity_Integer.class,
|
||||
SequenceEntity_Short.class,
|
||||
SequenceEntity_Byte.class,
|
||||
SequenceEntity_tlong.class,
|
||||
SequenceEntity_tint.class,
|
||||
SequenceEntity_tshort.class,
|
||||
SequenceEntity_tbyte.class,
|
||||
SequenceEntity_Long_composite.class,
|
||||
SequenceEntity_Integer_composite.class,
|
||||
SequenceEntity_Short_composite.class,
|
||||
SequenceEntity_Byte_composite.class,
|
||||
SequenceEntity_tlong_composite.class,
|
||||
SequenceEntity_tint_composite.class,
|
||||
SequenceEntity_tshort_composite.class,
|
||||
SequenceEntity_tbyte_composite.class,
|
||||
};
|
||||
|
||||
EnvironmentConfig envConfig = TestEnv.BDB.getConfig();
|
||||
envConfig.setAllowCreate(true);
|
||||
env = new Environment(envHome, envConfig);
|
||||
|
||||
StoreConfig storeConfig = new StoreConfig();
|
||||
storeConfig.setAllowCreate(true);
|
||||
EntityStore store = new EntityStore(env, "foo", storeConfig);
|
||||
|
||||
long seq = 0;
|
||||
|
||||
for (int i = 0; i < classes.length; i += 1) {
|
||||
Class entityCls = classes[i];
|
||||
SequenceEntity entity = (SequenceEntity) entityCls.newInstance();
|
||||
Class keyCls = entity.getKeyClass();
|
||||
|
||||
PrimaryIndex<Object,SequenceEntity> index =
|
||||
store.getPrimaryIndex(keyCls, entityCls);
|
||||
index.putNoReturn(entity);
|
||||
seq += 1;
|
||||
assertEquals(seq, entity.getKey());
|
||||
|
||||
index.putNoReturn(entity);
|
||||
assertEquals(seq, entity.getKey());
|
||||
|
||||
entity.nullifyKey();
|
||||
index.putNoReturn(entity);
|
||||
seq += 1;
|
||||
assertEquals(seq, entity.getKey());
|
||||
}
|
||||
|
||||
store.close();
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
|
||||
interface SequenceEntity {
|
||||
Class getKeyClass();
|
||||
long getKey();
|
||||
void nullifyKey();
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Long implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Long priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Integer implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Integer priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Short implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Short priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Short.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Byte implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Byte priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Byte.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tlong implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
long priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tint implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
int priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tshort implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
short priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Short.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tbyte implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
byte priKey;
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Byte.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Long_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
Long priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Integer_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
Integer priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Short_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
Short priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_Byte_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
Byte priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tlong_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
long priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tint_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
int priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tshort_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
short priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class SequenceEntity_tbyte_composite implements SequenceEntity {
|
||||
|
||||
@PrimaryKey(sequence="X")
|
||||
Key priKey;
|
||||
|
||||
@Persistent
|
||||
static class Key {
|
||||
@KeyField(1)
|
||||
byte priKey;
|
||||
}
|
||||
|
||||
public Class getKeyClass() {
|
||||
return Key.class;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return priKey.priKey;
|
||||
}
|
||||
|
||||
public void nullifyKey() {
|
||||
priKey = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: SubclassIndexTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.persist.test;
|
||||
|
||||
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.persist.EntityCursor;
|
||||
import com.sleepycat.persist.EntityStore;
|
||||
import com.sleepycat.persist.PrimaryIndex;
|
||||
import com.sleepycat.persist.SecondaryIndex;
|
||||
import com.sleepycat.persist.StoreConfig;
|
||||
import com.sleepycat.persist.model.Entity;
|
||||
import com.sleepycat.persist.model.Persistent;
|
||||
import com.sleepycat.persist.model.PrimaryKey;
|
||||
import com.sleepycat.persist.model.SecondaryKey;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
import com.sleepycat.util.test.TestEnv;
|
||||
|
||||
public class SubclassIndexTest extends TestCase {
|
||||
|
||||
private File envHome;
|
||||
private Environment env;
|
||||
|
||||
public void setUp()
|
||||
throws IOException {
|
||||
|
||||
envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR));
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
}
|
||||
|
||||
public void tearDown()
|
||||
throws IOException {
|
||||
|
||||
if (env != null) {
|
||||
try {
|
||||
env.close();
|
||||
} catch (DatabaseException e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
} catch (Error e) {
|
||||
System.out.println("During tearDown: " + e);
|
||||
}
|
||||
envHome = null;
|
||||
env = null;
|
||||
}
|
||||
|
||||
public void testSubclassIndex()
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
EnvironmentConfig envConfig = TestEnv.BDB.getConfig();
|
||||
envConfig.setAllowCreate(true);
|
||||
env = new Environment(envHome, envConfig);
|
||||
|
||||
StoreConfig storeConfig = new StoreConfig();
|
||||
storeConfig.setAllowCreate(true);
|
||||
EntityStore store = new EntityStore(env, "foo", storeConfig);
|
||||
|
||||
PrimaryIndex<String, Employee> employeesById =
|
||||
store.getPrimaryIndex(String.class, Employee.class);
|
||||
|
||||
employeesById.put(new Employee("1"));
|
||||
employeesById.put(new Manager("2", "a"));
|
||||
employeesById.put(new Manager("3", "a"));
|
||||
employeesById.put(new Manager("4", "b"));
|
||||
|
||||
Employee e;
|
||||
Manager m;
|
||||
|
||||
e = employeesById.get("1");
|
||||
assertNotNull(e);
|
||||
assertTrue(!(e instanceof Manager));
|
||||
|
||||
/* Ensure DB exists BEFORE calling getSubclassIndex. [#15247] */
|
||||
PersistTestUtils.assertDbExists
|
||||
(true, env, "foo", Employee.class.getName(), "dept");
|
||||
|
||||
/* Normal use: Subclass index for a key in the subclass. */
|
||||
SecondaryIndex<String, String, Manager> managersByDept =
|
||||
store.getSubclassIndex
|
||||
(employeesById, Manager.class, String.class, "dept");
|
||||
|
||||
m = managersByDept.get("a");
|
||||
assertNotNull(m);
|
||||
assertEquals("2", m.id);
|
||||
|
||||
m = managersByDept.get("b");
|
||||
assertNotNull(m);
|
||||
assertEquals("4", m.id);
|
||||
|
||||
EntityCursor<Manager> managers = managersByDept.entities();
|
||||
try {
|
||||
m = managers.next();
|
||||
assertNotNull(m);
|
||||
assertEquals("2", m.id);
|
||||
m = managers.next();
|
||||
assertNotNull(m);
|
||||
assertEquals("3", m.id);
|
||||
m = managers.next();
|
||||
assertNotNull(m);
|
||||
assertEquals("4", m.id);
|
||||
m = managers.next();
|
||||
assertNull(m);
|
||||
} finally {
|
||||
managers.close();
|
||||
}
|
||||
|
||||
/* Getting a subclass index for the entity class is also allowed. */
|
||||
store.getSubclassIndex
|
||||
(employeesById, Employee.class, String.class, "other");
|
||||
|
||||
/* Getting a subclass index for a base class key is not allowed. */
|
||||
try {
|
||||
store.getSubclassIndex
|
||||
(employeesById, Manager.class, String.class, "other");
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
store.close();
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class Employee {
|
||||
|
||||
@PrimaryKey
|
||||
String id;
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
String other;
|
||||
|
||||
Employee(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private Employee() {}
|
||||
}
|
||||
|
||||
@Persistent
|
||||
private static class Manager extends Employee {
|
||||
|
||||
@SecondaryKey(relate=MANY_TO_ONE)
|
||||
String dept;
|
||||
|
||||
Manager(String id, String dept) {
|
||||
super(id);
|
||||
this.dept = dept;
|
||||
}
|
||||
|
||||
private Manager() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ExceptionWrapperTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.util.ExceptionUnwrapper;
|
||||
import com.sleepycat.util.IOExceptionWrapper;
|
||||
import com.sleepycat.util.RuntimeExceptionWrapper;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class ExceptionWrapperTest extends TestCase {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(ExceptionWrapperTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public ExceptionWrapperTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("ExceptionWrapperTest." + getName());
|
||||
}
|
||||
|
||||
public void testIOWrapper()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
throw new IOExceptionWrapper(new RuntimeException("msg"));
|
||||
} catch (IOException e) {
|
||||
Exception ee = ExceptionUnwrapper.unwrap(e);
|
||||
assertTrue(ee instanceof RuntimeException);
|
||||
assertEquals("msg", ee.getMessage());
|
||||
|
||||
Throwable t = ExceptionUnwrapper.unwrapAny(e);
|
||||
assertTrue(t instanceof RuntimeException);
|
||||
assertEquals("msg", t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRuntimeWrapper()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
throw new RuntimeExceptionWrapper(new IOException("msg"));
|
||||
} catch (RuntimeException e) {
|
||||
Exception ee = ExceptionUnwrapper.unwrap(e);
|
||||
assertTrue(ee instanceof IOException);
|
||||
assertEquals("msg", ee.getMessage());
|
||||
|
||||
Throwable t = ExceptionUnwrapper.unwrapAny(e);
|
||||
assertTrue(t instanceof IOException);
|
||||
assertEquals("msg", t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testErrorWrapper()
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
throw new RuntimeExceptionWrapper(new Error("msg"));
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
ExceptionUnwrapper.unwrap(e);
|
||||
fail();
|
||||
} catch (Error ee) {
|
||||
assertTrue(ee instanceof Error);
|
||||
assertEquals("msg", ee.getMessage());
|
||||
}
|
||||
|
||||
Throwable t = ExceptionUnwrapper.unwrapAny(e);
|
||||
assertTrue(t instanceof Error);
|
||||
assertEquals("msg", t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stack trace for a nested exception and checks the output
|
||||
* for the nested exception.
|
||||
*/
|
||||
public void testStackTrace() {
|
||||
|
||||
/* Nested stack traces are not avilable in Java 1.3. */
|
||||
String version = System.getProperty("java.version");
|
||||
if (version.startsWith("1.3.")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Exception ex = new Exception("some exception");
|
||||
String causedBy = "Caused by: java.lang.Exception: some exception";
|
||||
|
||||
try {
|
||||
throw new RuntimeExceptionWrapper(ex);
|
||||
} catch (RuntimeException e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
String s = sw.toString();
|
||||
assertTrue(s.indexOf(causedBy) != -1);
|
||||
}
|
||||
|
||||
try {
|
||||
throw new IOExceptionWrapper(ex);
|
||||
} catch (IOException e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
String s = sw.toString();
|
||||
assertTrue(s.indexOf(causedBy) != -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: FastOutputStreamTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.util.FastOutputStream;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class FastOutputStreamTest extends TestCase {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(FastOutputStreamTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public FastOutputStreamTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("FastOutputStreamTest." + getName());
|
||||
}
|
||||
|
||||
public void testBufferSizing()
|
||||
throws Exception {
|
||||
|
||||
FastOutputStream fos = new FastOutputStream();
|
||||
assertEquals
|
||||
(FastOutputStream.DEFAULT_INIT_SIZE, fos.getBufferBytes().length);
|
||||
|
||||
/* Write X+1 bytes, expect array size 2X+1 */
|
||||
fos.write(new byte[FastOutputStream.DEFAULT_INIT_SIZE + 1]);
|
||||
assertEquals
|
||||
((FastOutputStream.DEFAULT_INIT_SIZE * 2) + 1,
|
||||
fos.getBufferBytes().length);
|
||||
|
||||
/* Write X+1 bytes, expect array size 4X+3 = (2(2X+1) + 1) */
|
||||
fos.write(new byte[FastOutputStream.DEFAULT_INIT_SIZE + 1]);
|
||||
assertEquals
|
||||
((FastOutputStream.DEFAULT_INIT_SIZE * 4) + 3,
|
||||
fos.getBufferBytes().length);
|
||||
}
|
||||
}
|
||||
191
test/scr024/src/com/sleepycat/util/test/PackedIntegerTest.java
Normal file
191
test/scr024/src/com/sleepycat/util/test/PackedIntegerTest.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: PackedIntegerTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import com.sleepycat.util.PackedInteger;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class PackedIntegerTest extends TestCase
|
||||
{
|
||||
static final long V119 = 119L;
|
||||
static final long MAX_1 = 0xFFL;
|
||||
static final long MAX_2 = 0xFFFFL;
|
||||
static final long MAX_3 = 0xFFFFFFL;
|
||||
static final long MAX_4 = 0xFFFFFFFFL;
|
||||
static final long MAX_5 = 0xFFFFFFFFFFL;
|
||||
static final long MAX_6 = 0xFFFFFFFFFFFFL;
|
||||
static final long MAX_7 = 0xFFFFFFFFFFFFFFL;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
|
||||
return new PackedIntegerTest();
|
||||
}
|
||||
|
||||
public PackedIntegerTest() {
|
||||
|
||||
super("PackedIntegerTest");
|
||||
}
|
||||
|
||||
public void runTest() {
|
||||
|
||||
/* Packed int tests. */
|
||||
|
||||
testIntRange(-V119, V119, 1);
|
||||
|
||||
testIntRange(-MAX_1 - V119, -1 - V119, 2);
|
||||
testIntRange(1 + V119, MAX_1 + V119, 2);
|
||||
|
||||
testIntRange(-MAX_2 - V119, -MAX_2 + 99, 3);
|
||||
testIntRange(-MAX_1 - V119 - 99, -MAX_1 - V119 - 1, 3);
|
||||
testIntRange(MAX_1 + V119 + 1, MAX_1 + V119 + 99, 3);
|
||||
testIntRange(MAX_2 - 99, MAX_2 + V119, 3);
|
||||
|
||||
testIntRange(-MAX_3 - V119, -MAX_3 + 99, 4);
|
||||
testIntRange(-MAX_2 - V119 - 99, -MAX_2 - V119 - 1, 4);
|
||||
testIntRange(MAX_2 + V119 + 1, MAX_2 + V119 + 99, 4);
|
||||
testIntRange(MAX_3 - 99, MAX_3 + V119, 4);
|
||||
|
||||
testIntRange(Integer.MIN_VALUE, Integer.MIN_VALUE + 99, 5);
|
||||
testIntRange(Integer.MAX_VALUE - 99, Integer.MAX_VALUE, 5);
|
||||
|
||||
/* Packed long tests. */
|
||||
|
||||
testLongRange(-V119, V119, 1);
|
||||
|
||||
testLongRange(-MAX_1 - V119, -1 - V119, 2);
|
||||
testLongRange(1 + V119, MAX_1 + V119, 2);
|
||||
|
||||
testLongRange(-MAX_2 - V119, -MAX_2 + 99, 3);
|
||||
testLongRange(-MAX_1 - V119 - 99, -MAX_1 - V119 - 1, 3);
|
||||
testLongRange(MAX_1 + V119 + 1, MAX_1 + V119 + 99, 3);
|
||||
testLongRange(MAX_2 - 99, MAX_2 + V119, 3);
|
||||
|
||||
testLongRange(-MAX_3 - V119, -MAX_3 + 99, 4);
|
||||
testLongRange(-MAX_2 - V119 - 99, -MAX_2 - V119 - 1, 4);
|
||||
testLongRange(MAX_2 + V119 + 1, MAX_2 + V119 + 99, 4);
|
||||
testLongRange(MAX_3 - 99, MAX_3 + V119, 4);
|
||||
|
||||
testLongRange(-MAX_4 - V119, -MAX_4 + 99, 5);
|
||||
testLongRange(-MAX_3 - V119 - 99, -MAX_3 - V119 - 1, 5);
|
||||
testLongRange(MAX_3 + V119 + 1, MAX_3 + V119 + 99, 5);
|
||||
testLongRange(MAX_4 - 99, MAX_4 + V119, 5);
|
||||
|
||||
testLongRange(-MAX_5 - V119, -MAX_5 + 99, 6);
|
||||
testLongRange(-MAX_4 - V119 - 99, -MAX_4 - V119 - 1, 6);
|
||||
testLongRange(MAX_4 + V119 + 1, MAX_4 + V119 + 99, 6);
|
||||
testLongRange(MAX_5 - 99, MAX_5 + V119, 6);
|
||||
|
||||
testLongRange(-MAX_6 - V119, -MAX_6 + 99, 7);
|
||||
testLongRange(-MAX_5 - V119 - 99, -MAX_5 - V119 - 1, 7);
|
||||
testLongRange(MAX_5 + V119 + 1, MAX_5 + V119 + 99, 7);
|
||||
testLongRange(MAX_6 - 99, MAX_6 + V119, 7);
|
||||
|
||||
testLongRange(-MAX_7 - V119, -MAX_7 + 99, 8);
|
||||
testLongRange(-MAX_6 - V119 - 99, -MAX_6 - V119 - 1, 8);
|
||||
testLongRange(MAX_6 + V119 + 1, MAX_6 + V119 + 99, 8);
|
||||
testLongRange(MAX_7 - 99, MAX_7 + V119, 8);
|
||||
|
||||
testLongRange(Long.MIN_VALUE, Long.MIN_VALUE + 99, 9);
|
||||
testLongRange(Long.MAX_VALUE - 99, Long.MAX_VALUE - 1, 9);
|
||||
}
|
||||
|
||||
private void testIntRange(long firstValue,
|
||||
long lastValue,
|
||||
int bytesExpected) {
|
||||
|
||||
byte[] buf = new byte[1000];
|
||||
int off = 0;
|
||||
|
||||
for (long longI = firstValue; longI <= lastValue; longI += 1) {
|
||||
int i = (int) longI;
|
||||
int before = off;
|
||||
off = PackedInteger.writeInt(buf, off, i);
|
||||
int bytes = off - before;
|
||||
if (bytes != bytesExpected) {
|
||||
fail("output of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
bytes = PackedInteger.getWriteIntLength(i);
|
||||
if (bytes != bytesExpected) {
|
||||
fail("count of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
}
|
||||
|
||||
off = 0;
|
||||
|
||||
for (long longI = firstValue; longI <= lastValue; longI += 1) {
|
||||
int i = (int) longI;
|
||||
int bytes = PackedInteger.getReadIntLength(buf, off);
|
||||
if (bytes != bytesExpected) {
|
||||
fail("count of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
int value = PackedInteger.readInt(buf, off);
|
||||
if (value != i) {
|
||||
fail("input of value=" + i + " but got=" + value);
|
||||
}
|
||||
off += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
private void testLongRange(long firstValue,
|
||||
long lastValue,
|
||||
int bytesExpected) {
|
||||
|
||||
byte[] buf = new byte[2000];
|
||||
int off = 0;
|
||||
|
||||
for (long longI = firstValue; longI <= lastValue; longI += 1) {
|
||||
long i = longI;
|
||||
int before = off;
|
||||
off = PackedInteger.writeLong(buf, off, i);
|
||||
int bytes = off - before;
|
||||
if (bytes != bytesExpected) {
|
||||
fail("output of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
bytes = PackedInteger.getWriteLongLength(i);
|
||||
if (bytes != bytesExpected) {
|
||||
fail("count of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
}
|
||||
|
||||
off = 0;
|
||||
|
||||
for (long longI = firstValue; longI <= lastValue; longI += 1) {
|
||||
long i = longI;
|
||||
int bytes = PackedInteger.getReadLongLength(buf, off);
|
||||
if (bytes != bytesExpected) {
|
||||
fail("count of value=" + i + " bytes=" + bytes +
|
||||
" bytesExpected=" + bytesExpected);
|
||||
}
|
||||
long value = PackedInteger.readLong(buf, off);
|
||||
if (value != i) {
|
||||
fail("input of value=" + i + " but got=" + value);
|
||||
}
|
||||
off += bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
192
test/scr024/src/com/sleepycat/util/test/SharedTestUtils.java
Normal file
192
test/scr024/src/com/sleepycat/util/test/SharedTestUtils.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: SharedTestUtils.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sleepycat.db.DatabaseConfig;
|
||||
|
||||
/**
|
||||
* Test utility methods shared by JE and DB core tests. Collections and
|
||||
* persist package test are used in both JE and DB core.
|
||||
*/
|
||||
public class SharedTestUtils {
|
||||
|
||||
/* Common system properties for running tests */
|
||||
public static String DEST_DIR = "testdestdir";
|
||||
public static String NO_SYNC = "txnnosync";
|
||||
public static String LONG_TEST = "longtest";
|
||||
|
||||
public static final DatabaseConfig DBCONFIG_CREATE = new DatabaseConfig();
|
||||
static {
|
||||
DBCONFIG_CREATE.setAllowCreate(true);
|
||||
}
|
||||
|
||||
private static File getTestDir() {
|
||||
String dir = System.getProperty(DEST_DIR);
|
||||
if (dir == null || dir.length() == 0) {
|
||||
throw new IllegalArgumentException
|
||||
("System property must be set to test data directory: " +
|
||||
DEST_DIR);
|
||||
}
|
||||
return new File(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if long running tests are enabled via setting the system
|
||||
* property longtest=true.
|
||||
*/
|
||||
public static boolean runLongTests() {
|
||||
String longTestProp = System.getProperty(LONG_TEST);
|
||||
if ((longTestProp != null) &&
|
||||
longTestProp.equalsIgnoreCase("true")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void printTestName(String name) {
|
||||
// don't want verbose printing for now
|
||||
// System.out.println(name);
|
||||
}
|
||||
|
||||
public static File getExistingDir(String name)
|
||||
throws IOException {
|
||||
|
||||
File dir = new File(getTestDir(), name);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException(
|
||||
"Not an existing directory: " + dir);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getNewDir()
|
||||
throws IOException {
|
||||
|
||||
return getNewDir("test-dir");
|
||||
}
|
||||
|
||||
public static void emptyDir(File dir)
|
||||
throws IOException {
|
||||
|
||||
if (dir.isDirectory()) {
|
||||
String[] files = dir.list();
|
||||
if (files != null) {
|
||||
for (int i = 0; i < files.length; i += 1) {
|
||||
new File(dir, files[i]).delete();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dir.delete();
|
||||
dir.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getNewDir(String name)
|
||||
throws IOException {
|
||||
|
||||
File dir = new File(getTestDir(), name);
|
||||
emptyDir(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getNewFile()
|
||||
throws IOException {
|
||||
|
||||
return getNewFile("test-file");
|
||||
}
|
||||
|
||||
public static File getNewFile(String name)
|
||||
throws IOException {
|
||||
|
||||
return getNewFile(getTestDir(), name);
|
||||
}
|
||||
|
||||
public static File getNewFile(File dir, String name)
|
||||
throws IOException {
|
||||
|
||||
File file = new File(dir, name);
|
||||
file.delete();
|
||||
return file;
|
||||
}
|
||||
|
||||
public static boolean copyResource(Class cls, String fileName, File toDir)
|
||||
throws IOException {
|
||||
|
||||
InputStream in = cls.getResourceAsStream("testdata/" + fileName);
|
||||
if (in == null) {
|
||||
return false;
|
||||
}
|
||||
in = new BufferedInputStream(in);
|
||||
File file = new File(toDir, fileName);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
out = new BufferedOutputStream(out);
|
||||
int c;
|
||||
while ((c = in.read()) >= 0) out.write(c);
|
||||
in.close();
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String qualifiedTestName(TestCase test) {
|
||||
|
||||
String s = test.getClass().getName();
|
||||
int i = s.lastIndexOf('.');
|
||||
if (i >= 0) {
|
||||
s = s.substring(i + 1);
|
||||
}
|
||||
return s + '.' + test.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all files in fromDir to toDir. Does not copy subdirectories.
|
||||
*/
|
||||
public static void copyFiles(File fromDir, File toDir)
|
||||
throws IOException {
|
||||
|
||||
String[] names = fromDir.list();
|
||||
if (names != null) {
|
||||
for (int i = 0; i < names.length; i += 1) {
|
||||
File fromFile = new File(fromDir, names[i]);
|
||||
if (fromFile.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
File toFile = new File(toDir, names[i]);
|
||||
int len = (int) fromFile.length();
|
||||
byte[] data = new byte[len];
|
||||
FileInputStream fis = null;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fis = new FileInputStream(fromFile);
|
||||
fos = new FileOutputStream(toFile);
|
||||
fis.read(data);
|
||||
fos.write(data);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
144
test/scr024/src/com/sleepycat/util/test/TestEnv.java
Normal file
144
test/scr024/src/com/sleepycat/util/test/TestEnv.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TestEnv.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sleepycat.compat.DbCompat;
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class TestEnv {
|
||||
|
||||
public static final TestEnv BDB;
|
||||
public static final TestEnv CDB;
|
||||
public static final TestEnv TXN;
|
||||
static {
|
||||
EnvironmentConfig config;
|
||||
|
||||
config = newEnvConfig();
|
||||
BDB = new TestEnv("bdb", config);
|
||||
|
||||
if (DbCompat.CDB) {
|
||||
config = newEnvConfig();
|
||||
DbCompat.setInitializeCDB(config, true);
|
||||
CDB = new TestEnv("cdb", config);
|
||||
} else {
|
||||
CDB = null;
|
||||
}
|
||||
|
||||
config = newEnvConfig();
|
||||
config.setTransactional(true);
|
||||
DbCompat.setInitializeLocking(config, true);
|
||||
TXN = new TestEnv("txn", config);
|
||||
}
|
||||
|
||||
private static EnvironmentConfig newEnvConfig() {
|
||||
|
||||
EnvironmentConfig config = new EnvironmentConfig();
|
||||
config.setTxnNoSync(Boolean.getBoolean(SharedTestUtils.NO_SYNC));
|
||||
if (DbCompat.MEMORY_SUBSYSTEM) {
|
||||
DbCompat.setInitializeCache(config, true);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public static final TestEnv[] ALL;
|
||||
static {
|
||||
if (DbCompat.CDB) {
|
||||
ALL = new TestEnv[] { BDB, CDB, TXN };
|
||||
} else {
|
||||
ALL = new TestEnv[] { BDB, TXN };
|
||||
}
|
||||
}
|
||||
|
||||
private String name;
|
||||
private EnvironmentConfig config;
|
||||
|
||||
protected TestEnv(String name, EnvironmentConfig config) {
|
||||
|
||||
this.name = name;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public EnvironmentConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
void copyConfig(EnvironmentConfig copyToConfig) {
|
||||
DbCompat.setInitializeCache
|
||||
(copyToConfig, DbCompat.getInitializeCache(config));
|
||||
DbCompat.setInitializeLocking
|
||||
(copyToConfig, DbCompat.getInitializeLocking(config));
|
||||
DbCompat.setInitializeCDB
|
||||
(copyToConfig, DbCompat.getInitializeCDB(config));
|
||||
copyToConfig.setTransactional(config.getTransactional());
|
||||
}
|
||||
|
||||
public boolean isTxnMode() {
|
||||
|
||||
return config.getTransactional();
|
||||
}
|
||||
|
||||
public boolean isCdbMode() {
|
||||
|
||||
return DbCompat.getInitializeCDB(config);
|
||||
}
|
||||
|
||||
public Environment open(String testName)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
return open(testName, true);
|
||||
}
|
||||
|
||||
public Environment open(String testName, boolean create)
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
config.setAllowCreate(create);
|
||||
/* OLDEST deadlock detection on DB matches the use of timeouts on JE.*/
|
||||
DbCompat.setLockDetectModeOldest(config);
|
||||
File dir = getDirectory(testName, create);
|
||||
return newEnvironment(dir, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is overridden in XACollectionTest.
|
||||
*/
|
||||
protected Environment newEnvironment(File dir, EnvironmentConfig config)
|
||||
throws DatabaseException, IOException {
|
||||
|
||||
return new Environment(dir, config);
|
||||
}
|
||||
|
||||
public File getDirectory(String testName)
|
||||
throws IOException {
|
||||
|
||||
return getDirectory(testName, true);
|
||||
}
|
||||
|
||||
public File getDirectory(String testName, boolean create)
|
||||
throws IOException {
|
||||
|
||||
if (create) {
|
||||
return SharedTestUtils.getNewDir(testName);
|
||||
} else {
|
||||
return SharedTestUtils.getExistingDir(testName);
|
||||
}
|
||||
}
|
||||
}
|
||||
223
test/scr024/src/com/sleepycat/util/test/TxnTestCase.java
Normal file
223
test/scr024/src/com/sleepycat/util/test/TxnTestCase.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: TxnTestCase.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.db.DatabaseException;
|
||||
import com.sleepycat.db.Environment;
|
||||
import com.sleepycat.db.EnvironmentConfig;
|
||||
import com.sleepycat.db.Transaction;
|
||||
import com.sleepycat.db.TransactionConfig;
|
||||
|
||||
/**
|
||||
* Permuates test cases over three transaction types: null (non-transactional),
|
||||
* auto-commit, and user (explicit).
|
||||
*
|
||||
* <p>Overrides runTest, setUp and tearDown to open/close the environment and to
|
||||
* set up protected members for use by test cases.</p>
|
||||
*
|
||||
* <p>If a subclass needs to override setUp or tearDown, the overridden method
|
||||
* should call super.setUp or super.tearDown.</p>
|
||||
*
|
||||
* <p>When writing a test case based on this class, write it as if a user txn
|
||||
* were always used: call txnBegin, txnCommit and txnAbort for all write
|
||||
* operations. Use the isTransactional protected field for setup of a database
|
||||
* config.</p>
|
||||
*/
|
||||
public abstract class TxnTestCase extends TestCase {
|
||||
|
||||
public static final String TXN_NULL = "txn-null";
|
||||
public static final String TXN_AUTO = "txn-auto";
|
||||
public static final String TXN_USER = "txn-user";
|
||||
|
||||
protected File envHome;
|
||||
protected Environment env;
|
||||
protected EnvironmentConfig envConfig;
|
||||
protected String txnType;
|
||||
protected boolean isTransactional;
|
||||
|
||||
/**
|
||||
* Returns a txn test suite. If txnTypes is null, all three types are run.
|
||||
*/
|
||||
public static TestSuite txnTestSuite(Class testCaseClass,
|
||||
EnvironmentConfig envConfig,
|
||||
String[] txnTypes) {
|
||||
if (txnTypes == null) {
|
||||
txnTypes = new String[] { TxnTestCase.TXN_NULL,
|
||||
TxnTestCase.TXN_USER,
|
||||
TxnTestCase.TXN_AUTO };
|
||||
}
|
||||
if (envConfig == null) {
|
||||
envConfig = new EnvironmentConfig();
|
||||
envConfig.setAllowCreate(true);
|
||||
}
|
||||
TestSuite suite = new TestSuite();
|
||||
for (int i = 0; i < txnTypes.length; i += 1) {
|
||||
TestSuite baseSuite = new TestSuite(testCaseClass);
|
||||
Enumeration e = baseSuite.tests();
|
||||
while (e.hasMoreElements()) {
|
||||
TxnTestCase test = (TxnTestCase) e.nextElement();
|
||||
test.txnInit(envConfig, txnTypes[i]);
|
||||
suite.addTest(test);
|
||||
}
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private void txnInit(EnvironmentConfig envConfig, String txnType) {
|
||||
|
||||
this.envConfig = envConfig;
|
||||
this.txnType = txnType;
|
||||
isTransactional = (txnType != TXN_NULL);
|
||||
}
|
||||
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
envHome = SharedTestUtils.getNewDir();
|
||||
}
|
||||
|
||||
public void runTest()
|
||||
throws Throwable {
|
||||
|
||||
openEnv();
|
||||
super.runTest();
|
||||
closeEnv();
|
||||
}
|
||||
|
||||
public void tearDown()
|
||||
throws Exception {
|
||||
|
||||
/* Set test name for reporting; cannot be done in the ctor or setUp. */
|
||||
setName(txnType + ':' + getName());
|
||||
|
||||
if (env != null) {
|
||||
try {
|
||||
env.close();
|
||||
} catch (Throwable e) {
|
||||
System.out.println("tearDown: " + e);
|
||||
}
|
||||
env = null;
|
||||
}
|
||||
|
||||
try {
|
||||
SharedTestUtils.emptyDir(envHome);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("tearDown: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the environment and sets the env field to null.
|
||||
* Used for closing and reopening the environment.
|
||||
*/
|
||||
public void closeEnv()
|
||||
throws DatabaseException {
|
||||
|
||||
if (env != null) {
|
||||
env.close();
|
||||
env = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the environment based on the txnType for this test case.
|
||||
* Used for closing and reopening the environment.
|
||||
*/
|
||||
public void openEnv()
|
||||
throws IOException, DatabaseException {
|
||||
|
||||
if (txnType == TXN_NULL) {
|
||||
TestEnv.BDB.copyConfig(envConfig);
|
||||
env = new Environment(envHome, envConfig);
|
||||
} else if (txnType == TXN_AUTO) {
|
||||
TestEnv.TXN.copyConfig(envConfig);
|
||||
env = new Environment(envHome, envConfig);
|
||||
} else if (txnType == TXN_USER) {
|
||||
TestEnv.TXN.copyConfig(envConfig);
|
||||
env = new Environment(envHome, envConfig);
|
||||
} else {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a txn if in TXN_USER mode; otherwise return null;
|
||||
*/
|
||||
protected Transaction txnBegin()
|
||||
throws DatabaseException {
|
||||
|
||||
return txnBegin(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a txn if in TXN_USER mode; otherwise return null;
|
||||
*/
|
||||
protected Transaction txnBegin(Transaction parentTxn,
|
||||
TransactionConfig config)
|
||||
throws DatabaseException {
|
||||
|
||||
if (txnType == TXN_USER) {
|
||||
return env.beginTransaction(parentTxn, config);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a txn if in TXN_USER or TXN_AUTO mode; otherwise return null;
|
||||
*/
|
||||
protected Transaction txnBeginCursor()
|
||||
throws DatabaseException {
|
||||
|
||||
return txnBeginCursor(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a txn if in TXN_USER or TXN_AUTO mode; otherwise return null;
|
||||
*/
|
||||
protected Transaction txnBeginCursor(Transaction parentTxn,
|
||||
TransactionConfig config)
|
||||
throws DatabaseException {
|
||||
|
||||
if (txnType == TXN_USER || txnType == TXN_AUTO) {
|
||||
return env.beginTransaction(parentTxn, config);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit a txn if non-null.
|
||||
*/
|
||||
protected void txnCommit(Transaction txn)
|
||||
throws DatabaseException {
|
||||
|
||||
if (txn != null) {
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit a txn if non-null.
|
||||
*/
|
||||
protected void txnAbort(Transaction txn)
|
||||
throws DatabaseException {
|
||||
|
||||
if (txn != null) {
|
||||
txn.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
168
test/scr024/src/com/sleepycat/util/test/UtfTest.java
Normal file
168
test/scr024/src/com/sleepycat/util/test/UtfTest.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: UtfTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
package com.sleepycat.util.test;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import com.sleepycat.util.FastOutputStream;
|
||||
import com.sleepycat.util.UtfOps;
|
||||
import com.sleepycat.util.test.SharedTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Hayes
|
||||
*/
|
||||
public class UtfTest extends TestCase {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
junit.framework.TestResult tr =
|
||||
junit.textui.TestRunner.run(suite());
|
||||
if (tr.errorCount() > 0 ||
|
||||
tr.failureCount() > 0) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
throws Exception {
|
||||
|
||||
TestSuite suite = new TestSuite(UtfTest.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public UtfTest(String name) {
|
||||
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
|
||||
SharedTestUtils.printTestName("UtfTest." + getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the UtfOps implementation to the java.util.DataOutputStream
|
||||
* (and by implication DataInputStream) implementation, character for
|
||||
* character in the full Unicode set.
|
||||
*/
|
||||
public void testMultibyte()
|
||||
throws Exception {
|
||||
|
||||
char c = 0;
|
||||
byte[] buf = new byte[10];
|
||||
byte[] javaBuf = new byte[10];
|
||||
char[] cArray = new char[1];
|
||||
FastOutputStream javaBufStream = new FastOutputStream(javaBuf);
|
||||
DataOutputStream javaOutStream = new DataOutputStream(javaBufStream);
|
||||
|
||||
try {
|
||||
for (int cInt = Character.MIN_VALUE; cInt <= Character.MAX_VALUE;
|
||||
cInt += 1) {
|
||||
c = (char) cInt;
|
||||
cArray[0] = c;
|
||||
int byteLen = UtfOps.getByteLength(cArray);
|
||||
|
||||
javaBufStream.reset();
|
||||
javaOutStream.writeUTF(new String(cArray));
|
||||
int javaByteLen = javaBufStream.size() - 2;
|
||||
|
||||
if (byteLen != javaByteLen) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps size " + byteLen +
|
||||
" != JavaIO size " + javaByteLen);
|
||||
}
|
||||
|
||||
Arrays.fill(buf, (byte) 0);
|
||||
UtfOps.charsToBytes(cArray, 0, buf, 0, 1);
|
||||
|
||||
if (byteLen == 1 && buf[0] == (byte) 0xff) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" was encoded as FF, which is reserved for null");
|
||||
}
|
||||
|
||||
for (int i = 0; i < byteLen; i += 1) {
|
||||
if (buf[i] != javaBuf[i + 2]) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" byte offset " + i +
|
||||
" UtfOps byte " + Integer.toHexString(buf[i]) +
|
||||
" != JavaIO byte " +
|
||||
Integer.toHexString(javaBuf[i + 2]));
|
||||
}
|
||||
}
|
||||
|
||||
int charLen = UtfOps.getCharLength(buf, 0, byteLen);
|
||||
if (charLen != 1) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps char len " + charLen +
|
||||
" but should be one");
|
||||
}
|
||||
|
||||
cArray[0] = (char) 0;
|
||||
int len = UtfOps.bytesToChars(buf, 0, cArray, 0, byteLen,
|
||||
true);
|
||||
if (len != byteLen) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps bytesToChars(w/byteLen) len " + len +
|
||||
" but should be " + byteLen);
|
||||
}
|
||||
|
||||
if (cArray[0] != c) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps bytesToChars(w/byteLen) char " +
|
||||
Integer.toHexString(cArray[0]));
|
||||
}
|
||||
|
||||
cArray[0] = (char) 0;
|
||||
len = UtfOps.bytesToChars(buf, 0, cArray, 0, 1, false);
|
||||
if (len != byteLen) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps bytesToChars(w/charLen) len " + len +
|
||||
" but should be " + byteLen);
|
||||
}
|
||||
|
||||
if (cArray[0] != c) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps bytesToChars(w/charLen) char " +
|
||||
Integer.toHexString(cArray[0]));
|
||||
}
|
||||
|
||||
String s = new String(cArray, 0, 1);
|
||||
byte[] sBytes = UtfOps.stringToBytes(s);
|
||||
if (sBytes.length != byteLen) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" UtfOps stringToBytes() len " + sBytes.length +
|
||||
" but should be " + byteLen);
|
||||
}
|
||||
|
||||
for (int i = 0; i < byteLen; i += 1) {
|
||||
if (sBytes[i] != javaBuf[i + 2]) {
|
||||
fail("Character 0x" + Integer.toHexString(c) +
|
||||
" byte offset " + i +
|
||||
" UtfOps byte " + Integer.toHexString(sBytes[i]) +
|
||||
" != JavaIO byte " +
|
||||
Integer.toHexString(javaBuf[i + 2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Character 0x" + Integer.toHexString(c) +
|
||||
" exception occurred");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user