From 641fdf861487e91b277fda8f06cc852842d14f60 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 2 Jun 2025 14:33:58 +0200 Subject: [PATCH 1/4] Preview --- .github/workflows/ci.yml | 17 + .github/workflows/maven-verify.yml | 16 - pom.xml | 232 +-- .../java/com/lambdazen/bitsy/BitsyEdge.java | 48 +- .../com/lambdazen/bitsy/BitsyElement.java | 70 +- .../com/lambdazen/bitsy/BitsyErrorCodes.java | 84 +- .../com/lambdazen/bitsy/BitsyException.java | 10 +- .../com/lambdazen/bitsy/BitsyFeatures.java | 73 +- .../java/com/lambdazen/bitsy/BitsyGraph.java | 307 ++-- .../com/lambdazen/bitsy/BitsyGraphMBean.java | 20 +- .../lambdazen/bitsy/BitsyGraphSONModule.java | 55 +- .../lambdazen/bitsy/BitsyIoRegistryV3d0.java | 68 +- .../com/lambdazen/bitsy/BitsyProperty.java | 20 +- .../lambdazen/bitsy/BitsyRetryException.java | 6 +- .../java/com/lambdazen/bitsy/BitsyState.java | 2 +- .../java/com/lambdazen/bitsy/BitsyVertex.java | 121 +- .../lambdazen/bitsy/BitsyVertexProperty.java | 21 +- .../com/lambdazen/bitsy/ICommitChanges.java | 2 +- .../java/com/lambdazen/bitsy/IGraphStore.java | 24 +- .../com/lambdazen/bitsy/ITransaction.java | 13 +- .../com/lambdazen/bitsy/PortDatabase.java | 222 +-- .../lambdazen/bitsy/ThreadedBitsyGraph.java | 139 +- src/main/java/com/lambdazen/bitsy/UUID.java | 27 +- .../bitsy/UUIDGraphBinarySerializer.java | 9 +- .../lambdazen/bitsy/ads/dict/Dictionary.java | 30 +- .../lambdazen/bitsy/ads/dict/Dictionary1.java | 104 +- .../bitsy/ads/dict/Dictionary11.java | 410 ++--- .../bitsy/ads/dict/Dictionary16.java | 577 +++--- .../lambdazen/bitsy/ads/dict/Dictionary2.java | 162 +- .../lambdazen/bitsy/ads/dict/Dictionary3.java | 182 +- .../lambdazen/bitsy/ads/dict/Dictionary4.java | 204 +-- .../lambdazen/bitsy/ads/dict/Dictionary6.java | 254 +-- .../lambdazen/bitsy/ads/dict/Dictionary8.java | 330 ++-- .../bitsy/ads/dict/DictionaryFactory.java | 6 +- .../bitsy/ads/dict/DictionaryMax.java | 140 +- .../bitsy/ads/dict/PrimitiveDictionary.java | 346 ++-- .../com/lambdazen/bitsy/ads/set/ArraySet.java | 18 +- .../bitsy/ads/set/CompactMultiSetMax.java | 42 +- .../lambdazen/bitsy/ads/set/CompactSet.java | 12 +- .../lambdazen/bitsy/ads/set/PrimitiveSet.java | 35 +- .../java/com/lambdazen/bitsy/ads/set/Set.java | 2 +- .../com/lambdazen/bitsy/ads/set/Set12.java | 114 +- .../com/lambdazen/bitsy/ads/set/Set2.java | 23 +- .../com/lambdazen/bitsy/ads/set/Set24.java | 261 +-- .../com/lambdazen/bitsy/ads/set/Set3.java | 25 +- .../com/lambdazen/bitsy/ads/set/Set4.java | 31 +- .../com/lambdazen/bitsy/ads/set/Set6.java | 43 +- .../com/lambdazen/bitsy/ads/set/Set8.java | 77 +- .../com/lambdazen/bitsy/ads/set/SetMax.java | 10 +- .../bitsy/gremlin/BitsyGraphStep.java | 81 +- .../bitsy/gremlin/BitsyTraversalStrategy.java | 57 +- .../com/lambdazen/bitsy/index/BitsyIndex.java | 21 +- .../lambdazen/bitsy/index/BitsyIndexMap.java | 28 +- .../com/lambdazen/bitsy/index/EdgeIndex.java | 12 +- .../lambdazen/bitsy/index/EdgeIndexMap.java | 3 +- .../lambdazen/bitsy/index/IndexHelper.java | 48 +- .../lambdazen/bitsy/index/VertexIndex.java | 11 +- .../lambdazen/bitsy/index/VertexIndexMap.java | 3 +- .../bitsy/jsr223/BitsyGremlinPlugin.java | 50 +- .../lambdazen/bitsy/store/AdjacencyMap.java | 88 +- .../bitsy/store/AdjacencyMapForBeans.java | 82 +- .../com/lambdazen/bitsy/store/BackupJob.java | 9 +- .../bitsy/store/CompactAndCopyTask.java | 173 +- .../com/lambdazen/bitsy/store/EdgeBean.java | 29 +- .../lambdazen/bitsy/store/EdgeBeanJson.java | 40 +- .../store/FileBackedMemoryGraphStore.java | 456 +++-- .../lambdazen/bitsy/store/ITxBatchJob.java | 4 +- .../lambdazen/bitsy/store/IVeReorgJob.java | 4 +- .../com/lambdazen/bitsy/store/IndexBean.java | 19 +- .../bitsy/store/JobWithCountDownLatch.java | 4 +- .../com/lambdazen/bitsy/store/LoadTask.java | 191 +- .../bitsy/store/MemoryGraphStore.java | 278 +-- .../bitsy/store/ParallelRecordReader.java | 71 +- .../com/lambdazen/bitsy/store/Record.java | 57 +- .../lambdazen/bitsy/store/RecordReader.java | 8 +- .../SingleThreadedStringCanonicalizer.java | 4 +- .../com/lambdazen/bitsy/store/TxBatch.java | 2 +- .../java/com/lambdazen/bitsy/store/TxLog.java | 4 +- .../bitsy/store/TxLogFlushPotential.java | 16 +- .../com/lambdazen/bitsy/store/TxUnit.java | 21 +- .../bitsy/store/VEObsolescencePotential.java | 21 +- .../com/lambdazen/bitsy/store/VertexBean.java | 18 +- .../lambdazen/bitsy/store/VertexBeanJson.java | 14 +- .../lambdazen/bitsy/tx/BitsyTransaction.java | 88 +- .../bitsy/tx/BitsyTransactionContext.java | 79 +- .../bitsy/util/BitsyElementIterator.java | 42 +- .../lambdazen/bitsy/util/BufferFlusher.java | 5 +- .../lambdazen/bitsy/util/BufferPotential.java | 2 +- .../lambdazen/bitsy/util/BufferQueuer.java | 2 +- .../bitsy/util/CommittableFileLog.java | 174 +- .../bitsy/util/DefaultCommitChanges.java | 13 +- .../lambdazen/bitsy/util/DoubleBuffer.java | 71 +- .../bitsy/util/DoubleBufferThread.java | 30 +- .../bitsy/util/DoubleBufferWithExecWork.java | 17 +- .../lambdazen/bitsy/util/EdgeIterator.java | 21 +- .../lambdazen/bitsy/util/VertexIterator.java | 21 +- .../bitsy/wrapper/BitsyAutoReloadingEdge.java | 50 +- .../wrapper/BitsyAutoReloadingGraph.java | 86 +- .../wrapper/BitsyAutoReloadingVertex.java | 88 +- .../com/lambdazen/bitsy/BitsyGraphIT.java | 1607 +++++++++-------- .../com/lambdazen/bitsy/BitsyMemGraphIT.java | 50 +- .../lambdazen/bitsy/FileBasedTestCase.java | 15 +- .../com/lambdazen/bitsy/RecoveryTest.java | 35 +- .../bitsy/ads/dict/DictionaryTest.java | 79 +- .../bitsy/ads/set/CompactMultiSetMaxTest.java | 72 +- .../com/lambdazen/bitsy/ads/set/SetTest.java | 78 +- .../lambdazen/bitsy/store/EndpointTest.java | 55 +- .../store/FileBackedMemoryGraphStoreTest.java | 235 ++- .../bitsy/store/MemoryGraphStoreTest.java | 239 +-- .../com/lambdazen/bitsy/store/RecordTest.java | 52 +- ...SingleThreadedStringCanonicalizerTest.java | 8 +- .../BitsyGraphStructureTestSuite.java | 78 +- .../BitsyProcessStandardTestSuite.java | 273 ++- .../structure/BitsyTestGraphProvider.java | 45 +- .../bitsy/structure/HasLabelTest.java | 8 +- .../bitsy/util/CommittableFileLogTest.java | 46 +- .../lambdazen/bitsy/util/DoubleBufferIT.java | 172 +- 117 files changed, 5635 insertions(+), 5272 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/maven-verify.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dd306e1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,17 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + build: + name: Verify + uses: maveniverse/parent/.github/workflows/ci.yml@release-39 + with: + maven-single-run: 'false' + jdk-matrix: '[ "8", "11", "17", "21", "24" ]' + maven-matrix: '[ "3.9.9", "4.0.0-rc-3" ]' + maven-test: './mvnw clean verify -e -B -V -P run-its' \ No newline at end of file diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml deleted file mode 100644 index 6b599cf..0000000 --- a/.github/workflows/maven-verify.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: maven-verify - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - name: Build with Maven - run: ./mvnw --batch-mode --update-snapshots verify diff --git a/pom.xml b/pom.xml index f7e11a2..eb4589b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,29 @@ + 4.0.0 + + eu.maveniverse.maven.parent + parent + 39 + + com.lambdazen.bitsy bitsy 3.6.3-SNAPSHOT Bitsy Graph Database + Bitsy v3 is a small, fast, embeddable, durable in-memory graph database that is compatible with Tinkerpop3 + + https://github.com/lambdazen/bitsy/ + 2013 + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + lambdazen @@ -20,12 +38,6 @@ https://www.cstamas.org - - Bitsy v3 is a small, fast, embeddable, durable in-memory graph database that is compatible with Tinkerpop3 - - - https://github.com/lambdazen/bitsy/ - 2013 scm:git:https://github.com/lambdazen/bitsy.git @@ -33,12 +45,18 @@ https://github.com/lambdazen/bitsy/ - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + UTF-8 @@ -46,7 +64,7 @@ 8 - 3.6.8 + 3.7.3 1.7.36 2.19.0 @@ -54,6 +72,78 @@ + + + org.apache.tinkerpop + gremlin-core + ${gremlin.version} + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + + + junit + junit + 4.13.2 + test + + + + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + + org.apache.tinkerpop + gremlin-test + ${gremlin.version} + test + + + + + + sonatype-snapshots @@ -61,19 +151,6 @@ - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots/ - - - sonatype-nexus-staging - Nexus Release Repository - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - @@ -253,93 +330,21 @@ org.apache.maven.plugins maven-dependency-plugin 3.8.1 - - - install - - copy-dependencies - - - ${project.build.directory}/lib - - - + + + + copy-dependencies + + install + + ${project.build.directory}/lib + + + - - - org.apache.tinkerpop - gremlin-core - ${gremlin.version} - - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - - - - junit - junit - 4.13.2 - test - - - - org.slf4j - slf4j-simple - ${slf4j.version} - test - - - - org.apache.tinkerpop - gremlin-test - ${gremlin.version} - test - - - - - - - it - - - it - true - - + run-its diff --git a/src/main/java/com/lambdazen/bitsy/BitsyEdge.java b/src/main/java/com/lambdazen/bitsy/BitsyEdge.java index 9ab315d..ab10b92 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyEdge.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyEdge.java @@ -1,44 +1,57 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.ads.dict.Dictionary; +import com.lambdazen.bitsy.store.EdgeBean; +import com.lambdazen.bitsy.store.EdgeBeanJson; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; -import com.lambdazen.bitsy.ads.dict.Dictionary; -import com.lambdazen.bitsy.store.EdgeBean; -import com.lambdazen.bitsy.store.EdgeBeanJson; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public class BitsyEdge extends BitsyElement implements Edge, IEdge { UUID outVertexId; UUID inVertexId; - - public BitsyEdge(UUID id, Dictionary properties, BitsyTransaction tx, BitsyState state, int version, String label, UUID outVertexId, UUID inVertexId) { + + public BitsyEdge( + UUID id, + Dictionary properties, + BitsyTransaction tx, + BitsyState state, + int version, + String label, + UUID outVertexId, + UUID inVertexId) { super(id, label, properties, tx, state, version); if (label == null) { throw new IllegalArgumentException("Edge label can not be null"); // Enforced by 2.3.0 test case } - + this.outVertexId = outVertexId; this.inVertexId = inVertexId; } public BitsyEdge(EdgeBean bean, BitsyTransaction tx, BitsyState state) { - this(bean.getId(), bean.getPropertiesDict(), - tx, state, bean.getVersion(), bean.getLabel(), bean.getOutVertexId(), bean.getInVertexId()); + this( + bean.getId(), + bean.getPropertiesDict(), + tx, + state, + bean.getVersion(), + bean.getLabel(), + bean.getOutVertexId(), + bean.getInVertexId()); } public EdgeBeanJson asJsonBean() { // The TX is usually not active at this point. So no checks. - return new EdgeBeanJson((UUID)id, properties, version, label, outVertexId, inVertexId, state); + return new EdgeBeanJson((UUID) id, properties, version, label, outVertexId, inVertexId, state); } @Override @@ -82,7 +95,10 @@ private Vertex inOrOutVertex(Direction dir) { // Vertex may disappear in READ_COMMITTED MODE if (ans == null) { - throw new BitsyRetryException(BitsyErrorCodes.CONCURRENT_MODIFICATION, "The vertex in direction " + dir + " of the edge " + this.id() + " was removed by another transaction"); + throw new BitsyRetryException( + BitsyErrorCodes.CONCURRENT_MODIFICATION, + "The vertex in direction " + dir + " of the edge " + this.id() + + " was removed by another transaction"); } return ans; @@ -109,7 +125,7 @@ public UUID getVertexId(Direction dir) { public void incrementVersion() { this.version++; } - + public void remove() { tx.removeEdge(this); } @@ -124,8 +140,8 @@ public Iterator> properties(String... propertyKeys) { ArrayList> ans = new ArrayList>(); if (propertyKeys.length == 0) { - if (this.properties == null) return Collections.emptyIterator(); - propertyKeys = this.properties.getPropertyKeys(); + if (this.properties == null) return Collections.emptyIterator(); + propertyKeys = this.properties.getPropertyKeys(); } for (String key : propertyKeys) { diff --git a/src/main/java/com/lambdazen/bitsy/BitsyElement.java b/src/main/java/com/lambdazen/bitsy/BitsyElement.java index f8480ab..c2871f6 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyElement.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyElement.java @@ -1,23 +1,25 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.ads.dict.Dictionary; +import com.lambdazen.bitsy.ads.dict.Dictionary1; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; - import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; -import com.lambdazen.bitsy.ads.dict.Dictionary; -import com.lambdazen.bitsy.ads.dict.Dictionary1; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public abstract class BitsyElement implements Element { - public static enum PropType {ELEMENT, VERTEX, EDGE}; + public static enum PropType { + ELEMENT, + VERTEX, + EDGE + }; Object id; String label; @@ -26,8 +28,9 @@ public static enum PropType {ELEMENT, VERTEX, EDGE}; BitsyState state; int version; boolean updated; - - public BitsyElement(Object id, String label, Dictionary properties, BitsyTransaction tx, BitsyState state, int version) { + + public BitsyElement( + Object id, String label, Dictionary properties, BitsyTransaction tx, BitsyState state, int version) { this.id = id; this.label = label; this.properties = properties; @@ -45,7 +48,7 @@ public Object id() { @Override public String label() { - // There is no Tx validation for label because it is used even after deletion to update indexes, etc. + // There is no Tx validation for label because it is used even after deletion to update indexes, etc. return label; } @@ -53,13 +56,13 @@ public String label() { public Graph graph() { return tx.graph(); } - + public Dictionary getPropertyDict() { return properties; } @Override - public T value(String key) { + public T value(String key) { tx.validateForQuery(this); if (properties == null) { @@ -72,7 +75,7 @@ public T value(String key) { @Override public Set keys() { tx.validateForQuery(this); - + if (properties == null) { return Collections.emptySet(); } else { @@ -80,44 +83,45 @@ public Set keys() { } } - public T removeProperty(String key) { + public T removeProperty(String key) { markForUpdate(); if (properties == null) { - return null; + return null; } else { - Object ans = properties.getProperty(key); + Object ans = properties.getProperty(key); - properties = properties.removeProperty(key); + properties = properties.removeProperty(key); - return (T)ans; + return (T) ans; } } @Override public Property property(String key, T value) { if (value == null) { - throw new IllegalArgumentException("A null property can not be stored. You can call removeProperty() instead"); + throw new IllegalArgumentException( + "A null property can not be stored. You can call removeProperty() instead"); } markForUpdate(); if (key == null) { - throw new IllegalArgumentException("Expecting non-null key in setProperty"); + throw new IllegalArgumentException("Expecting non-null key in setProperty"); } else if (key.length() == 0) { - throw new IllegalArgumentException("Expecting non-empty key in setProperty"); + throw new IllegalArgumentException("Expecting non-empty key in setProperty"); } else if (key.equals("id")) { - throw new IllegalArgumentException("Can not set the 'id' property on an element"); + throw new IllegalArgumentException("Can not set the 'id' property on an element"); } else if (key.equals("label")) { - throw new IllegalArgumentException("Can not set the 'label' property on an element"); + throw new IllegalArgumentException("Can not set the 'label' property on an element"); } else if (key.charAt(0) == '~') { - throw new IllegalArgumentException("Can not set a property beginning with ~ on an element"); + throw new IllegalArgumentException("Can not set a property beginning with ~ on an element"); } if (this.properties == null) { - this.properties = new Dictionary1(key, value); + this.properties = new Dictionary1(key, value); } else { - this.properties = properties.setProperty(key, value); + this.properties = properties.setProperty(key, value); } assert (properties != null); @@ -141,13 +145,13 @@ public Property property(String key) { public Iterator> properties(String... propertyKeys) { ArrayList> ans = new ArrayList>(); if (propertyKeys.length == 0) { - if (this.properties == null) return Collections.emptyIterator(); - propertyKeys = this.properties.getPropertyKeys(); + if (this.properties == null) return Collections.emptyIterator(); + propertyKeys = this.properties.getPropertyKeys(); } for (String key : propertyKeys) { - Property prop = property(key); - if (prop.isPresent()) ans.add(prop); + Property prop = property(key); + if (prop.isPresent()) ans.add(prop); } return ans.iterator(); @@ -157,7 +161,7 @@ public Iterator> properties(String... propertyKeys) { public void markForUpdate() { if (!updated) { updated = true; - + // Make a copy of the underlying property map, if non-null if (properties != null) { properties = properties.copyOf(); @@ -173,7 +177,7 @@ public void markForUpdate() { public BitsyState getState() { return state; } - + public void setState(BitsyState state) { this.state = state; } @@ -194,6 +198,6 @@ public int hashCode() { @Override public boolean equals(Object object) { - return ElementHelper.areEqual(this, object); + return ElementHelper.areEqual(this, object); } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdazen/bitsy/BitsyErrorCodes.java b/src/main/java/com/lambdazen/bitsy/BitsyErrorCodes.java index 5bad630..db23b2e 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyErrorCodes.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyErrorCodes.java @@ -6,19 +6,19 @@ public String toString() { return "INTERNAL_ERROR: An internal error occurred"; } }, - + ACCESS_OUTSIDE_TX_SCOPE { public String toString() { return "ACCESS_OUTSIDE_TX_SCOPE: A vertex/edge was accessed outside the scope of the transaction that created it"; } }, - + ELEMENT_ALREADY_DELETED { public String toString() { return "ELEMENT_ALREADY_DELETED: The vertex/edge being accessed has already been deleted"; } }, - + ADDING_EDGE_TO_A_DELETED_VERTEX { public String toString() { return "ADDING_EDGE_TO_A_DELETED_VERTEX: A edge was added in a transaction to (Direction.IN) a vertex that was deleted in the same transaction"; @@ -30,181 +30,181 @@ public String toString() { return "ADDING_EDGE_FROM_A_DELETED_VERTEX: A edge was added in a transaction from (Direction.OUT) a vertex that was deleted in the same transaction"; } }, - + EXCEPTION_IN_FLUSH { public String toString() { return "EXCEPTION_IN_FLUSH: The given exception occurred in the different thread while flushing a double buffer"; } }, - + BAD_DB_PATH { public String toString() { return "BAD_DB_PATH: The given path to the database is not a directory"; } }, - + ERROR_INITIALIZING_DB_FILES { public String toString() { return "ERROR_INITIALIZING_DB_FILES: The given database file could not be opened or initialized"; } }, - + ERROR_READING_FROM_FILE { public String toString() { return "ERROR_READING_FROM_FILE: A fatal error occurred while reading from a file. The database may need to be restarted after investigating the root cause"; - } - }, - + } + }, + ERROR_WRITING_TO_FILE { public String toString() { return "ERROR_WRITING_TO_TX_FILE: A fatal error occurred while writing to a transaction file. The database may need to be restarted after investigating the root cause"; } }, - + TRANSACTION_INTERRUPTED { public String toString() { return "TRANSACTION_INTERRUPTED: The given InterruptedException occurred during a transaction"; } }, - + SERIALIZATION_ERROR { public String toString() { return "SERIALIZATION_ERROR: The given exception occurred while serializing a commit block using Jackson JSON API"; } }, - + ADDING_EDGE_WITH_VERTEX_FROM_ANOTHER_TX { public String toString() { return "ADDING_EDGE_WITH_VERTICES_FROM_ANOTHER_TX: An edge was added in a transaction with an endpoint vertex belonging to another transaction"; } }, - - REMOVING_VERTEX_FROM_ANOTHER_TX { + + REMOVING_VERTEX_FROM_ANOTHER_TX { public String toString() { return "REMOVING_VERTEX_FROM_ANOTHER_TX: A vertex was removed in a transaction different from the one in which it was loaded"; } }, - + REMOVING_EDGE_FROM_ANOTHER_TX { public String toString() { return "REMOVING_EDGE_FROM_ANOTHER_TX: An edge was removed in a transaction different from the one in which it was loaded"; } }, - + CHECKSUM_MISMATCH { public String toString() { return "CHECKSUM_MISMATCH: Encountered a checksum mismatch while loading a database file"; } }, - + CONCURRENT_MODIFICATION { public String toString() { return "CONCURRENT_MODIFICATION: A vertex or edge loaded in a transaction was concurrently modified by another transaction. Please retry this transaction"; } }, - + ERROR_IN_FILE_HEADER { public String toString() { return "ERROR_IN_FILE_HEADER: A fatal error occured while parsing the first line (header) in a database file"; } }, - + INCOMPLETE_TX_FLUSH { public String toString() { return "INCOMPLETE_TX_FLUSH: A V/E file was not fully flushed when the database was previously shutdown"; } }, - - DATABASE_IS_CORRUPT { + + DATABASE_IS_CORRUPT { public String toString() { return "DATABASE_IS_CORRUPT: The given error is fatal and the database can not be loaded"; } - }, - + }, + JAVA_DESERIALIZATION_ERROR { public String toString() { return "DESERIALIZATION_ERROR: An error occurred while de-serializing a Java Serializable object"; } }, - + INDEX_ALREADY_EXISTS { public String toString() { return "INDEX_ALREADY_EXISTS: The given index already exists in the database"; } }, - + UNSUPPORTED_INDEX_TYPE { public String toString() { return "UNSUPPORTED_INDEX_TYPE: Indexes are only supported on Vertex and Edge classes"; } }, - + MISSING_INDEX { public String toString() { return "MISSING_INDEX: A vertex/edge query on a matching key-value pair was performed without creating an index for that key"; } }, - + OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS { public String toString() { return "OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS: The requested operation can not be performed on memory-only graphs"; } }, - - FULL_GRAPH_SCANS_ARE_DISABLED { + + FULL_GRAPH_SCANS_ARE_DISABLED { public String toString() { return "FULL_GRAPH_SCANS_ARE_DISABLED: The requested operation can not be performed because the BitsyGraph was constructed with the allowFullGraphScans option disabled"; } }, - - BAD_BACKUP_PATH { + + BAD_BACKUP_PATH { public String toString() { return "BAD_BACKUP_PATH: The given path to backup the database is not an empty directory"; } }, - + BACKUP_IN_PROGRESS { public String toString() { return "BACKUP_IN_PROGRESS: A scheduled backup task is already in progress. Please try after a some time"; } }, - + BACKUP_INTERRUPTED { public String toString() { return "BACKUP_INTERRUPTED: The given InterruptedException occurred while waiting for a backup to be performed"; } }, - + BACKUP_FAILED { public String toString() { return "BACKUP_FAILED: The given exception occurred during a backup operation"; } }, - - FLUSH_INTERRUPTED { + + FLUSH_INTERRUPTED { public String toString() { return "FLUSH_INTERRUPTED: The given InterruptedException occurrend while waiting for a flush operation on a transaction log to complete"; } }, - + INSTANCE_ALREADY_EXISTS { public String toString() { return "INSTANCE_ALREADY_EXISTS: A BitsyGraph object with the same path has been registered with the MBeanServer. Creating multiple instances of BitsyGraph (without calling shutdown) will cause data corruption"; } }, - + ERROR_REGISTERING_TO_MBEAN_SERVER { public String toString() { return "ERROR_REGISTERING_TO_MBEAN_SERVER: A BitsyGraph object could not be registered with the MBeanServer"; } }, - + MAJOR_VERSION_MISMATCH { public String toString() { return "MAJOR_VERSION_MISMATCH: The database loaded was created with by different major version of Bitsy. Please run 'java com.lambdazen.bitsy.PortDatabase' to upgrade or downgrade the database"; } }, - + NO_OLAP_SUPPORT { public String toString() { return "NO_OLAP_SUPPORT: Bitsy is not designed to be an OLAP graph"; @@ -222,7 +222,7 @@ public String toString() { }, NO_CUSTOM_ID_SUPPORT { - public String toString() { + public String toString() { return "NO_CUSTOM_ID_SUPPORT: Bitsy does not support user-supplied IDs for vertices and edges, only auto-generated UUIDs. Please move this to an indexed key"; } } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyException.java b/src/main/java/com/lambdazen/bitsy/BitsyException.java index c3be559..6d08d47 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyException.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyException.java @@ -1,6 +1,6 @@ package com.lambdazen.bitsy; -public class BitsyException extends RuntimeException { +public class BitsyException extends RuntimeException { private static final long serialVersionUID = -5310572247323732287L; BitsyErrorCodes code; @@ -9,19 +9,19 @@ public BitsyException(BitsyErrorCodes code) { this.code = code; } - + public BitsyException(BitsyErrorCodes code, String s) { super(code.toString() + ". " + s); this.code = code; } - + public BitsyException(BitsyErrorCodes code, String s, Throwable t) { super(code.toString() + ". " + s, t); - + this.code = code; } - + public BitsyErrorCodes getErrorCode() { return code; } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyFeatures.java b/src/main/java/com/lambdazen/bitsy/BitsyFeatures.java index 55fe3e3..102e110 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyFeatures.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyFeatures.java @@ -13,7 +13,7 @@ public class BitsyFeatures implements Features { private boolean isPersistent; public BitsyFeatures(boolean isPersistent) { - this.isPersistent = isPersistent; + this.isPersistent = isPersistent; } @Override @@ -33,7 +33,7 @@ public VertexFeatures vertex() { @Override public String toString() { - return StringFactory.featureString(this); + return StringFactory.featureString(this); } public class BitsyGraphFeatures implements Features.GraphFeatures { @@ -55,15 +55,15 @@ public boolean supportsPersistence() { } // Yes for transactions - - // TODO: Change from no for threaded transactions to yes -- semantics seems to have changed per shouldNotReuseThreadedTransaction + + // TODO: Change from no for threaded transactions to yes -- semantics seems to have changed per + // shouldNotReuseThreadedTransaction @Override public boolean supportsThreadedTransactions() { - return false; + return false; } } - public class BitsyVariableFeatures implements Features.VariableFeatures { @Override public boolean supportsVariables() { @@ -72,82 +72,95 @@ public boolean supportsVariables() { @Override public boolean supportsBooleanValues() { - return false; + return false; } @Override public boolean supportsDoubleValues() { - return false; + return false; } @Override public boolean supportsFloatValues() { - return false; + return false; } @Override public boolean supportsIntegerValues() { - return false; + return false; } @Override public boolean supportsLongValues() { - return false; + return false; } + @Override public boolean supportsMapValues() { - return false; + return false; } + @Override public boolean supportsMixedListValues() { - return false; + return false; } + @Override public boolean supportsByteValues() { - return false; + return false; } + @Override public boolean supportsBooleanArrayValues() { - return false; + return false; } + @Override public boolean supportsByteArrayValues() { - return false; + return false; } + @Override public boolean supportsDoubleArrayValues() { - return false; + return false; } + @Override public boolean supportsFloatArrayValues() { - return false; + return false; } + @Override public boolean supportsIntegerArrayValues() { - return false; + return false; } + @Override public boolean supportsLongArrayValues() { - return false; + return false; } + @Override public boolean supportsSerializableValues() { - return false; + return false; } + @Override public boolean supportsStringValues() { - return false; + return false; } + @Override public boolean supportsUniformListValues() { - return false; + return false; } + @Override public boolean supportsStringArrayValues() { - return false; + return false; } } - + public class BitsyVertexFeatures implements Features.VertexFeatures { private final Features.VertexPropertyFeatures vertexPropertyFeatures = new BitsyGraphPropertyFeatures(); @@ -173,12 +186,12 @@ public boolean supportsUserSuppliedIds() { @Override public boolean supportsNumericIds() { - return false; + return false; } @Override public boolean supportsAnyIds() { - return false; + return false; } // Yes for add and remove vertices @@ -199,12 +212,12 @@ public boolean supportsUserSuppliedIds() { @Override public boolean supportsNumericIds() { - return false; + return false; } @Override public boolean supportsAnyIds() { - return false; + return false; } // Yes for add and remove edges @@ -243,4 +256,4 @@ public boolean supportsUuidIds() { // Yes for all property types } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdazen/bitsy/BitsyGraph.java b/src/main/java/com/lambdazen/bitsy/BitsyGraph.java index 21b5c0a..d67866b 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyGraph.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyGraph.java @@ -1,5 +1,11 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.gremlin.BitsyTraversalStrategy; +import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; +import com.lambdazen.bitsy.store.MemoryGraphStore; +import com.lambdazen.bitsy.tx.BitsyTransaction; +import com.lambdazen.bitsy.tx.BitsyTransactionContext; +import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; import java.lang.management.ManagementFactory; import java.nio.file.Path; import java.nio.file.Paths; @@ -8,11 +14,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; - import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; - import org.apache.commons.configuration2.BaseConfiguration; import org.apache.commons.configuration2.Configuration; import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; @@ -27,13 +31,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.lambdazen.bitsy.gremlin.BitsyTraversalStrategy; -import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; -import com.lambdazen.bitsy.store.MemoryGraphStore; -import com.lambdazen.bitsy.tx.BitsyTransaction; -import com.lambdazen.bitsy.tx.BitsyTransactionContext; -import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; - @Graph.OptIn("com.lambdazen.bitsy.structure.BitsyGraphStructureTestSuite") @Graph.OptIn("com.lambdazen.bitsy.structure.BitsyProcessStandardTestSuite") /** Bitsy 3.0 compatible with Tinkerpop 3.0 */ @@ -69,8 +66,16 @@ public class BitsyGraph implements Graph, BitsyGraphMBean { static { try { - TraversalStrategies.GlobalCache.registerStrategies(BitsyGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(BitsyTraversalStrategy.instance())); - TraversalStrategies.GlobalCache.registerStrategies(BitsyAutoReloadingGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(BitsyTraversalStrategy.instance())); + TraversalStrategies.GlobalCache.registerStrategies( + BitsyGraph.class, + TraversalStrategies.GlobalCache.getStrategies(Graph.class) + .clone() + .addStrategies(BitsyTraversalStrategy.instance())); + TraversalStrategies.GlobalCache.registerStrategies( + BitsyAutoReloadingGraph.class, + TraversalStrategies.GlobalCache.getStrategies(Graph.class) + .clone() + .addStrategies(BitsyTraversalStrategy.instance())); } catch (java.lang.BootstrapMethodError e) { // Known issue with Android System.err.println("Not registering traversal strategies"); @@ -115,7 +120,12 @@ public BitsyGraph(Path dbPath, boolean allowFullGraphScans, long txLogThreshold, * @param reorgFactor V/E reorgs are triggered when the size of the V/E files exceeds the initial size by (1 + factor) * @param createDirIfMissing create the Bitsy directory if it is missing */ - public BitsyGraph(Path dbPath, boolean allowFullGraphScans, long txLogThreshold, double reorgFactor, boolean createDirIfMissing) { + public BitsyGraph( + Path dbPath, + boolean allowFullGraphScans, + long txLogThreshold, + double reorgFactor, + boolean createDirIfMissing) { this.dbPath = dbPath; this.allowFullGraphScans = allowFullGraphScans; this.curTransactionContext = new ThreadLocal(); @@ -124,41 +134,53 @@ public BitsyGraph(Path dbPath, boolean allowFullGraphScans, long txLogThreshold, this.createDirIfMissing = createDirIfMissing; if (IS_ANDROID) { - if (isPersistent()) { - // Load from files - this.graphStore = new FileBackedMemoryGraphStore(new MemoryGraphStore(allowFullGraphScans), dbPath, txLogThreshold, reorgFactor, createDirIfMissing); - } else { - this.graphStore = new MemoryGraphStore(allowFullGraphScans); - } + if (isPersistent()) { + // Load from files + this.graphStore = new FileBackedMemoryGraphStore( + new MemoryGraphStore(allowFullGraphScans), + dbPath, + txLogThreshold, + reorgFactor, + createDirIfMissing); + } else { + this.graphStore = new MemoryGraphStore(allowFullGraphScans); + } } else { - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - if (isPersistent()) { - // Make sure that another BitsyGraph doesn't exist with the same path - try { - this.objectName = new ObjectName("com.lambdazen.bitsy", "path", ObjectName.quote(dbPath.toString())); - } catch (MalformedObjectNameException e) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Bug in quoting ObjectName", e); - } - - // Check registry - if (server.isRegistered(objectName)) { - throw new BitsyException(BitsyErrorCodes.INSTANCE_ALREADY_EXISTS, "Path " + dbPath.toString()); - } - - // Load from files - this.graphStore = new FileBackedMemoryGraphStore(new MemoryGraphStore(allowFullGraphScans), dbPath, txLogThreshold, reorgFactor, createDirIfMissing); - } else { - this.graphStore = new MemoryGraphStore(allowFullGraphScans); + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + if (isPersistent()) { + // Make sure that another BitsyGraph doesn't exist with the same path + try { + this.objectName = + new ObjectName("com.lambdazen.bitsy", "path", ObjectName.quote(dbPath.toString())); + } catch (MalformedObjectNameException e) { + throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Bug in quoting ObjectName", e); } - // Register this to the MBeanServer - if (objectName != null) { - try { - server.registerMBean(this, objectName); - } catch (Exception e) { - throw new BitsyException(BitsyErrorCodes.ERROR_REGISTERING_TO_MBEAN_SERVER, "Encountered exception", e); - } + // Check registry + if (server.isRegistered(objectName)) { + throw new BitsyException(BitsyErrorCodes.INSTANCE_ALREADY_EXISTS, "Path " + dbPath.toString()); + } + + // Load from files + this.graphStore = new FileBackedMemoryGraphStore( + new MemoryGraphStore(allowFullGraphScans), + dbPath, + txLogThreshold, + reorgFactor, + createDirIfMissing); + } else { + this.graphStore = new MemoryGraphStore(allowFullGraphScans); + } + + // Register this to the MBeanServer + if (objectName != null) { + try { + server.registerMBean(this, objectName); + } catch (Exception e) { + throw new BitsyException( + BitsyErrorCodes.ERROR_REGISTERING_TO_MBEAN_SERVER, "Encountered exception", e); } + } } this.bitsyFeatures = new BitsyFeatures(isPersistent); @@ -168,39 +190,40 @@ public BitsyGraph(Path dbPath, boolean allowFullGraphScans, long txLogThreshold, * Constructor with a Configuration object with String dbPath, boolean allowFullGraphScans, long txLogThreshold and double reorgFactor */ public BitsyGraph(Configuration configuration) { - this(Paths.get(configuration.getString(DB_PATH_KEY)), + this( + Paths.get(configuration.getString(DB_PATH_KEY)), configuration.getBoolean(ALLOW_FULL_GRAPH_SCANS_KEY, Boolean.TRUE), configuration.getLong(TX_LOG_THRESHOLD_KEY, DEFAULT_TX_LOG_THRESHOLD), configuration.getDouble(REORG_FACTOR_KEY, DEFAULT_REORG_FACTOR), configuration.getBoolean(CREATE_DIR_IF_MISSING_KEY, false)); String isoLevelStr = configuration.getString(DEFAULT_ISOLATION_LEVEL_KEY); if (isoLevelStr != null) { - setDefaultIsolationLevel(BitsyIsolationLevel.valueOf(isoLevelStr)); + setDefaultIsolationLevel(BitsyIsolationLevel.valueOf(isoLevelStr)); } String vertexIndices = configuration.getString(VERTEX_INDICES_KEY); if (vertexIndices != null) { - createIndices(Vertex.class, vertexIndices); + createIndices(Vertex.class, vertexIndices); } String edgeIndices = configuration.getString(EDGE_INDICES_KEY); if (edgeIndices != null) { - createIndices(Edge.class, edgeIndices); + createIndices(Edge.class, edgeIndices); } this.origConfig = configuration; } - private void createIndices(Class elemType, String vertexIndices) { - for (String indexKey : vertexIndices.split(",")) { - try { - createKeyIndex(indexKey.trim(), elemType); - } catch (BitsyException ex) { - if (ex.getErrorCode() == BitsyErrorCodes.INDEX_ALREADY_EXISTS) { - // That's fine - } else { - throw ex; - } - } + private void createIndices(Class elemType, String vertexIndices) { + for (String indexKey : vertexIndices.split(",")) { + try { + createKeyIndex(indexKey.trim(), elemType); + } catch (BitsyException ex) { + if (ex.getErrorCode() == BitsyErrorCodes.INDEX_ALREADY_EXISTS) { + // That's fine + } else { + throw ex; } + } } + } public static final BitsyGraph open(Configuration configuration) { return new BitsyGraph(configuration); @@ -247,58 +270,78 @@ public void setTxIsolationLevel(BitsyIsolationLevel level) { public double getReorgFactor() { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); } else { - return ((FileBackedMemoryGraphStore)graphStore).getVEReorgPotential().getFactor(); + return ((FileBackedMemoryGraphStore) graphStore) + .getVEReorgPotential() + .getFactor(); } } public void setReorgFactor(double factor) { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); } else { - ((FileBackedMemoryGraphStore)graphStore).getVEReorgPotential().setFactor(factor); + ((FileBackedMemoryGraphStore) graphStore).getVEReorgPotential().setFactor(factor); } } public int getMinLinesPerReorg() { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); } else { - return ((FileBackedMemoryGraphStore)graphStore).getVEReorgPotential().getMinLinesPerReorg(); + return ((FileBackedMemoryGraphStore) graphStore) + .getVEReorgPotential() + .getMinLinesPerReorg(); } } public void setMinLinesPerReorg(int minLinesPerReorg) { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Reorg factor is only defined for persistent graphs (with a defined path to DB)"); } else { - ((FileBackedMemoryGraphStore)graphStore).getVEReorgPotential().setMinLinesPerReorg(minLinesPerReorg); + ((FileBackedMemoryGraphStore) graphStore).getVEReorgPotential().setMinLinesPerReorg(minLinesPerReorg); } } public long getTxLogThreshold() { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); } else { - return ((FileBackedMemoryGraphStore)graphStore).getTxLogFlushPotential().getTxLogThreshold(); + return ((FileBackedMemoryGraphStore) graphStore) + .getTxLogFlushPotential() + .getTxLogThreshold(); } } public void setTxLogThreshold(long txLogThreshold) { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); } else { - ((FileBackedMemoryGraphStore)graphStore).getTxLogFlushPotential().setTxLogThreshold(txLogThreshold); + ((FileBackedMemoryGraphStore) graphStore).getTxLogFlushPotential().setTxLogThreshold(txLogThreshold); } } /** This method flushes the transaction log to the V/E text files */ public void flushTxLog() { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); } else { - ((FileBackedMemoryGraphStore)graphStore).flushTxLog(); + ((FileBackedMemoryGraphStore) graphStore).flushTxLog(); } } @@ -316,9 +359,11 @@ public void backup(String pathToDir) { */ public void backup(Path pathToDir) { if (!isPersistent()) { - throw new BitsyException(BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); + throw new BitsyException( + BitsyErrorCodes.OPERATION_UNDEFINED_FOR_NON_PERSISTENT_GRAPHS, + "Transaction log threshold is only defined for persistent graphs (with a defined path to DB)"); } else { - ((FileBackedMemoryGraphStore)graphStore).backup(pathToDir); + ((FileBackedMemoryGraphStore) graphStore).backup(pathToDir); } } @@ -349,17 +394,21 @@ public ITransaction tx() { /* UNIMPLEMENTED OLAP METHODS */ @Override public GraphComputer compute() { - throw new UnsupportedOperationException("Bitsy doesn't support the compute() method", new BitsyException(BitsyErrorCodes.NO_OLAP_SUPPORT)); + throw new UnsupportedOperationException( + "Bitsy doesn't support the compute() method", new BitsyException(BitsyErrorCodes.NO_OLAP_SUPPORT)); } @Override public GraphComputer compute(Class graphComputerClass) { - throw new UnsupportedOperationException("Bitsy doesn't support the compute() method", new BitsyException(BitsyErrorCodes.NO_OLAP_SUPPORT)); + throw new UnsupportedOperationException( + "Bitsy doesn't support the compute() method", new BitsyException(BitsyErrorCodes.NO_OLAP_SUPPORT)); } @Override public I io(final Io.Builder builder) { - return (I) builder.graph(this).onMapper(m -> m.addRegistry(BitsyIoRegistryV3d0.instance())).create(); + return (I) builder.graph(this) + .onMapper(m -> m.addRegistry(BitsyIoRegistryV3d0.instance())) + .create(); } /* FEATURES */ @@ -372,7 +421,7 @@ public Graph.Features features() { @Override public Configuration configuration() { if (this.origConfig != null) { - return this.origConfig; + return this.origConfig; } else { Configuration ans = new BaseConfiguration(); ans.setProperty(DB_PATH_KEY, dbPath.toString()); @@ -391,36 +440,40 @@ public Configuration configuration() { private void validateHomogenousIds(final Object[] ids) { final Class firstClass = ids[0].getClass(); - for (int i=1; i < ids.length; i++) { - Class curClass = ids[i].getClass(); - if (!curClass.equals(firstClass)) { - throw new IllegalArgumentException("Argument " + i + " has class " + curClass + " which mismatches arg 0's class " + firstClass); - } + for (int i = 1; i < ids.length; i++) { + Class curClass = ids[i].getClass(); + if (!curClass.equals(firstClass)) { + throw new IllegalArgumentException( + "Argument " + i + " has class " + curClass + " which mismatches arg 0's class " + firstClass); + } } } @Override public Vertex addVertex(Object... keyValues) { if (keyValues == null) { - throw new IllegalArgumentException("Expecting non-null arguments in addVertex"); + throw new IllegalArgumentException("Expecting non-null arguments in addVertex"); } else if (keyValues.length % 2 == 1) { - throw new IllegalArgumentException("Expecting even number of items in the keyValue array. Found " + keyValues.length); + throw new IllegalArgumentException( + "Expecting even number of items in the keyValue array. Found " + keyValues.length); } // Validate first - for (int i = 0; i < keyValues.length; i = i+2) { - if (keyValues[i] == T.id) { + for (int i = 0; i < keyValues.length; i = i + 2) { + if (keyValues[i] == T.id) { // We don't support custom IDs - throw new UnsupportedOperationException("Encountered T.id in addVertex", new BitsyException(BitsyErrorCodes.NO_CUSTOM_ID_SUPPORT)); - } else if (keyValues[i] == null) { - throw new IllegalArgumentException("Encountered a null key in argument #" + i); - } else if (keyValues[i+1] == null) { - throw new IllegalArgumentException("Encountered a null value in argument #" + i); - } else if (keyValues[i] == T.label) { - // That's fine - } else if (!(keyValues[i] instanceof String)) { - throw new IllegalArgumentException("Encountered a non-string key: " + keyValues[i] + " in argument #" + i); - } + throw new UnsupportedOperationException( + "Encountered T.id in addVertex", new BitsyException(BitsyErrorCodes.NO_CUSTOM_ID_SUPPORT)); + } else if (keyValues[i] == null) { + throw new IllegalArgumentException("Encountered a null key in argument #" + i); + } else if (keyValues[i + 1] == null) { + throw new IllegalArgumentException("Encountered a null value in argument #" + i); + } else if (keyValues[i] == T.label) { + // That's fine + } else if (!(keyValues[i] instanceof String)) { + throw new IllegalArgumentException( + "Encountered a non-string key: " + keyValues[i] + " in argument #" + i); + } } // Do the work @@ -428,13 +481,13 @@ public Vertex addVertex(Object... keyValues) { BitsyTransaction tx = getTx(); BitsyVertex vertex = new BitsyVertex(UUID.randomUUID(), label, null, tx, BitsyState.M, 0); - for (int i = 0; i < keyValues.length; i = i+2) { - if (keyValues[i] == T.label) { - // Already found it - } else { - String key = (String)keyValues[i]; - vertex.property(key, keyValues[i+1]); - } + for (int i = 0; i < keyValues.length; i = i + 2) { + if (keyValues[i] == T.label) { + // Already found it + } else { + String key = (String) keyValues[i]; + vertex.property(key, keyValues[i + 1]); + } } tx.addVertex(vertex); @@ -452,7 +505,7 @@ public Iterator vertices(Object... vertexIds) { final ITransaction tx = getTx(); return tx.getAllVertices(); - } else if (vertexIds.length == 1 ) { + } else if (vertexIds.length == 1) { Vertex vertex = getVertex(vertexIds[0]); if (vertex == null) { return Collections.emptyList().iterator(); @@ -460,7 +513,7 @@ public Iterator vertices(Object... vertexIds) { return Collections.singletonList(vertex).iterator(); } } else { - validateHomogenousIds(vertexIds); + validateHomogenousIds(vertexIds); List ans = new ArrayList(); for (Object vertexId : vertexIds) { Vertex vertex = getVertex(vertexId); @@ -479,12 +532,12 @@ private Vertex getVertex(Object id) { Vertex ans; if (id instanceof UUID) { - ans = getTx().getVertex((UUID)id); + ans = getTx().getVertex((UUID) id); } else if (id instanceof String) { // Get the UUID from the string representation -- may fail UUID uuid; try { - uuid = UUID.fromString((String)id); + uuid = UUID.fromString((String) id); } catch (IllegalArgumentException e) { // Decoding failed return null; @@ -492,7 +545,7 @@ private Vertex getVertex(Object id) { ans = getTx().getVertex(uuid); } else if (id instanceof Vertex) { - return getTx().getVertex((UUID)((Vertex)id).id()); + return getTx().getVertex((UUID) ((Vertex) id).id()); } else { // Wrong type ans = null; @@ -507,12 +560,12 @@ private Edge getEdge(Object id) { } if (id instanceof UUID) { - return getTx().getEdge((UUID)id); + return getTx().getEdge((UUID) id); } else if (id instanceof String) { // Get the UUID from the string representation -- may fail UUID uuid; try { - uuid = UUID.fromString((String)id); + uuid = UUID.fromString((String) id); } catch (IllegalArgumentException e) { // Decoding failed return null; @@ -520,7 +573,7 @@ private Edge getEdge(Object id) { return getTx().getEdge(uuid); } else if (id instanceof Edge) { - return getTx().getEdge((UUID)((Edge)id).id()); + return getTx().getEdge((UUID) ((Edge) id).id()); } else { // Wrong type return null; @@ -536,7 +589,7 @@ public Iterator edges(Object... edgeIds) { final ITransaction tx = getTx(); return tx.getAllEdges(); - } else if (edgeIds.length == 1 ) { + } else if (edgeIds.length == 1) { Edge edge = getEdge(edgeIds[0]); if (edge == null) { return Collections.emptyList().iterator(); @@ -544,7 +597,7 @@ public Iterator edges(Object... edgeIds) { return Collections.singletonList(edge).iterator(); } } else { - validateHomogenousIds(edgeIds); + validateHomogenousIds(edgeIds); List ans = new ArrayList(); for (Object edgeId : edgeIds) { Edge edge = getEdge(edgeId); @@ -560,11 +613,11 @@ public Iterator edges(Object... edgeIds) { public void shutdown() { try { // As per Blueprints tests, shutdown() implies automatic commit - BitsyTransaction tx = curTransaction.get(); - if ((tx != null) && tx.isOpen()) { - tx.commit(); - tx = null; - } + BitsyTransaction tx = curTransaction.get(); + if ((tx != null) && tx.isOpen()) { + tx.commit(); + tx = null; + } // Shutdown the underlying store graphStore.shutdown(); @@ -621,13 +674,13 @@ public IGraphStore getStore() { return graphStore; } - @Override - public void close() throws Exception { - this.shutdown(); - } + @Override + public void close() throws Exception { + this.shutdown(); + } - @Override - public Variables variables() { - throw new UnsupportedOperationException("Bitsy doesn't support variables. Please store the data in a vertex"); - } + @Override + public Variables variables() { + throw new UnsupportedOperationException("Bitsy doesn't support variables. Please store the data in a vertex"); + } } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyGraphMBean.java b/src/main/java/com/lambdazen/bitsy/BitsyGraphMBean.java index ef8d0c1..8131273 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyGraphMBean.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyGraphMBean.java @@ -14,40 +14,40 @@ public interface BitsyGraphMBean { * more disk space and startup time in the worst case. Default value is 1. */ public void setReorgFactor(double factor); - + /** * Returns the minimum number of vertices and edges that must be added * before a reorganization is considered. This rule is used in combination * with the reorgFactor. Default value is 1000. */ public int getMinLinesPerReorg(); - + /** * Modify the minimum lines to be added before a reorganization is - * considered. Default value is 1000. + * considered. Default value is 1000. */ public void setMinLinesPerReorg(int minLinesPerReorg); - + /** * Returns the transaction log threshold which is the minimum size of the * transaction log (T?.txt) in bytes, before which the contents of the log * are copied to V?.txt and E?.txt. Default value is 4MB. */ public long getTxLogThreshold(); - + /** * Modify the transaction log threshold. A higher number indicates fewer * file operations, but more disk space and startup time in the worst case. * Default value is 4MB. */ public void setTxLogThreshold(long txLogThreshold); - + /** This method flushes the transaction log to the V/E text files */ public void flushTxLog(); - - /** This method backs up the database while it is still operational. Only one backup can be in progress at a time. - * - * @param pathToDir directory to which the database must be backed up. + + /** This method backs up the database while it is still operational. Only one backup can be in progress at a time. + * + * @param pathToDir directory to which the database must be backed up. */ public void backup(String pathToDir); } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyGraphSONModule.java b/src/main/java/com/lambdazen/bitsy/BitsyGraphSONModule.java index c95c077..8495ac5 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyGraphSONModule.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyGraphSONModule.java @@ -14,11 +14,12 @@ package com.lambdazen.bitsy; -import com.lambdazen.bitsy.ads.dict.Dictionary; import com.lambdazen.bitsy.store.EdgeBean; import com.lambdazen.bitsy.store.VertexBean; -import com.lambdazen.bitsy.store.VertexBeanJson; -import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens; +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import org.apache.tinkerpop.gremlin.structure.io.graphson.TinkerPopJacksonModule; import org.apache.tinkerpop.shaded.jackson.core.*; import org.apache.tinkerpop.shaded.jackson.core.type.WritableTypeId; @@ -28,12 +29,6 @@ import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer; import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - /** * @author Stephen Mallette (http://stephen.genoprime.com) */ @@ -41,20 +36,22 @@ public class BitsyGraphSONModule extends TinkerPopJacksonModule { private static final String TYPE_NAMESPACE = "bitsy"; - private static final Map TYPE_DEFINITIONS = Collections.unmodifiableMap( - new LinkedHashMap() {{ - put(UUID.class, "UUID"); - put(VertexBean.class, "VertexBean"); - put(EdgeBean.class, "EdgeBean"); - }}); + private static final Map TYPE_DEFINITIONS = + Collections.unmodifiableMap(new LinkedHashMap() { + { + put(UUID.class, "UUID"); + put(VertexBean.class, "VertexBean"); + put(EdgeBean.class, "EdgeBean"); + } + }); private BitsyGraphSONModule() { super("bitsy"); addSerializer(UUID.class, new UUIDSerializer()); addDeserializer(UUID.class, new UUIDDeserializer()); -// addSerializer(VertexBean.class, new UUIDSerializer()); -// addSerializer(EdgeBean.class, new UUIDSerializer()); + // addSerializer(VertexBean.class, new UUIDSerializer()); + // addSerializer(EdgeBean.class, new UUIDSerializer()); } private static final BitsyGraphSONModule INSTANCE = new BitsyGraphSONModule(); @@ -80,23 +77,23 @@ public UUIDSerializer() { } @Override - public void serialize(final UUID uuid, - final JsonGenerator jsonGenerator, - final SerializerProvider serializerProvider) - throws IOException, JsonGenerationException - { + public void serialize( + final UUID uuid, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) + throws IOException, JsonGenerationException { String uuidStr = UUID.toString(uuid); jsonGenerator.writeString(uuidStr); } @Override - public void serializeWithType(final UUID uuid, - final JsonGenerator jsonGenerator, - final SerializerProvider serializerProvider, - final TypeSerializer typeSerializer) + public void serializeWithType( + final UUID uuid, + final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider, + final TypeSerializer typeSerializer) throws IOException, JsonProcessingException { // since jackson 2.9, must keep track of `typeIdDef` in order to close it properly - final WritableTypeId typeIdDef = typeSerializer.writeTypePrefix(jsonGenerator, typeSerializer.typeId(uuid, JsonToken.VALUE_STRING)); + final WritableTypeId typeIdDef = + typeSerializer.writeTypePrefix(jsonGenerator, typeSerializer.typeId(uuid, JsonToken.VALUE_STRING)); String uuidStr = UUID.toString(uuid); jsonGenerator.writeString(uuidStr); typeSerializer.writeTypeSuffix(jsonGenerator, typeIdDef); @@ -109,11 +106,11 @@ public UUIDDeserializer() { } @Override - public UUID deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + public UUID deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) + throws IOException, JsonProcessingException { jsonParser.nextToken(); final String uuidStr = deserializationContext.readValue(jsonParser, String.class); return UUID.fromString(uuidStr); } } - } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyIoRegistryV3d0.java b/src/main/java/com/lambdazen/bitsy/BitsyIoRegistryV3d0.java index 7e33e77..43b3732 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyIoRegistryV3d0.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyIoRegistryV3d0.java @@ -11,45 +11,39 @@ import org.apache.tinkerpop.shaded.kryo.io.Input; import org.apache.tinkerpop.shaded.kryo.io.Output; -public class BitsyIoRegistryV3d0 - extends AbstractIoRegistry -{ - private static final BitsyIoRegistryV3d0 INSTANCE = new BitsyIoRegistryV3d0(); - - private BitsyIoRegistryV3d0() { - register(GryoIo.class, UUID.class, new UUIDGryoSerializer()); - register(GryoIo.class, VertexBean.class, new UUIDGryoSerializer()); - register(GryoIo.class, EdgeBean.class, new UUIDGryoSerializer()); - - register(GraphSONIo.class, UUID.class, BitsyGraphSONModule.getInstance()); - register(GraphSONIo.class, VertexBean.class, BitsyGraphSONModule.getInstance()); - register(GraphSONIo.class, EdgeBean.class, BitsyGraphSONModule.getInstance()); - - register(GraphBinaryIo.class, UUID.class, new UUIDGraphBinarySerializer()); - register(GraphBinaryIo.class, VertexBean.class, new UUIDGraphBinarySerializer()); - register(GraphBinaryIo.class, EdgeBean.class, new UUIDGraphBinarySerializer()); - } - - public static BitsyIoRegistryV3d0 instance() { - return INSTANCE; - } - - final static class UUIDGryoSerializer - extends Serializer - { - @Override - public void write(final Kryo kryo, final Output output, final UUID uuid) { - output.writeLong(uuid.getMostSignificantBits()); - output.writeLong(uuid.getLeastSignificantBits()); - } +public class BitsyIoRegistryV3d0 extends AbstractIoRegistry { + private static final BitsyIoRegistryV3d0 INSTANCE = new BitsyIoRegistryV3d0(); + + private BitsyIoRegistryV3d0() { + register(GryoIo.class, UUID.class, new UUIDGryoSerializer()); + register(GryoIo.class, VertexBean.class, new UUIDGryoSerializer()); + register(GryoIo.class, EdgeBean.class, new UUIDGryoSerializer()); + + register(GraphSONIo.class, UUID.class, BitsyGraphSONModule.getInstance()); + register(GraphSONIo.class, VertexBean.class, BitsyGraphSONModule.getInstance()); + register(GraphSONIo.class, EdgeBean.class, BitsyGraphSONModule.getInstance()); - @Override - public UUID read(final Kryo kryo, final Input input, final Class aClass) { - long msb = input.readLong(); - long lsb = input.readLong(); - return new UUID(msb, lsb); + register(GraphBinaryIo.class, UUID.class, new UUIDGraphBinarySerializer()); + register(GraphBinaryIo.class, VertexBean.class, new UUIDGraphBinarySerializer()); + register(GraphBinaryIo.class, EdgeBean.class, new UUIDGraphBinarySerializer()); } - } + public static BitsyIoRegistryV3d0 instance() { + return INSTANCE; + } + static final class UUIDGryoSerializer extends Serializer { + @Override + public void write(final Kryo kryo, final Output output, final UUID uuid) { + output.writeLong(uuid.getMostSignificantBits()); + output.writeLong(uuid.getLeastSignificantBits()); + } + + @Override + public UUID read(final Kryo kryo, final Input input, final Class aClass) { + long msb = input.readLong(); + long lsb = input.readLong(); + return new UUID(msb, lsb); + } + } } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyProperty.java b/src/main/java/com/lambdazen/bitsy/BitsyProperty.java index 6b11d01..fd8da8f 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyProperty.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyProperty.java @@ -25,11 +25,11 @@ public String key() { @Override public T value() throws NoSuchElementException { - if (removed) { - throw new NoSuchElementException("This property is empty"); - } else { - return value; - } + if (removed) { + throw new NoSuchElementException("This property is empty"); + } else { + return value; + } } @Override @@ -44,10 +44,10 @@ public Element element() { @Override public void remove() { - if (isPresent()) { - element.removeProperty(key); - this.removed = true; - } + if (isPresent()) { + element.removeProperty(key); + this.removed = true; + } } // Moved to ElementHelper hashCode and equals in TP3 @@ -64,4 +64,4 @@ public boolean equals(final Object object) { public String toString() { return StringFactory.propertyString(this); } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdazen/bitsy/BitsyRetryException.java b/src/main/java/com/lambdazen/bitsy/BitsyRetryException.java index b071404..5d25c19 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyRetryException.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyRetryException.java @@ -1,17 +1,17 @@ package com.lambdazen.bitsy; -public class BitsyRetryException extends BitsyException { +public class BitsyRetryException extends BitsyException { private static final long serialVersionUID = 976641612846833462L; BitsyErrorCodes code; public BitsyRetryException(BitsyErrorCodes code) { super(code); } - + public BitsyRetryException(BitsyErrorCodes code, String s) { super(code, s); } - + public BitsyRetryException(BitsyErrorCodes code, String s, Throwable t) { super(code, s, t); } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyState.java b/src/main/java/com/lambdazen/bitsy/BitsyState.java index 130f559..b674504 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyState.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyState.java @@ -3,5 +3,5 @@ public enum BitsyState { U, // unmodified M, // modified - D // deleted + D // deleted } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyVertex.java b/src/main/java/com/lambdazen/bitsy/BitsyVertex.java index bf6120d..d17a6bf 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyVertex.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyVertex.java @@ -1,9 +1,13 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.ads.dict.Dictionary; +import com.lambdazen.bitsy.store.IStringCanonicalizer; +import com.lambdazen.bitsy.store.VertexBean; +import com.lambdazen.bitsy.store.VertexBeanJson; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.T; @@ -12,19 +16,14 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; -import com.lambdazen.bitsy.ads.dict.Dictionary; -import com.lambdazen.bitsy.store.IStringCanonicalizer; -import com.lambdazen.bitsy.store.VertexBean; -import com.lambdazen.bitsy.store.VertexBeanJson; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public class BitsyVertex extends BitsyElement implements Vertex { - private static final Direction[] directions = new Direction[] {Direction.OUT, Direction.IN}; - - public BitsyVertex(UUID id, String label, Dictionary properties, BitsyTransaction tx, BitsyState state, int version) { + private static final Direction[] directions = new Direction[] {Direction.OUT, Direction.IN}; + + public BitsyVertex( + UUID id, String label, Dictionary properties, BitsyTransaction tx, BitsyState state, int version) { super(id, label, properties, tx, state, version); } - + public BitsyVertex(VertexBean bean, BitsyTransaction tx, BitsyState state) { this(bean.getId(), bean.getLabel(), bean.getPropertiesDict(), tx, state, bean.getVersion()); } @@ -32,7 +31,7 @@ public BitsyVertex(VertexBean bean, BitsyTransaction tx, BitsyState state) { @Override public String label() { String result = super.label(); - return (result == null) ? Vertex.DEFAULT_LABEL : result; + return (result == null) ? Vertex.DEFAULT_LABEL : result; } @Override @@ -42,30 +41,30 @@ public Iterator edges(Direction dir, String... edgeLabels) { public VertexBean asBean() { // The TX is usually not active at this point. So no checks. - return new VertexBean((UUID)id, label, properties, version); + return new VertexBean((UUID) id, label, properties, version); } public VertexBean asBean(IStringCanonicalizer canonicalizer) { if (properties != null) { properties.canonicalizeKeys(canonicalizer); } - + return asBean(); } public VertexBeanJson asJsonBean() { // The TX is usually not active at this point. So no checks. - //TreeMap propertyMap = (properties == null) ? null : properties.toMap(); - return new VertexBeanJson((UUID)id, label, properties, version, state); + // TreeMap propertyMap = (properties == null) ? null : properties.toMap(); + return new VertexBeanJson((UUID) id, label, properties, version, state); } @Override public Iterator vertices(final Direction dir, String... edgeLabels) { final ArrayList vertices = new ArrayList(); - + for (Direction myDir : directions) { if ((myDir == dir) || (dir == Direction.BOTH)) { - Iterator iter = edges(myDir, edgeLabels); + Iterator iter = edges(myDir, edgeLabels); while (iter.hasNext()) { Edge e = iter.next(); Vertex toAdd = (myDir.opposite() == Direction.IN) ? e.inVertex() : e.outVertex(); @@ -73,7 +72,7 @@ public Iterator vertices(final Direction dir, String... edgeLabels) { } } } - + // Go through the edges and load the vertices return vertices.iterator(); } @@ -90,46 +89,50 @@ public void remove() { @Override public Edge addEdge(String label, Vertex inVertex, Object... keyValues) { if (keyValues.length % 2 == 1) { - throw new IllegalArgumentException("Expecting even number of items in the keyValue array. Found " + keyValues.length); + throw new IllegalArgumentException( + "Expecting even number of items in the keyValue array. Found " + keyValues.length); } if (label == null) { - throw new IllegalArgumentException("You have to specify a non-null String label when adding an edge"); + throw new IllegalArgumentException("You have to specify a non-null String label when adding an edge"); } else if (label.length() == 0) { - throw new IllegalArgumentException("You have to specify a non-empty String label when adding an edge"); + throw new IllegalArgumentException("You have to specify a non-empty String label when adding an edge"); } else if (label.charAt(0) == '~') { - throw new IllegalArgumentException("Labels beginning with ~ are invalid"); + throw new IllegalArgumentException("Labels beginning with ~ are invalid"); } if (inVertex == null) { - throw new IllegalArgumentException("The inVertex supplied to addEdge() is null"); + throw new IllegalArgumentException("The inVertex supplied to addEdge() is null"); } // Validate first - for (int i = 0; i < keyValues.length; i = i+2) { - if (keyValues[i] == T.label) { - throw new UnsupportedOperationException("Encountered T.label in addVertex"); - } else if (keyValues[i] == T.id) { - throw new UnsupportedOperationException("Encountered T.id in addVertex", new BitsyException(BitsyErrorCodes.NO_CUSTOM_ID_SUPPORT)); - } else if (keyValues[i] == null) { - throw new IllegalArgumentException("Encountered a null key in argument #" + i); - } else if (keyValues[i+1] == null) { - throw new IllegalArgumentException("Encountered a null value in argument #" + i); - } else if (!(keyValues[i] instanceof String)) { - throw new IllegalArgumentException("Encountered a non-string key: " + keyValues[i] + " in argument #" + i); - } + for (int i = 0; i < keyValues.length; i = i + 2) { + if (keyValues[i] == T.label) { + throw new UnsupportedOperationException("Encountered T.label in addVertex"); + } else if (keyValues[i] == T.id) { + throw new UnsupportedOperationException( + "Encountered T.id in addVertex", new BitsyException(BitsyErrorCodes.NO_CUSTOM_ID_SUPPORT)); + } else if (keyValues[i] == null) { + throw new IllegalArgumentException("Encountered a null key in argument #" + i); + } else if (keyValues[i + 1] == null) { + throw new IllegalArgumentException("Encountered a null value in argument #" + i); + } else if (!(keyValues[i] instanceof String)) { + throw new IllegalArgumentException( + "Encountered a non-string key: " + keyValues[i] + " in argument #" + i); + } } - // Construct the edge with this as the out vertex - BitsyEdge edge = new BitsyEdge(UUID.randomUUID(), null, tx, BitsyState.M, 0, label, (UUID)id(), (UUID)inVertex.id()); + // Construct the edge with this as the out vertex + BitsyEdge edge = + new BitsyEdge(UUID.randomUUID(), null, tx, BitsyState.M, 0, label, (UUID) id(), (UUID) inVertex.id()); - for (int i = 0; i < keyValues.length; i = i+2) { - String key = (String)keyValues[i]; - edge.property(key, keyValues[i+1]); + for (int i = 0; i < keyValues.length; i = i + 2) { + String key = (String) keyValues[i]; + edge.property(key, keyValues[i + 1]); } tx.addEdge(edge); - + return edge; } @@ -150,36 +153,40 @@ public VertexProperty property(String key) { @Override public VertexProperty property(String key, V value) { - super.property(key, value); - return new BitsyVertexProperty(this, key, value); + super.property(key, value); + return new BitsyVertexProperty(this, key, value); } @Override - public VertexProperty property(final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues) { - if (cardinality != Cardinality.single) { - // For some reason, TP3 tests fail with this exception - //throw new BitsyException(BitsyErrorCodes.NO_MULTI_PROPERTY_SUPPORT, "Encountered cardinality: " + cardinality.toString()); - } else if (keyValues.length != 0) { - throw new UnsupportedOperationException("Encountered key values: " + keyValues.toString(), new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT)); - } + public VertexProperty property( + final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues) { + if (cardinality != Cardinality.single) { + // For some reason, TP3 tests fail with this exception + // throw new BitsyException(BitsyErrorCodes.NO_MULTI_PROPERTY_SUPPORT, "Encountered cardinality: " + + // cardinality.toString()); + } else if (keyValues.length != 0) { + throw new UnsupportedOperationException( + "Encountered key values: " + keyValues.toString(), + new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT)); + } - return property(key, value); + return property(key, value); } // THERE ARE TWO MORE COPIES OF THIS CODE IN ELEMENT AND EDGE @Override - public Iterator> properties(String... propertyKeys) { + public Iterator> properties(String... propertyKeys) { ArrayList> ans = new ArrayList>(); if (propertyKeys.length == 0) { - if (this.properties == null) return Collections.emptyIterator(); - propertyKeys = this.properties.getPropertyKeys(); + if (this.properties == null) return Collections.emptyIterator(); + propertyKeys = this.properties.getPropertyKeys(); } for (String key : propertyKeys) { - VertexProperty prop = property(key); + VertexProperty prop = property(key); if (prop.isPresent()) ans.add(prop); } return ans.iterator(); - } + } } diff --git a/src/main/java/com/lambdazen/bitsy/BitsyVertexProperty.java b/src/main/java/com/lambdazen/bitsy/BitsyVertexProperty.java index 7010461..03f29d8 100644 --- a/src/main/java/com/lambdazen/bitsy/BitsyVertexProperty.java +++ b/src/main/java/com/lambdazen/bitsy/BitsyVertexProperty.java @@ -3,15 +3,14 @@ import java.util.Collections; import java.util.Iterator; import java.util.Set; - import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; public class BitsyVertexProperty extends BitsyProperty implements VertexProperty { - public BitsyVertexProperty(final BitsyVertex vertex, final String key, final V value) { - super(vertex, key, value); + public BitsyVertexProperty(final BitsyVertex vertex, final String key, final V value) { + super(vertex, key, value); } @Override @@ -21,28 +20,28 @@ public Set keys() { @Override public Property property(final String key) { - throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); + throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); } @Override public Property property(final String key, final U value) { - throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); + throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); } @Override public Vertex element() { - return (BitsyVertex)super.element(); + return (BitsyVertex) super.element(); } @Override public Iterator> properties(final String... propertyKeys) { - throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); + throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT); } - @Override - public Object id() { - return element().id().toString() + ":" + key(); - } + @Override + public Object id() { + return element().id().toString() + ":" + key(); + } public String toString() { return StringFactory.propertyString(this); diff --git a/src/main/java/com/lambdazen/bitsy/ICommitChanges.java b/src/main/java/com/lambdazen/bitsy/ICommitChanges.java index 9bbcde6..ff2ab3d 100644 --- a/src/main/java/com/lambdazen/bitsy/ICommitChanges.java +++ b/src/main/java/com/lambdazen/bitsy/ICommitChanges.java @@ -4,6 +4,6 @@ public interface ICommitChanges { public Collection getVertexChanges(); - + public Collection getEdgeChanges(); } diff --git a/src/main/java/com/lambdazen/bitsy/IGraphStore.java b/src/main/java/com/lambdazen/bitsy/IGraphStore.java index 8b77cc9..5f2b361 100644 --- a/src/main/java/com/lambdazen/bitsy/IGraphStore.java +++ b/src/main/java/com/lambdazen/bitsy/IGraphStore.java @@ -1,16 +1,14 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.store.EdgeBean; +import com.lambdazen.bitsy.store.VertexBean; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.Collection; import java.util.List; import java.util.Set; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Element; -import com.lambdazen.bitsy.store.EdgeBean; -import com.lambdazen.bitsy.store.VertexBean; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public interface IGraphStore { public void commit(ICommitChanges changes); @@ -22,26 +20,26 @@ public interface IGraphStore { /** Only to be used internally within the store */ public EdgeBean getEdge(UUID id); - + /** Returns a transaction-specific BitsyEdge given the tx and the ID */ public BitsyEdge getBitsyEdge(BitsyTransaction tx, UUID id); public List getEdges(UUID vertexId, Direction dir, String[] edgeLabels); - + public Collection getAllVertices(); - + public Collection getAllEdges(); - + public void createKeyIndex(String key, Class elementType); - + public void dropKeyIndex(String key, Class elementType); - + public Set getIndexedKeys(Class elementType); - + public void shutdown(); public Collection lookupVertices(String key, Object value); - + public Collection lookupEdges(String key, Object value); public boolean allowFullGraphScans(); diff --git a/src/main/java/com/lambdazen/bitsy/ITransaction.java b/src/main/java/com/lambdazen/bitsy/ITransaction.java index dc8ca0c..89896eb 100644 --- a/src/main/java/com/lambdazen/bitsy/ITransaction.java +++ b/src/main/java/com/lambdazen/bitsy/ITransaction.java @@ -1,7 +1,6 @@ package com.lambdazen.bitsy; import java.util.Iterator; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Transaction; @@ -9,7 +8,7 @@ public interface ITransaction extends Transaction { public void save(boolean commit); - + public void validateForQuery(BitsyElement bitsyElement) throws BitsyException; public Vertex getVertex(UUID outVertexId) throws BitsyException; @@ -17,13 +16,13 @@ public interface ITransaction extends Transaction { public Edge getEdge(UUID id) throws BitsyException; public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... edgeLabels) throws BitsyException; - + public void markForPropertyUpdate(BitsyElement bitsyElement) throws BitsyException; public void addVertex(BitsyVertex vertex) throws BitsyException; public void removeVertex(BitsyVertex vertex) throws BitsyException; - + public void addEdge(BitsyEdge edge) throws BitsyException; public void removeEdge(BitsyEdge edge) throws BitsyException; @@ -33,10 +32,10 @@ public interface ITransaction extends Transaction { public Iterator getAllEdges(); public Iterator lookupVertices(String key, Object value); - + public Iterator lookupEdges(String key, Object value); - public BitsyIsolationLevel getIsolationLevel(); + public BitsyIsolationLevel getIsolationLevel(); - public void setIsolationLevel(BitsyIsolationLevel level); + public void setIsolationLevel(BitsyIsolationLevel level); } diff --git a/src/main/java/com/lambdazen/bitsy/PortDatabase.java b/src/main/java/com/lambdazen/bitsy/PortDatabase.java index d0cebaa..5fce699 100644 --- a/src/main/java/com/lambdazen/bitsy/PortDatabase.java +++ b/src/main/java/com/lambdazen/bitsy/PortDatabase.java @@ -1,11 +1,12 @@ package com.lambdazen.bitsy; import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -18,10 +19,11 @@ public class PortDatabase { public static final List SUPPORTED_VERSIONS = Arrays.asList(new String[] {"1.0", "1.5"}); - private static final String[] FILE_NAMES = new String[] {"metaA.txt", "metaB.txt", "vA.txt", "vB.txt", "eA.txt", "eB.txt", "txA.txt", "txB.txt"}; - private static final Charset UTF8 = Charset.forName("UTF-8"); + private static final String[] FILE_NAMES = + new String[] {"metaA.txt", "metaB.txt", "vA.txt", "vB.txt", "eA.txt", "eB.txt", "txA.txt", "txB.txt"}; + private static final Charset UTF8 = Charset.forName("UTF-8"); - String targetVersion; + String targetVersion; Path sourcePath; Path targetPath; String sourceVersion; @@ -35,30 +37,32 @@ public PortDatabase(String[] args) throws IOException { setError("Expecting 4 arguments"); return; } - + this.targetVersion = null; int i; - for (i=0; i < args.length - 1; i++) { + for (i = 0; i < args.length - 1; i++) { if (args[i].equals("-toVersion")) { - targetVersion = args[i+1]; + targetVersion = args[i + 1]; break; } } - + String sourceDir = (i == 0) ? args[2] : args[0]; - String targetDir = (i == 2) ? args[1] : args[3]; + String targetDir = (i == 2) ? args[1] : args[3]; if (targetVersion == null) { setError("Could not find -toVersion flag followed by a version number"); - return; + return; } else if (!SUPPORTED_VERSIONS.contains(targetVersion)) { - setError("The version number " + targetVersion + " provided in the -toVersion flag is not supported. You must provide one of the following: " + SUPPORTED_VERSIONS); + setError("The version number " + targetVersion + + " provided in the -toVersion flag is not supported. You must provide one of the following: " + + SUPPORTED_VERSIONS); return; } this.sourcePath = Paths.get(sourceDir); this.targetPath = Paths.get(targetDir); - + if (!Files.isDirectory(sourcePath)) { setError("Source path " + sourceDir + " does not point to a directory"); return; @@ -75,16 +79,19 @@ public PortDatabase(String[] args) throws IOException { } if (!SUPPORTED_VERSIONS.contains(sourceVersion)) { - setError("The version number " + sourceVersion + " found in the source database is not supported. You must provide a database created by one of these versions of Bitsy: " + SUPPORTED_VERSIONS); + setError("The version number " + sourceVersion + + " found in the source database is not supported. You must provide a database created by one of these versions of Bitsy: " + + SUPPORTED_VERSIONS); return; } if (sourceVersion.equals(targetVersion)) { - setError("The source and target version numbers are the same: Version " + sourceVersion); + setError("The source and target version numbers are the same: Version " + sourceVersion); return; } - System.out.println("Porting database in " + sourceDir + " from version " + sourceVersion + " to version " + targetVersion + " under " + targetDir); + System.out.println("Porting database in " + sourceDir + " from version " + sourceVersion + " to version " + + targetVersion + " under " + targetDir); portDatabase(); @@ -92,42 +99,43 @@ public PortDatabase(String[] args) throws IOException { } private void portDatabase() throws IOException { - Converter converter; - if (sourceVersion.equals("1.0") && targetVersion.equals("1.5")) { - converter = new V10ToV15Coverter(); - } else if (sourceVersion.equals("1.5") && targetVersion.equals("1.0")) { - converter = new V15ToV10Coverter(); - } else { - setError("PortDatabase does not support porting from source version " + sourceVersion + " to target version " + targetVersion); - return; - } - - for (String fileName : FILE_NAMES) { - Path path = sourcePath.resolve(fileName); - - FileInputStream fis = null; - BufferedReader br = null; - FileOutputStream fos = null; + Converter converter; + if (sourceVersion.equals("1.0") && targetVersion.equals("1.5")) { + converter = new V10ToV15Coverter(); + } else if (sourceVersion.equals("1.5") && targetVersion.equals("1.0")) { + converter = new V15ToV10Coverter(); + } else { + setError("PortDatabase does not support porting from source version " + sourceVersion + + " to target version " + targetVersion); + return; + } + + for (String fileName : FILE_NAMES) { + Path path = sourcePath.resolve(fileName); + + InputStream fis = null; + BufferedReader br = null; + OutputStream fos = null; try { - fis = new FileInputStream(path.toFile()); - fos = new FileOutputStream(targetPath.resolve(fileName).toFile()); + fis = Files.newInputStream(path); + fos = Files.newOutputStream(targetPath.resolve(fileName)); br = new BufferedReader(new InputStreamReader(fis, UTF8)); - + String line; int lineNo = 0; while ((line = br.readLine()) != null) { - String outLine = converter.convert(line, lineNo, fileName); - if (outLine != null) { - fos.write(outLine.getBytes(UTF8)); - fos.write('\n'); - } + String outLine = converter.convert(line, lineNo, fileName); + if (outLine != null) { + fos.write(outLine.getBytes(UTF8)); + fos.write('\n'); + } } } finally { if (br != null) { br.close(); } - + if (fis != null) { fis.close(); } @@ -136,8 +144,8 @@ private void portDatabase() throws IOException { fos.close(); } } - } - } + } + } private String getVersion(Path sourcePath) throws IOException { Path mA = sourcePath.resolve("metaA.txt"); @@ -152,7 +160,7 @@ private String getVersion(Path sourcePath) throws IOException { } missingFiles = false; } - + if (Files.exists(mB)) { String versionB = getVersionFromPath(mB); if (versionB != null) { @@ -160,7 +168,7 @@ private String getVersion(Path sourcePath) throws IOException { } missingFiles = false; } - + if (missingFiles) { setError("Neither metaA.txt nor metaB.txt can be found in " + sourcePath); return null; @@ -168,15 +176,10 @@ private String getVersion(Path sourcePath) throws IOException { return version; } } - + public String getVersionFromPath(Path metaPath) throws IOException { - FileInputStream fis = null; - BufferedReader br = null; String fileName = metaPath.toString(); - - try { - fis = new FileInputStream(metaPath.toFile()); - br = new BufferedReader(new InputStreamReader(fis, Charset.forName("UTF-8"))); + try (BufferedReader br = Files.newBufferedReader(metaPath, StandardCharsets.UTF_8)) { String line; int lineNo = 0; while ((line = br.readLine()) != null) { @@ -184,13 +187,18 @@ public String getVersionFromPath(Path metaPath) throws IOException { int hashPos = line.lastIndexOf('#'); if (hashPos < 0) { - throw new BitsyException(BitsyErrorCodes.CHECKSUM_MISMATCH, "Line " + lineNo + " in file " + fileName + " has no hash-code. Encountered " + line); + throw new BitsyException( + BitsyErrorCodes.CHECKSUM_MISMATCH, + "Line " + lineNo + " in file " + fileName + " has no hash-code. Encountered " + line); } else { String hashCode = line.substring(hashPos + 1); String expHashCode = toHex(line.substring(0, hashPos + 1).hashCode()); if (!hashCode.endsWith(expHashCode)) { - throw new BitsyException(BitsyErrorCodes.CHECKSUM_MISMATCH, "Line " + lineNo + " in file " + fileName + " has the wrong hash-code " + hashCode + ". Expected " + expHashCode); + throw new BitsyException( + BitsyErrorCodes.CHECKSUM_MISMATCH, + "Line " + lineNo + " in file " + fileName + " has the wrong hash-code " + hashCode + + ". Expected " + expHashCode); } else { // All OK char typeChar = line.charAt(0); @@ -202,14 +210,6 @@ public String getVersionFromPath(Path metaPath) throws IOException { } } } - } finally { - if (br != null) { - br.close(); - } - - if (fis != null) { - fis.close(); - } } return null; @@ -228,7 +228,8 @@ private static void printUsage(String error) { System.err.println("ERROR: " + error); } - System.err.println("Usage: java com.lambdazen.bitsy.PortDatabase -toVersion "); + System.err.println( + "Usage: java com.lambdazen.bitsy.PortDatabase -toVersion "); } public static void main(String[] args) { @@ -244,67 +245,68 @@ public static void main(String[] args) { System.exit(1); } } - + // Faster than Integer.toHexString() private static final char[] HEX_CHAR_ARR = "0123456789abcdef".toCharArray(); + private static String toHex(int input) { final char[] sb = new char[8]; - final int len = (sb.length-1); + final int len = (sb.length - 1); for (int i = 0; i <= len; i++) { // MSB - sb[i] = HEX_CHAR_ARR[((int)(input >>> ((len - i)<<2))) & 0xF]; + sb[i] = HEX_CHAR_ARR[((int) (input >>> ((len - i) << 2))) & 0xF]; } return new String(sb); } - + public interface Converter { - public String convert(String line, int lineNo, String fileName); + public String convert(String line, int lineNo, String fileName); } public class V10ToV15Coverter implements Converter { - Pattern edgePat = Pattern.compile("^(E=\\{[^{}]*,\"p\":)\\[\"java.util.TreeMap\",(.*)\\]\\}#[0-9a-zA-Z]*$"); - - @Override - public String convert(String line, int lineNo, String fileName) { - if (line.startsWith("H=") && fileName.startsWith("meta")) { - String versionLine = "M=1.5#"; - return line + "\n" + versionLine + toHex(versionLine.hashCode()); - } else if (line.startsWith("E=")) { - Matcher m = edgePat.matcher(line); - if (!m.find()) { - return line; - } else { - // Move from TreeMap to Map - line = m.group(1) + m.group(2) + "}#"; - - return line + toHex(line.hashCode()); - } - } else { - return line; - } - } + Pattern edgePat = Pattern.compile("^(E=\\{[^{}]*,\"p\":)\\[\"java.util.TreeMap\",(.*)\\]\\}#[0-9a-zA-Z]*$"); + + @Override + public String convert(String line, int lineNo, String fileName) { + if (line.startsWith("H=") && fileName.startsWith("meta")) { + String versionLine = "M=1.5#"; + return line + "\n" + versionLine + toHex(versionLine.hashCode()); + } else if (line.startsWith("E=")) { + Matcher m = edgePat.matcher(line); + if (!m.find()) { + return line; + } else { + // Move from TreeMap to Map + line = m.group(1) + m.group(2) + "}#"; + + return line + toHex(line.hashCode()); + } + } else { + return line; + } + } } public class V15ToV10Coverter implements Converter { - Pattern edgePat = Pattern.compile("^(E=\\{[^{}]*,\"p\":)(.*)\\}#[0-9a-zA-Z]*$"); - - @Override - public String convert(String line, int lineNo, String fileName) { - if (line.startsWith("M=") && fileName.startsWith("meta")) { - // Skip the version - return null; - } else if (line.startsWith("E=")) { - Matcher m = edgePat.matcher(line); - if (!m.find()) { - return line; - } else { - // Move from TreeMap to Map - line = m.group(1) + "[\"java.util.TreeMap\"," + m.group(2) + "]}#"; - - return line + toHex(line.hashCode()); - } - } else { - return line; - } - } + Pattern edgePat = Pattern.compile("^(E=\\{[^{}]*,\"p\":)(.*)\\}#[0-9a-zA-Z]*$"); + + @Override + public String convert(String line, int lineNo, String fileName) { + if (line.startsWith("M=") && fileName.startsWith("meta")) { + // Skip the version + return null; + } else if (line.startsWith("E=")) { + Matcher m = edgePat.matcher(line); + if (!m.find()) { + return line; + } else { + // Move from TreeMap to Map + line = m.group(1) + "[\"java.util.TreeMap\"," + m.group(2) + "]}#"; + + return line + toHex(line.hashCode()); + } + } else { + return line; + } + } } } diff --git a/src/main/java/com/lambdazen/bitsy/ThreadedBitsyGraph.java b/src/main/java/com/lambdazen/bitsy/ThreadedBitsyGraph.java index aadf620..315a113 100644 --- a/src/main/java/com/lambdazen/bitsy/ThreadedBitsyGraph.java +++ b/src/main/java/com/lambdazen/bitsy/ThreadedBitsyGraph.java @@ -1,24 +1,20 @@ package com.lambdazen.bitsy; -import java.util.Set; - -import org.apache.tinkerpop.gremlin.structure.Element; - import com.lambdazen.bitsy.tx.BitsyTransaction; import com.lambdazen.bitsy.tx.BitsyTransactionContext; public class ThreadedBitsyGraph extends BitsyGraph { BitsyGraph underlyingGraph; BitsyTransaction tx; - + public ThreadedBitsyGraph(BitsyGraph g) { // Using protected constructor that doesn't create a graph store super('_', g.isFullGraphScanAllowed()); - + this.underlyingGraph = g; this.tx = null; } - + public String toString() { return underlyingGraph.toString(); } @@ -27,16 +23,19 @@ public String toString() { public Features features() { return underlyingGraph.features(); } - + @Override protected BitsyTransaction getTx() { // Overriding the getTx() method ensures that the work will be done on - // the local transaction, NOT the ThreadLocal transaction + // the local transaction, NOT the ThreadLocal transaction if ((tx == null) || (!tx.isOpen())) { - this.tx = new BitsyTransaction(new BitsyTransactionContext(underlyingGraph.getStore()), getDefaultIsolationLevel(), underlyingGraph); + this.tx = new BitsyTransaction( + new BitsyTransactionContext(underlyingGraph.getStore()), + getDefaultIsolationLevel(), + underlyingGraph); } - return tx; + return tx; } @Override @@ -48,76 +47,76 @@ public boolean isTransactionActive() { public BitsyIsolationLevel getDefaultIsolationLevel() { return underlyingGraph.getDefaultIsolationLevel(); } - + public void setDefaultIsolationLevel(BitsyIsolationLevel level) { underlyingGraph.setDefaultIsolationLevel(level); } - + public BitsyIsolationLevel getTxIsolationLevel() { return getTx().getIsolationLevel(); } - + public void setTxIsolationLevel(BitsyIsolationLevel level) { - getTx().setIsolationLevel(level); + getTx().setIsolationLevel(level); } @Override public void shutdown() { - // As per Blueprints tests, shutdown() implies automatic commit - if (tx == null) { - // Nothing to do - } else { - try { - // Stop the old transaction if it exists - tx.commit(); - } finally { - // Remove this transaction -- independent of success/failure - this.tx = null; - } - } - - // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one + // As per Blueprints tests, shutdown() implies automatic commit + if (tx == null) { + // Nothing to do + } else { + try { + // Stop the old transaction if it exists + tx.commit(); + } finally { + // Remove this transaction -- independent of success/failure + this.tx = null; + } + } + + // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one } -// @Deprecated -// public void stopTransaction(Conclusion conclusion) { -// stopTx(conclusion == Conclusion.SUCCESS); -// } - -// @Override -// public void commit() { -// tx.save(commit); -// } -// -// @Override -// public void rollback() { -// stopTx(false); -// } -// -// public void stopTx(boolean commit) { -// if (tx == null) { -// // Nothing to do -// } else { -// try { -// // Stop the old transaction if it exists -// tx.save(commit); -// } finally { -// // Remove this transaction -- independent of success/failure -// this.tx = null; -// } -// } -// } -// -// @Override -// public TransactionalGraph startTransaction() { -// throw new UnsupportedOperationException("Can not startTransaction on a threaded transaction graph"); -// } -// -// @Override -// public void shutdown() { -// // As per Blueprints tests, shutdown() implies automatic commit -// stopTx(true); -// -// // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one -// } + // @Deprecated + // public void stopTransaction(Conclusion conclusion) { + // stopTx(conclusion == Conclusion.SUCCESS); + // } + + // @Override + // public void commit() { + // tx.save(commit); + // } + // + // @Override + // public void rollback() { + // stopTx(false); + // } + // + // public void stopTx(boolean commit) { + // if (tx == null) { + // // Nothing to do + // } else { + // try { + // // Stop the old transaction if it exists + // tx.save(commit); + // } finally { + // // Remove this transaction -- independent of success/failure + // this.tx = null; + // } + // } + // } + // + // @Override + // public TransactionalGraph startTransaction() { + // throw new UnsupportedOperationException("Can not startTransaction on a threaded transaction graph"); + // } + // + // @Override + // public void shutdown() { + // // As per Blueprints tests, shutdown() implies automatic commit + // stopTx(true); + // + // // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one + // } } diff --git a/src/main/java/com/lambdazen/bitsy/UUID.java b/src/main/java/com/lambdazen/bitsy/UUID.java index 166b2b6..dfd1e56 100644 --- a/src/main/java/com/lambdazen/bitsy/UUID.java +++ b/src/main/java/com/lambdazen/bitsy/UUID.java @@ -5,13 +5,14 @@ /** This class captures a UUID and is modeled after java.util.UUID */ public class UUID implements Comparable { // Java guarantees that - // "Reads and writes are atomic for reference variables and for most primitive variables (all types except long and double)." + // "Reads and writes are atomic for reference variables and for most primitive variables (all types except long and + // double)." // Therefore, mostSigBits and leastSigBits must not be changed during the lifetime of this object. // Also, these objects must not be accessible to other threads without a memory flush/fence/barrier // Typically this memory barrier is handled by the ConcurrentHashMap that holds the vertex/edge bean. private final long mostSigBits; private final long leastSigBits; - + public UUID(long msb, long lsb) { this.mostSigBits = msb; this.leastSigBits = lsb; @@ -30,23 +31,23 @@ public long getLeastSignificantBits() { public String toString() { return uuidRepr(); } - + public String uuidRepr() { return new java.util.UUID(mostSigBits, leastSigBits).toString(); } - + public static UUID fromString(String str) { java.util.UUID ans = java.util.UUID.fromString(str); - + return new UUID(ans.getMostSignificantBits(), ans.getLeastSignificantBits()); } public static UUID randomUUID() { java.util.UUID ans = java.util.UUID.randomUUID(); - + return new UUID(ans.getMostSignificantBits(), ans.getLeastSignificantBits()); } - + public int compareTo(UUID other) { if (this.mostSigBits < other.mostSigBits) { return -1; @@ -60,25 +61,25 @@ public int compareTo(UUID other) { return 0; } } - @Override public int hashCode() { // Same as java.util.UUID long hilo = mostSigBits ^ leastSigBits; - return ((int)(hilo >> 32)) ^ (int) hilo; + return ((int) (hilo >> 32)) ^ (int) hilo; } - + @Override public boolean equals(Object obj) { - if (obj == null) { + if (obj == null) { return false; } else if (this == obj) { return true; } else { try { - UUID other = (UUID)obj; - return (mostSigBits == other.getMostSignificantBits()) && (leastSigBits == other.getLeastSignificantBits()); + UUID other = (UUID) obj; + return (mostSigBits == other.getMostSignificantBits()) + && (leastSigBits == other.getLeastSignificantBits()); } catch (ClassCastException e) { return false; } diff --git a/src/main/java/com/lambdazen/bitsy/UUIDGraphBinarySerializer.java b/src/main/java/com/lambdazen/bitsy/UUIDGraphBinarySerializer.java index ff0f45f..705bfa6 100644 --- a/src/main/java/com/lambdazen/bitsy/UUIDGraphBinarySerializer.java +++ b/src/main/java/com/lambdazen/bitsy/UUIDGraphBinarySerializer.java @@ -1,17 +1,15 @@ package com.lambdazen.bitsy; +import java.io.IOException; import org.apache.tinkerpop.gremlin.structure.io.Buffer; import org.apache.tinkerpop.gremlin.structure.io.binary.DataType; import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader; import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter; import org.apache.tinkerpop.gremlin.structure.io.binary.types.CustomTypeSerializer; -import java.io.IOException; - -public class UUIDGraphBinarySerializer implements CustomTypeSerializer -{ +public class UUIDGraphBinarySerializer implements CustomTypeSerializer { - private final byte[] typeInfoBuffer = new byte[] { 0, 0, 0, 0 }; + private final byte[] typeInfoBuffer = new byte[] {0, 0, 0, 0}; @Override public String getTypeName() { @@ -92,5 +90,4 @@ public void writeValue(UUID value, Buffer buffer, GraphBinaryWriter context, boo context.writeValue(msb, buffer, false); context.writeValue(lsb, buffer, false); } - } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary.java index ffec8db..246c0ec 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary.java @@ -7,19 +7,19 @@ * and remove methods return a reference to a new map with the value. */ public interface Dictionary { - public int size(); - - public Object getProperty(String key); - - public String[] getPropertyKeys(); - - public Dictionary setProperty(String key, Object value); - - public Dictionary removeProperty(String key); - - public Dictionary copyOf(); - -// public TreeMap toMap(); - - public void canonicalizeKeys(IStringCanonicalizer canonicalizer); + public int size(); + + public Object getProperty(String key); + + public String[] getPropertyKeys(); + + public Dictionary setProperty(String key, Object value); + + public Dictionary removeProperty(String key); + + public Dictionary copyOf(); + + // public TreeMap toMap(); + + public void canonicalizeKeys(IStringCanonicalizer canonicalizer); } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary1.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary1.java index 6aaab23..3776c00 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary1.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary1.java @@ -1,59 +1,59 @@ package com.lambdazen.bitsy.ads.dict; -/** This class implements a dictionary with one element */ +/** This class implements a dictionary with one element */ public class Dictionary1 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 1; - - String key0; - Object value0; - - // Expand constructor - public Dictionary1(String key, Object value) { - this.key0 = key; - this.value0 = value; - } - - // Contract constructor - public Dictionary1(Dictionary2 base) { - this.key0 = base.key0; - this.value0 = base.value0; - } - - // Copy constructor - public Dictionary1(Dictionary1 base) { - this.key0 = base.key0; - this.value0 = base.value0; - } - - @Override - protected String[] keys() { - return new String[] {key0}; - } - - @Override - protected Object[] values() { - return new Object[] {value0}; - } + public static final int CAPACITY = 1; + + String key0; + Object value0; + + // Expand constructor + public Dictionary1(String key, Object value) { + this.key0 = key; + this.value0 = value; + } + + // Contract constructor + public Dictionary1(Dictionary2 base) { + this.key0 = base.key0; + this.value0 = base.value0; + } + + // Copy constructor + public Dictionary1(Dictionary1 base) { + this.key0 = base.key0; + this.value0 = base.value0; + } + + @Override + protected String[] keys() { + return new String[] {key0}; + } + + @Override + protected Object[] values() { + return new Object[] {value0}; + } @Override public Dictionary copyOf() { - return new Dictionary1(this); - } - - protected int contractThreshold() { - return 0; - } - - protected Dictionary contract() { - return null; - } - - protected Dictionary expand(String key, Object value) { - return new Dictionary2(this, key, value); - } - - protected void write(int index, String key, Object value) { - key0 = key; - value0 = value; - } + return new Dictionary1(this); + } + + protected int contractThreshold() { + return 0; + } + + protected Dictionary contract() { + return null; + } + + protected Dictionary expand(String key, Object value) { + return new Dictionary2(this, key, value); + } + + protected void write(int index, String key, Object value) { + key0 = key; + value0 = value; + } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary11.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary11.java index 5fbff5b..4be79bf 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary11.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary11.java @@ -1,116 +1,116 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary11 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 11; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - String key3; - Object value3; - - String key4; - Object value4; - - String key5; - Object value5; - - String key6; - Object value6; - - String key7; - Object value7; - - String key8; - Object value8; - - String key9; - Object value9; - - String key10; - Object value10; - - // Expand constructor - public Dictionary11(Dictionary8 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - - this.key6 = base.key6; - this.value6 = base.value6; - - this.key7 = base.key7; - this.value7 = base.value7; - - // Last key - this.key8 = key; - this.value8 = value; - } - - // Contract constructor - public Dictionary11(Dictionary16 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - - this.key6 = base.key6; - this.value6 = base.value6; - - this.key7 = base.key7; - this.value7 = base.value7; - - this.key8 = base.key8; - this.value8 = base.value8; - - this.key9 = base.key9; - this.value9 = base.value9; - - this.key10 = base.key10; - this.value10 = base.value10; - } - - // Copy constructor + public static final int CAPACITY = 11; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + String key3; + Object value3; + + String key4; + Object value4; + + String key5; + Object value5; + + String key6; + Object value6; + + String key7; + Object value7; + + String key8; + Object value8; + + String key9; + Object value9; + + String key10; + Object value10; + + // Expand constructor + public Dictionary11(Dictionary8 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + + this.key6 = base.key6; + this.value6 = base.value6; + + this.key7 = base.key7; + this.value7 = base.value7; + + // Last key + this.key8 = key; + this.value8 = value; + } + + // Contract constructor + public Dictionary11(Dictionary16 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + + this.key6 = base.key6; + this.value6 = base.value6; + + this.key7 = base.key7; + this.value7 = base.value7; + + this.key8 = base.key8; + this.value8 = base.value8; + + this.key9 = base.key9; + this.value9 = base.value9; + + this.key10 = base.key10; + this.value10 = base.value10; + } + + // Copy constructor public Dictionary11(Dictionary11 base) { this.key0 = base.key0; this.value0 = base.value0; - + this.key1 = base.key1; this.value1 = base.value1; - + this.key2 = base.key2; this.value2 = base.value2; @@ -134,7 +134,7 @@ public Dictionary11(Dictionary11 base) { this.key9 = base.key9; this.value9 = base.value9; - + this.key10 = base.key10; this.value10 = base.value10; } @@ -174,104 +174,104 @@ public Dictionary11(String[] keys, Object[] values) { this.key10 = lookupKey(keys, 10); this.value10 = lookupValue(values, 10); } - + + @Override + String[] keys() { + return new String[] {key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10}; + } + @Override - String[] keys() { - return new String[] {key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10}; - } - - @Override - void write(int index, String key, Object value) { - if (index < 6) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - case 3: - key3 = key; - value3 = value; - break; - - case 4: - key4 = key; - value4 = value; - break; - - case 5: - key5 = key; - value5 = value; - break; - - default: - throw new RuntimeException("Bug in code"); - } - } else { - switch (index) { - case 6: - key6 = key; - value6 = value; - break; - - case 7: - key7 = key; - value7 = value; - break; - - case 8: - key8 = key; - value8 = value; - break; - - case 9: - key9 = key; - value9 = value; - break; - - case 10: - key10 = key; - value10 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary16(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary8.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary8(this); - } - - @Override - public Dictionary copyOf() { - return new Dictionary11(this); - } + void write(int index, String key, Object value) { + if (index < 6) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + case 3: + key3 = key; + value3 = value; + break; + + case 4: + key4 = key; + value4 = value; + break; + + case 5: + key5 = key; + value5 = value; + break; + + default: + throw new RuntimeException("Bug in code"); + } + } else { + switch (index) { + case 6: + key6 = key; + value6 = value; + break; + + case 7: + key7 = key; + value7 = value; + break; + + case 8: + key8 = key; + value8 = value; + break; + + case 9: + key9 = key; + value9 = value; + break; + + case 10: + key10 = key; + value10 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary16(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary8.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary8(this); + } + + @Override + public Dictionary copyOf() { + return new Dictionary11(this); + } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary16.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary16.java index 9161560..986c8d0 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary16.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary16.java @@ -3,197 +3,143 @@ import java.util.Arrays; public class Dictionary16 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 16; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - String key3; - Object value3; - - String key4; - Object value4; - - String key5; - Object value5; - - String key6; - Object value6; - - String key7; - Object value7; - - String key8; - Object value8; - - String key9; - Object value9; - - String key10; - Object value10; - - String key11; - Object value11; - - String key12; - Object value12; - - String key13; - Object value13; - - String key14; - Object value14; - - String key15; - Object value15; - - // Expand constructor - public Dictionary16(Dictionary11 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - - this.key6 = base.key6; - this.value6 = base.value6; - - this.key7 = base.key7; - this.value7 = base.value7; - - this.key8 = base.key8; - this.value8 = base.value8; - - this.key9 = base.key9; - this.value9 = base.value9; - - this.key10 = base.key10; - this.value10 = base.value10; - - // Last key - this.key11 = key; - this.value11 = value; - } - - // Contract constructor - public Dictionary16(DictionaryMax base) { - String[] keys = Arrays.copyOf(base.keys(), 16); - Object[] values = Arrays.copyOf(base.values(), 16); - - this.key0 = keys[0]; - this.value0 = values[0]; - - this.key1 = keys[1]; - this.value1 = values[1]; - - this.key2 = keys[2]; - this.value2 = values[2]; - - this.key3 = keys[3]; - this.value3 = values[3]; - - this.key4 = keys[4]; - this.value4 = values[4]; - - this.key5 = keys[5]; - this.value5 = values[5]; - - this.key6 = keys[6]; - this.value6 = values[6]; - - this.key7 = keys[7]; - this.value7 = values[7]; - - this.key8 = keys[8]; - this.value8 = values[8]; - - this.key9 = keys[9]; - this.value9 = values[9]; - - this.key10 = keys[10]; - this.value10 = values[10]; - - this.key11 = keys[11]; - this.value11 = values[11]; - - this.key12 = keys[12]; - this.value12 = values[12]; - - this.key13 = keys[13]; - this.value13 = values[13]; - - this.key14 = keys[14]; - this.value14 = values[14]; - - this.key15 = keys[15]; - this.value15 = values[15]; - } - - // Copy constructor - public Dictionary16(Dictionary16 base) { + public static final int CAPACITY = 16; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + String key3; + Object value3; + + String key4; + Object value4; + + String key5; + Object value5; + + String key6; + Object value6; + + String key7; + Object value7; + + String key8; + Object value8; + + String key9; + Object value9; + + String key10; + Object value10; + + String key11; + Object value11; + + String key12; + Object value12; + + String key13; + Object value13; + + String key14; + Object value14; + + String key15; + Object value15; + + // Expand constructor + public Dictionary16(Dictionary11 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + + this.key6 = base.key6; + this.value6 = base.value6; + + this.key7 = base.key7; + this.value7 = base.value7; + + this.key8 = base.key8; + this.value8 = base.value8; + + this.key9 = base.key9; + this.value9 = base.value9; + + this.key10 = base.key10; + this.value10 = base.value10; + + // Last key + this.key11 = key; + this.value11 = value; + } + + // Contract constructor + public Dictionary16(DictionaryMax base) { String[] keys = Arrays.copyOf(base.keys(), 16); Object[] values = Arrays.copyOf(base.values(), 16); - + this.key0 = keys[0]; this.value0 = values[0]; this.key1 = keys[1]; this.value1 = values[1]; - + this.key2 = keys[2]; this.value2 = values[2]; this.key3 = keys[3]; this.value3 = values[3]; - + this.key4 = keys[4]; this.value4 = values[4]; this.key5 = keys[5]; this.value5 = values[5]; - + this.key6 = keys[6]; this.value6 = values[6]; this.key7 = keys[7]; this.value7 = values[7]; - + this.key8 = keys[8]; this.value8 = values[8]; this.key9 = keys[9]; this.value9 = values[9]; - + this.key10 = keys[10]; this.value10 = values[10]; this.key11 = keys[11]; this.value11 = values[11]; - + this.key12 = keys[12]; this.value12 = values[12]; this.key13 = keys[13]; this.value13 = values[13]; - + this.key14 = keys[14]; this.value14 = values[14]; @@ -201,6 +147,59 @@ public Dictionary16(Dictionary16 base) { this.value15 = values[15]; } + // Copy constructor + public Dictionary16(Dictionary16 base) { + String[] keys = Arrays.copyOf(base.keys(), 16); + Object[] values = Arrays.copyOf(base.values(), 16); + + this.key0 = keys[0]; + this.value0 = values[0]; + + this.key1 = keys[1]; + this.value1 = values[1]; + + this.key2 = keys[2]; + this.value2 = values[2]; + + this.key3 = keys[3]; + this.value3 = values[3]; + + this.key4 = keys[4]; + this.value4 = values[4]; + + this.key5 = keys[5]; + this.value5 = values[5]; + + this.key6 = keys[6]; + this.value6 = values[6]; + + this.key7 = keys[7]; + this.value7 = values[7]; + + this.key8 = keys[8]; + this.value8 = values[8]; + + this.key9 = keys[9]; + this.value9 = values[9]; + + this.key10 = keys[10]; + this.value10 = values[10]; + + this.key11 = keys[11]; + this.value11 = values[11]; + + this.key12 = keys[12]; + this.value12 = values[12]; + + this.key13 = keys[13]; + this.value13 = values[13]; + + this.key14 = keys[14]; + this.value14 = values[14]; + + this.key15 = keys[15]; + this.value15 = values[15]; + } // FromMap constructor public Dictionary16(String[] keys, Object[] values) { @@ -252,140 +251,142 @@ public Dictionary16(String[] keys, Object[] values) { this.key15 = lookupKey(keys, 15); this.value15 = lookupValue(values, 15); } - - @Override - String[] keys() { - return new String[] {key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10, key11, key12, key13, key14, key15}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12, value13, value14, value15}; - } - - @Override - void write(int index, String key, Object value) { - if (index < 4) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - case 3: - key3 = key; - value3 = value; - break; - - default: - throw new RuntimeException("Bug in code"); - } - } else if (index < 8){ - switch (index) { - - case 4: - key4 = key; - value4 = value; - break; - - case 5: - key5 = key; - value5 = value; - break; - - case 6: - key6 = key; - value6 = value; - break; - - case 7: - key7 = key; - value7 = value; - break; - - default: - throw new RuntimeException("Bug in code"); - } - } else if (index < 12 ) { - switch (index) { - - case 8: - key8 = key; - value8 = value; - break; - - case 9: - key9 = key; - value9 = value; - break; - - case 10: - key10 = key; - value10 = value; - break; - - case 11: - key11 = key; - value11 = value; - break; - - default: - throw new RuntimeException("Bug in code"); - } - } else { - switch (index) { - - case 12: - key12 = key; - value12 = value; - break; - - case 13: - key13 = key; - value13 = value; - break; - - case 14: - key14 = key; - value14 = value; - break; - - case 15: - key15 = key; - value15 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - } - - @Override - Dictionary expand(String key, Object value) { - return new DictionaryMax(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary11.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary11(this); - } - + + @Override + String[] keys() { + return new String[] { + key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10, key11, key12, key13, key14, key15 + }; + } + + @Override + Object[] values() { + return new Object[] { + value0, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12, + value13, value14, value15 + }; + } + + @Override + void write(int index, String key, Object value) { + if (index < 4) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + case 3: + key3 = key; + value3 = value; + break; + + default: + throw new RuntimeException("Bug in code"); + } + } else if (index < 8) { + switch (index) { + case 4: + key4 = key; + value4 = value; + break; + + case 5: + key5 = key; + value5 = value; + break; + + case 6: + key6 = key; + value6 = value; + break; + + case 7: + key7 = key; + value7 = value; + break; + + default: + throw new RuntimeException("Bug in code"); + } + } else if (index < 12) { + switch (index) { + case 8: + key8 = key; + value8 = value; + break; + + case 9: + key9 = key; + value9 = value; + break; + + case 10: + key10 = key; + value10 = value; + break; + + case 11: + key11 = key; + value11 = value; + break; + + default: + throw new RuntimeException("Bug in code"); + } + } else { + switch (index) { + case 12: + key12 = key; + value12 = value; + break; + + case 13: + key13 = key; + value13 = value; + break; + + case 14: + key14 = key; + value14 = value; + break; + + case 15: + key15 = key; + value15 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + } + + @Override + Dictionary expand(String key, Object value) { + return new DictionaryMax(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary11.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary11(this); + } + @Override public Dictionary copyOf() { return new Dictionary16(this); diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary2.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary2.java index b513352..04b6362 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary2.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary2.java @@ -1,43 +1,43 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary2 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 2; - - String key0; - Object value0; - - String key1; - Object value1; - - // Expand constructor - public Dictionary2(Dictionary1 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - // Last key - this.key1 = key; - this.value1 = value; - } - + public static final int CAPACITY = 2; + + String key0; + Object value0; + + String key1; + Object value1; + + // Expand constructor + public Dictionary2(Dictionary1 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + // Last key + this.key1 = key; + this.value1 = value; + } + // Contract constructor - public Dictionary2(Dictionary3 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - } - - // Copy constructor - public Dictionary2(Dictionary2 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - } - - // FromMap constructor + public Dictionary2(Dictionary3 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + } + + // Copy constructor + public Dictionary2(Dictionary2 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + } + + // FromMap constructor public Dictionary2(String[] keys, Object[] values) { this.key0 = lookupKey(keys, 0); this.value0 = lookupValue(values, 0); @@ -46,51 +46,51 @@ public Dictionary2(String[] keys, Object[] values) { this.value1 = lookupValue(values, 1); } - @Override - String[] keys() { - return new String[] {key0, key1}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1}; - } - - @Override - void write(int index, String key, Object value) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary3(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary1.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary1(this); - } - - @Override - public Dictionary copyOf() { + @Override + String[] keys() { + return new String[] {key0, key1}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1}; + } + + @Override + void write(int index, String key, Object value) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary3(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary1.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary1(this); + } + + @Override + public Dictionary copyOf() { return new Dictionary2(this); } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary3.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary3.java index d105892..7fcb848 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary3.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary3.java @@ -1,54 +1,54 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary3 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 3; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - // Expand constructor - public Dictionary3(Dictionary2 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - // Last key - this.key2 = key; - this.value2 = value; - } - - // Contract constructor - public Dictionary3(Dictionary4 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - } - - // Copy constructor - public Dictionary3(Dictionary3 base) { + public static final int CAPACITY = 3; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + // Expand constructor + public Dictionary3(Dictionary2 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + // Last key + this.key2 = key; + this.value2 = value; + } + + // Contract constructor + public Dictionary3(Dictionary4 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + } + + // Copy constructor + public Dictionary3(Dictionary3 base) { this.key0 = base.key0; this.value0 = base.value0; - + this.key1 = base.key1; this.value1 = base.value1; - + this.key2 = base.key2; this.value2 = base.value2; } - + // FromMap constructor public Dictionary3(String[] keys, Object[] values) { this.key0 = lookupKey(keys, 0); @@ -61,56 +61,56 @@ public Dictionary3(String[] keys, Object[] values) { this.value2 = lookupValue(values, 2); } - @Override - String[] keys() { - return new String[] {key0, key1, key2}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2}; - } - - @Override - void write(int index, String key, Object value) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary4(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary2.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary2(this); - } - - @Override - public Dictionary copyOf() { + @Override + String[] keys() { + return new String[] {key0, key1, key2}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1, value2}; + } + + @Override + void write(int index, String key, Object value) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary4(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary2.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary2(this); + } + + @Override + public Dictionary copyOf() { return new Dictionary3(this); } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary4.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary4.java index 45d727b..e8c3673 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary4.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary4.java @@ -1,66 +1,66 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary4 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 4; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - String key3; - Object value3; - + public static final int CAPACITY = 4; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + String key3; + Object value3; + // Expand constructor - public Dictionary4(Dictionary3 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - // Last key - this.key3 = key; - this.value3 = value; - } - + public Dictionary4(Dictionary3 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + // Last key + this.key3 = key; + this.value3 = value; + } + // Contract constructor - public Dictionary4(Dictionary6 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - } - - // Copy constructor + public Dictionary4(Dictionary6 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + } + + // Copy constructor public Dictionary4(Dictionary4 base) { this.key0 = base.key0; this.value0 = base.value0; - + this.key1 = base.key1; this.value1 = base.value1; - + this.key2 = base.key2; this.value2 = base.value2; this.key3 = base.key3; this.value3 = base.value3; } - + // FromMap constructor public Dictionary4(String[] keys, Object[] values) { this.key0 = lookupKey(keys, 0); @@ -76,61 +76,61 @@ public Dictionary4(String[] keys, Object[] values) { this.value3 = lookupValue(values, 3); } - @Override - String[] keys() { - return new String[] {key0, key1, key2, key3}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2, value3}; - } - - @Override - void write(int index, String key, Object value) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - case 3: - key3 = key; - value3 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary6(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary3.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary3(this); - } - - @Override - public Dictionary copyOf() { + @Override + String[] keys() { + return new String[] {key0, key1, key2, key3}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1, value2, value3}; + } + + @Override + void write(int index, String key, Object value) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + case 3: + key3 = key; + value3 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary6(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary3.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary3(this); + } + + @Override + public Dictionary copyOf() { return new Dictionary4(this); } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary6.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary6.java index f04af1b..09c15d6 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary6.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary6.java @@ -1,74 +1,74 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary6 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 6; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - String key3; - Object value3; - - String key4; - Object value4; - - String key5; - Object value5; - - // Expand constructor - public Dictionary6(Dictionary4 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - // Last key - this.key4 = key; - this.value4 = value; - } + public static final int CAPACITY = 6; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + String key3; + Object value3; + + String key4; + Object value4; + + String key5; + Object value5; + + // Expand constructor + public Dictionary6(Dictionary4 base, String key, Object value) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + // Last key + this.key4 = key; + this.value4 = value; + } // Contract constructor - public Dictionary6(Dictionary8 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - } - - // Copy constructor + public Dictionary6(Dictionary8 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + } + + // Copy constructor public Dictionary6(Dictionary6 base) { this.key0 = base.key0; this.value0 = base.value0; - + this.key1 = base.key1; this.value1 = base.value1; - + this.key2 = base.key2; this.value2 = base.value2; @@ -81,7 +81,7 @@ public Dictionary6(Dictionary6 base) { this.key5 = base.key5; this.value5 = base.value5; } - + // FromMap constructor public Dictionary6(String[] keys, Object[] values) { this.key0 = lookupKey(keys, 0); @@ -102,72 +102,72 @@ public Dictionary6(String[] keys, Object[] values) { this.key5 = lookupKey(keys, 5); this.value5 = lookupValue(values, 5); } - + + @Override + String[] keys() { + return new String[] {key0, key1, key2, key3, key4, key5}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1, value2, value3, value4, value5}; + } + + @Override + void write(int index, String key, Object value) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + case 3: + key3 = key; + value3 = value; + break; + + case 4: + key4 = key; + value4 = value; + break; + + case 5: + key5 = key; + value5 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary8(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary4.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary4(this); + } + @Override - String[] keys() { - return new String[] {key0, key1, key2, key3, key4, key5}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2, value3, value4, value5}; - } - - @Override - void write(int index, String key, Object value) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - case 3: - key3 = key; - value3 = value; - break; - - case 4: - key4 = key; - value4 = value; - break; - - case 5: - key5 = key; - value5 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary8(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary4.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary4(this); - } - - @Override - public Dictionary copyOf() { + public Dictionary copyOf() { return new Dictionary6(this); } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary8.java b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary8.java index 85a3bab..77581f9 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary8.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary8.java @@ -1,92 +1,92 @@ package com.lambdazen.bitsy.ads.dict; public class Dictionary8 extends PrimitiveDictionary implements Dictionary { - public static final int CAPACITY = 8; - - String key0; - Object value0; - - String key1; - Object value1; - - String key2; - Object value2; - - String key3; - Object value3; - - String key4; - Object value4; - - String key5; - Object value5; - - String key6; - Object value6; - - String key7; - Object value7; - - // Expand constructor - public Dictionary8(Dictionary6 base, String key, Object value) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - - // Last key - this.key6 = key; - this.value6 = value; - } - - // Contract constructor - public Dictionary8(Dictionary11 base) { - this.key0 = base.key0; - this.value0 = base.value0; - - this.key1 = base.key1; - this.value1 = base.value1; - - this.key2 = base.key2; - this.value2 = base.value2; - - this.key3 = base.key3; - this.value3 = base.value3; - - this.key4 = base.key4; - this.value4 = base.value4; - - this.key5 = base.key5; - this.value5 = base.value5; - - this.key6 = base.key6; - this.value6 = base.value6; - - this.key7 = base.key7; - this.value7 = base.value7; - } - - // Copy constructor - public Dictionary8(Dictionary8 base) { + public static final int CAPACITY = 8; + + String key0; + Object value0; + + String key1; + Object value1; + + String key2; + Object value2; + + String key3; + Object value3; + + String key4; + Object value4; + + String key5; + Object value5; + + String key6; + Object value6; + + String key7; + Object value7; + + // Expand constructor + public Dictionary8(Dictionary6 base, String key, Object value) { this.key0 = base.key0; this.value0 = base.value0; - + this.key1 = base.key1; this.value1 = base.value1; - + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + + // Last key + this.key6 = key; + this.value6 = value; + } + + // Contract constructor + public Dictionary8(Dictionary11 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + + this.key2 = base.key2; + this.value2 = base.value2; + + this.key3 = base.key3; + this.value3 = base.value3; + + this.key4 = base.key4; + this.value4 = base.value4; + + this.key5 = base.key5; + this.value5 = base.value5; + + this.key6 = base.key6; + this.value6 = base.value6; + + this.key7 = base.key7; + this.value7 = base.value7; + } + + // Copy constructor + public Dictionary8(Dictionary8 base) { + this.key0 = base.key0; + this.value0 = base.value0; + + this.key1 = base.key1; + this.value1 = base.value1; + this.key2 = base.key2; this.value2 = base.value2; @@ -132,89 +132,89 @@ public Dictionary8(String[] keys, Object[] values) { this.key7 = lookupKey(keys, 7); this.value7 = lookupValue(values, 7); } - - @Override - String[] keys() { - return new String[] {key0, key1, key2, key3, key4, key5, key6, key7}; - } - - @Override - Object[] values() { - return new Object[] {value0, value1, value2, value3, value4, value5, value6, value7}; - } - - @Override - void write(int index, String key, Object value) { - if (index < 4) { - switch (index) { - case 0: - key0 = key; - value0 = value; - break; - - case 1: - key1 = key; - value1 = value; - break; - - case 2: - key2 = key; - value2 = value; - break; - - case 3: - key3 = key; - value3 = value; - break; - - default: - throw new RuntimeException("Bug in code"); - } - } else { - switch (index) { - case 4: - key4 = key; - value4 = value; - break; - - case 5: - key5 = key; - value5 = value; - break; - - case 6: - key6 = key; - value6 = value; - break; - - case 7: - key7 = key; - value7 = value; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); - } - } - } - - @Override - Dictionary expand(String key, Object value) { - return new Dictionary11(this, key, value); - } - - @Override - int contractThreshold() { - return Dictionary6.CAPACITY; - } - - @Override - Dictionary contract() { - return new Dictionary6(this); - } - - @Override - public Dictionary copyOf() { + + @Override + String[] keys() { + return new String[] {key0, key1, key2, key3, key4, key5, key6, key7}; + } + + @Override + Object[] values() { + return new Object[] {value0, value1, value2, value3, value4, value5, value6, value7}; + } + + @Override + void write(int index, String key, Object value) { + if (index < 4) { + switch (index) { + case 0: + key0 = key; + value0 = value; + break; + + case 1: + key1 = key; + value1 = value; + break; + + case 2: + key2 = key; + value2 = value; + break; + + case 3: + key3 = key; + value3 = value; + break; + + default: + throw new RuntimeException("Bug in code"); + } + } else { + switch (index) { + case 4: + key4 = key; + value4 = value; + break; + + case 5: + key5 = key; + value5 = value; + break; + + case 6: + key6 = key; + value6 = value; + break; + + case 7: + key7 = key; + value7 = value; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); + } + } + } + + @Override + Dictionary expand(String key, Object value) { + return new Dictionary11(this, key, value); + } + + @Override + int contractThreshold() { + return Dictionary6.CAPACITY; + } + + @Override + Dictionary contract() { + return new Dictionary6(this); + } + + @Override + public Dictionary copyOf() { return new Dictionary8(this); } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryFactory.java b/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryFactory.java index 95113c2..acfcc43 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryFactory.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryFactory.java @@ -18,9 +18,9 @@ public static Dictionary fromMap(Map properties) { values[counter] = entry.getValue(); counter++; } - - //assert counter == size; - + + // assert counter == size; + if (size == 0) { return null; } else if (size <= 1) { diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryMax.java b/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryMax.java index 92355d9..81e5d67 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryMax.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryMax.java @@ -3,26 +3,26 @@ import java.util.Arrays; public class DictionaryMax extends PrimitiveDictionary implements Dictionary { - int capacity; - String[] keys; - Object[] values; - - // Expand constructor - public DictionaryMax(Dictionary16 base, String key, Object value) { - this.capacity = 24; - keys = Arrays.copyOf(base.keys(), capacity); - values = Arrays.copyOf(base.values(), capacity); - - keys[16] = key; - values[16] = value; - } - - // Copy constructor - public DictionaryMax(DictionaryMax base) { - this.capacity = base.capacity; - keys = Arrays.copyOf(base.keys(), capacity); - values = Arrays.copyOf(base.values(), capacity); - } + int capacity; + String[] keys; + Object[] values; + + // Expand constructor + public DictionaryMax(Dictionary16 base, String key, Object value) { + this.capacity = 24; + keys = Arrays.copyOf(base.keys(), capacity); + values = Arrays.copyOf(base.values(), capacity); + + keys[16] = key; + values[16] = value; + } + + // Copy constructor + public DictionaryMax(DictionaryMax base) { + this.capacity = base.capacity; + keys = Arrays.copyOf(base.keys(), capacity); + values = Arrays.copyOf(base.values(), capacity); + } // FromMap constructor public DictionaryMax(String[] keys, Object[] values) { @@ -31,56 +31,56 @@ public DictionaryMax(String[] keys, Object[] values) { this.keys = Arrays.copyOf(keys, capacity); this.values = Arrays.copyOf(values, capacity); } - - @Override - String[] keys() { - return keys; - } - - @Override - Object[] values() { - return values; - } - - @Override - void write(int index, String key, Object value) { - keys[index] = key; - values[index] = value; - } - - @Override - Dictionary expand(String key, Object value) { - int newCapacity = capacity + (capacity / 2); - keys = Arrays.copyOf(keys, newCapacity); - values = Arrays.copyOf(values, newCapacity); - - keys[capacity] = key; - values[capacity] = value; - - this.capacity = newCapacity; - - return this; - } - - @Override - int contractThreshold() { - return capacity / 2; - } - - @Override - Dictionary contract() { - if (capacity < 14) { - // Move to Dictionary16 - return new Dictionary16(this); - } else { - int newCapacity = capacity * 3 / 4; - keys = Arrays.copyOf(keys, newCapacity); - values = Arrays.copyOf(values, newCapacity); - this.capacity = newCapacity; - - return this; - } - } + + @Override + String[] keys() { + return keys; + } + + @Override + Object[] values() { + return values; + } + + @Override + void write(int index, String key, Object value) { + keys[index] = key; + values[index] = value; + } + + @Override + Dictionary expand(String key, Object value) { + int newCapacity = capacity + (capacity / 2); + keys = Arrays.copyOf(keys, newCapacity); + values = Arrays.copyOf(values, newCapacity); + + keys[capacity] = key; + values[capacity] = value; + + this.capacity = newCapacity; + + return this; + } + + @Override + int contractThreshold() { + return capacity / 2; + } + + @Override + Dictionary contract() { + if (capacity < 14) { + // Move to Dictionary16 + return new Dictionary16(this); + } else { + int newCapacity = capacity * 3 / 4; + keys = Arrays.copyOf(keys, newCapacity); + values = Arrays.copyOf(values, newCapacity); + this.capacity = newCapacity; + + return this; + } + } @Override public Dictionary copyOf() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/dict/PrimitiveDictionary.java b/src/main/java/com/lambdazen/bitsy/ads/dict/PrimitiveDictionary.java index aa961d2..732d01b 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/dict/PrimitiveDictionary.java +++ b/src/main/java/com/lambdazen/bitsy/ads/dict/PrimitiveDictionary.java @@ -1,180 +1,184 @@ package com.lambdazen.bitsy.ads.dict; -import java.util.Arrays; - import com.lambdazen.bitsy.store.IStringCanonicalizer; +import java.util.Arrays; public abstract class PrimitiveDictionary implements Dictionary { - public PrimitiveDictionary() { - // Nothing to do - } - - abstract String[] keys(); - abstract Object[] values(); - abstract void write(int index, String key, Object value); - abstract Dictionary expand(String key, Object value); - abstract int contractThreshold(); - abstract Dictionary contract(); - - public abstract Dictionary copyOf(); - - public int size() { - String[] keys = keys(); - - int i; - for (i=0; i < keys.length; i++) { - if (keys[i] == null) { - break; - } - } - - return i; - } - - public String[] getPropertyKeys() { - String[] keys = keys(); - - int i; - for (i=0; i < keys.length; i++) { - if (keys[i] == null) { - break; - } - } - - return Arrays.copyOf(keys, i); - } - - @Override - public Object getProperty(String key) { - String[] keys = keys(); - Object[] values = values(); - - for (int i=0; i < keys.length; i++) { - String curKey = keys[i]; - - if (curKey == null) { - // End of keys - return null; - } else if (curKey.equals(key)) { - return values[i]; - } - } - - return null; - } - - @Override - public Dictionary setProperty(String key, Object value) { - String[] keys = keys(); - Object[] values = values(); - - boolean overwroteValue = false; - int i; - for (i=0; i < keys.length; i++) { - String curKey = keys[i]; - - if (curKey == null) { - // End of keys - break; - } else if (keys[i].equals(key)) { - values[i] = value; - write(i, keys[i], value); - overwroteValue = true; - } - } - - if (overwroteValue) { - // Stick with this - return this; - } else { - if (i == keys.length) { - // Reached end, need to move up - return expand(key, value); - } else { - // Not yet at the end - write(i, key, value); - - return this; - } - } - } - - @Override - public void canonicalizeKeys(IStringCanonicalizer canonicalizer) { - String[] keys = keys(); - Object[] values = null; - - int i = 0; - for (i=0; i < keys.length; i++) { + public PrimitiveDictionary() { + // Nothing to do + } + + abstract String[] keys(); + + abstract Object[] values(); + + abstract void write(int index, String key, Object value); + + abstract Dictionary expand(String key, Object value); + + abstract int contractThreshold(); + + abstract Dictionary contract(); + + public abstract Dictionary copyOf(); + + public int size() { + String[] keys = keys(); + + int i; + for (i = 0; i < keys.length; i++) { + if (keys[i] == null) { + break; + } + } + + return i; + } + + public String[] getPropertyKeys() { + String[] keys = keys(); + + int i; + for (i = 0; i < keys.length; i++) { + if (keys[i] == null) { + break; + } + } + + return Arrays.copyOf(keys, i); + } + + @Override + public Object getProperty(String key) { + String[] keys = keys(); + Object[] values = values(); + + for (int i = 0; i < keys.length; i++) { + String curKey = keys[i]; + + if (curKey == null) { + // End of keys + return null; + } else if (curKey.equals(key)) { + return values[i]; + } + } + + return null; + } + + @Override + public Dictionary setProperty(String key, Object value) { + String[] keys = keys(); + Object[] values = values(); + + boolean overwroteValue = false; + int i; + for (i = 0; i < keys.length; i++) { + String curKey = keys[i]; + + if (curKey == null) { + // End of keys + break; + } else if (keys[i].equals(key)) { + values[i] = value; + write(i, keys[i], value); + overwroteValue = true; + } + } + + if (overwroteValue) { + // Stick with this + return this; + } else { + if (i == keys.length) { + // Reached end, need to move up + return expand(key, value); + } else { + // Not yet at the end + write(i, key, value); + + return this; + } + } + } + + @Override + public void canonicalizeKeys(IStringCanonicalizer canonicalizer) { + String[] keys = keys(); + Object[] values = null; + + int i = 0; + for (i = 0; i < keys.length; i++) { String origKey = keys[i]; String newKey = canonicalizer.canonicalize(origKey); - // Avoid step if already canonical - if (newKey != origKey) { - if (values == null) { - // Don't generate values unless required - values = values(); - } - - write(i, newKey, values[i]); - } - - i++; - } - } - - @Override - public Dictionary removeProperty(String key) { - String[] keys = keys(); - Object[] values = values(); - - int overwritePos = -1; - int i; - for (i=0; i < keys.length; i++) { - String curKey = keys[i]; - - if (curKey == null) { - // End of keys - break; - } else if (keys[i].equals(key)) { - overwritePos = i; - } - } - - if (overwritePos == -1) { - // Couldn't find key - return this; - } else { - // Overwrite from end to here - int lastIdx = i - 1; - if (overwritePos != lastIdx) { - write(overwritePos, keys[lastIdx], values[lastIdx]); - } - write(lastIdx, null, null); - - if (lastIdx <= contractThreshold()) { - // The new size is at or below the contract threshold - return contract(); - } else { - return this; - } - } - } - - protected String lookupKey(String[] keys, int i) { - return (i < keys.length) ? keys[i] : null; - } - - protected Object lookupValue(Object[] values, int i) { - return (i < values.length) ? values[i] : null; - } - - public String toString() { - StringBuffer ans = new StringBuffer("PrimitiveDictionary(size = " + size()); - for (String key : getPropertyKeys()) { - ans.append(", " + key + ": " + getProperty(key)); - } - ans.append(")"); - return ans.toString(); - } + // Avoid step if already canonical + if (newKey != origKey) { + if (values == null) { + // Don't generate values unless required + values = values(); + } + + write(i, newKey, values[i]); + } + + i++; + } + } + + @Override + public Dictionary removeProperty(String key) { + String[] keys = keys(); + Object[] values = values(); + + int overwritePos = -1; + int i; + for (i = 0; i < keys.length; i++) { + String curKey = keys[i]; + + if (curKey == null) { + // End of keys + break; + } else if (keys[i].equals(key)) { + overwritePos = i; + } + } + + if (overwritePos == -1) { + // Couldn't find key + return this; + } else { + // Overwrite from end to here + int lastIdx = i - 1; + if (overwritePos != lastIdx) { + write(overwritePos, keys[lastIdx], values[lastIdx]); + } + write(lastIdx, null, null); + + if (lastIdx <= contractThreshold()) { + // The new size is at or below the contract threshold + return contract(); + } else { + return this; + } + } + } + + protected String lookupKey(String[] keys, int i) { + return (i < keys.length) ? keys[i] : null; + } + + protected Object lookupValue(Object[] values, int i) { + return (i < values.length) ? values[i] : null; + } + + public String toString() { + StringBuilder ans = new StringBuilder("PrimitiveDictionary(size = " + size()); + for (String key : getPropertyKeys()) { + ans.append(", " + key + ": " + getProperty(key)); + } + ans.append(")"); + return ans.toString(); + } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/ArraySet.java b/src/main/java/com/lambdazen/bitsy/ads/set/ArraySet.java index aeae559..338790f 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/ArraySet.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/ArraySet.java @@ -10,7 +10,7 @@ */ public class ArraySet implements Set { int size; - Object[] elements; + Object[] elements; public ArraySet(Object[] elements) { this(elements, elements.length); @@ -20,8 +20,8 @@ protected ArraySet(Object[] elements, int size) { this.size = size; this.elements = new Object[size + size / 2]; - for (int i=0; i < size; i++) { - this.elements[i] = (T)elements[i]; + for (int i = 0; i < size; i++) { + this.elements[i] = (T) elements[i]; } } @@ -38,7 +38,7 @@ public Object[] getElements() { @Override public Object removeElement(T elem) { // Go over elements and remove the one - for (int i=0; i < size; i++) { + for (int i = 0; i < size; i++) { if (elem.equals(elements[i])) { if (i < size - 1) { elements[i] = elements[size - 1]; @@ -46,31 +46,31 @@ public Object removeElement(T elem) { this.size--; elements[size] = null; - + break; } } - + if (size < 16) { return new Set24(getElements()); } else if (size < elements.length / 2) { // Using the constructor that cuts the size -- to avoid two array creations return new ArraySet(elements, size); } else { - // Use the same object + // Use the same object return this; } } @Override public Set addElement(T elem) { - for (int i=0; i < size; i++) { + for (int i = 0; i < size; i++) { if (elem.equals(elements[i])) { // Nothing to do return this; } } - + if (size < elements.length) { elements[size] = elem; this.size++; diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMax.java b/src/main/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMax.java index b797cd7..7a4625f 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMax.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMax.java @@ -8,14 +8,14 @@ * supports a get that takes the classifier and returns the matches. This class * is NOT thread-safe, but can support multiple readers as long as there is only * one writer. - * + * * This class is used for two purposes. The first is to store adjacency lists by * label. The classifier picks up the label from the Edge. The second purpose is * to provide SetMax with a thread-safe HashSet implementation. */ public class CompactMultiSetMax { public static final int MIN_TO_RESIZE = 8; - + int occupied = 0; boolean safe; Object[] elements; @@ -25,16 +25,16 @@ public CompactMultiSetMax(int initSize, boolean safe) { this.occupied = 0; this.safe = safe; } - + public int getOccupiedCells() { return this.occupied; } - + public CompactMultiSetMax add(T obj, ClassifierGetter c) { Object classifier = c.getClassifier(obj); addElementNoRehash(classifier.hashCode(), obj); - + int len = elements.length; if (occupied >= len - (len / 4)) { // 0.75 load factor return rehash(len * 2, c); @@ -47,7 +47,7 @@ protected void addElementNoRehash(int hashCode, T obj) { int index = (hashCode & 0x7FFFFFFF) % elements.length; if (elements[index] == null) { - occupied++; + occupied++; } if (safe) { @@ -59,14 +59,14 @@ protected void addElementNoRehash(int hashCode, T obj) { private CompactMultiSetMax rehash(int newLength, ClassifierGetter c) { CompactMultiSetMax ans = new CompactMultiSetMax(newLength, safe); // use the same safe boolean - + for (Object elem : elements) { for (Object item : CompactSet.getElements(elem)) { - Object classifier = c.getClassifier((T)item); - ans.addElementNoRehash(classifier.hashCode(), (T)item); + Object classifier = c.getClassifier((T) item); + ans.addElementNoRehash(classifier.hashCode(), (T) item); } } - + return ans; } @@ -86,9 +86,9 @@ public CompactMultiSetMax remove(T obj, ClassifierGetter c) { protected void removeElementNoHash(int hashCode, T obj) { int index = (hashCode & 0x7FFFFFFF) % elements.length; - Object oldVal = elements[index]; + Object oldVal = elements[index]; if (oldVal == null) { - return; + return; } else { Object newVal = CompactSet.remove(oldVal, obj); elements[index] = newVal; @@ -108,17 +108,17 @@ public Object[] getSuperSetWithClassifier(C key) { return getAllElements(); } else { int index = (key.hashCode() & 0x7FFFFFFF) % elements.length; - + return CompactSet.getElements(elements[index]); } } - + public Object[] getAllElements() { List ans = new ArrayList(); - for (int i=0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { Object elem = elements[i]; - + for (Object item : CompactSet.getElements(elem)) { if (item != null) { // This check is needed because item could be null when @@ -130,14 +130,14 @@ public Object[] getAllElements() { } } } - + return ans.toArray(); } // This method goes over the elements to see if this compact set can be fit inside a Set24 public boolean sizeBiggerThan24() { int currentSize = 0; - for (int i=0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { Object elem = elements[i]; if (elem == null) { // Empty cell @@ -149,14 +149,14 @@ public boolean sizeBiggerThan24() { // Don't reorg till the SetMax reduces to Set24 return true; } else { - currentSize += CompactSet.size(elem); + currentSize += CompactSet.size(elem); } - + if (currentSize > 24) { return true; } } - + return false; } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/CompactSet.java b/src/main/java/com/lambdazen/bitsy/ads/set/CompactSet.java index 69a6e37..6c3eb9a 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/CompactSet.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/CompactSet.java @@ -5,7 +5,7 @@ public static int size(Object set) { if (set == null) { return 0; } else if (set instanceof Set) { - return ((Set)set).size(); + return ((Set) set).size(); } else { return 1; } @@ -15,7 +15,7 @@ public static Object[] getElements(Object set) { if (set == null) { return new Object[0]; } else if (set instanceof Set) { - return ((Set)set).getElements(); + return ((Set) set).getElements(); } else { return new Object[] {set}; } @@ -25,7 +25,7 @@ public static Object add(Object set, T elem) { if (set == null) { return elem; } else if (set instanceof Set) { - return ((Set)set).addElement(elem); + return ((Set) set).addElement(elem); } else { if (set.equals(elem)) { return set; @@ -40,15 +40,15 @@ public static Object addSafe(Object set, T elem) { // Move to ArraySet instead of SetMax to avoid cyclic dependency from CompactMultiSetMax and SetMax set = new ArraySet(CompactSet.getElements(set)); } - + return CompactSet.add(set, elem); } - + public static Object remove(Object set, T elem) { if (set == null) { return null; } else if (set instanceof Set) { - return ((Set)set).removeElement(elem); + return ((Set) set).removeElement(elem); } else { if ((set == elem) || (set.equals(elem))) { return null; diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/PrimitiveSet.java b/src/main/java/com/lambdazen/bitsy/ads/set/PrimitiveSet.java index e742f1d..d79aa97 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/PrimitiveSet.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/PrimitiveSet.java @@ -8,34 +8,37 @@ public PrimitiveSet() { } abstract Object[] elements(); + abstract void write(int index, T elem); abstract Set expand(T elem); + abstract int contractThreshold(); + abstract Object contract(); public int size() { Object[] elems = elements(); - + return size(elems); } - + private int size(Object[] elems) { int i; - for (i=0; i < elems.length; i++) { + for (i = 0; i < elems.length; i++) { if (elems[i] == null) { break; } } - + return i; } - + public Object[] getElements() { Object[] elems = elements(); int i; - for (i=0; i < elems.length; i++) { + for (i = 0; i < elems.length; i++) { if (elems[i] == null) { break; } @@ -47,12 +50,12 @@ public Object[] getElements() { public Set addElement(T elem) { Object[] elems = elements(); int size = elems.length; - + boolean duplicate = false; int i; - for (i=0; i < size; i++) { - T curElem = (T)elems[i]; - + for (i = 0; i < size; i++) { + T curElem = (T) elems[i]; + if (curElem == null) { // End of keys break; @@ -60,7 +63,7 @@ public Set addElement(T elem) { duplicate = true; } } - + if (duplicate) { // Stick with this return this; @@ -71,7 +74,7 @@ public Set addElement(T elem) { } else { // Not yet at the end write(i, elem); - + return this; } } @@ -84,9 +87,9 @@ public Object removeElement(T elem) { int overwritePos = -1; int i; - for (i=0; i < size; i++) { + for (i = 0; i < size; i++) { Object curElem = elems[i]; - + if (curElem == null) { // End of keys break; @@ -94,7 +97,7 @@ public Object removeElement(T elem) { overwritePos = i; } } - + if (overwritePos == -1) { // Couldn't find key return this; @@ -102,7 +105,7 @@ public Object removeElement(T elem) { // Overwrite from end to here int lastIdx = i - 1; if (overwritePos != lastIdx) { - write(overwritePos, (T)elems[lastIdx]); + write(overwritePos, (T) elems[lastIdx]); } write(lastIdx, null); diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set.java index 77423cf..a90d676 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set.java @@ -1,6 +1,6 @@ package com.lambdazen.bitsy.ads.set; -/** A bag keeps an unordered, unstable collection of elements */ +/** A bag keeps an unordered, unstable collection of elements */ public interface Set { public int size(); diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set12.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set12.java index 5817e7e..828b966 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set12.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set12.java @@ -2,7 +2,7 @@ public class Set12 extends PrimitiveSet implements Set { T elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11; - + public Set12(Set8 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -38,66 +38,66 @@ public Object[] elements() { protected void write(int index, T elem) { if (index < 4) { switch (index) { - case 0: - this.elem0 = elem; - break; - - case 1: - this.elem1 = elem; - break; - - case 2: - this.elem2 = elem; - break; - - case 3: - this.elem3 = elem; - break; - - default: - throw new RuntimeException("Bug in code"); + case 0: + this.elem0 = elem; + break; + + case 1: + this.elem1 = elem; + break; + + case 2: + this.elem2 = elem; + break; + + case 3: + this.elem3 = elem; + break; + + default: + throw new RuntimeException("Bug in code"); } } else if (index < 8) { - switch (index) { - case 4: - this.elem4 = elem; - break; - - case 5: - this.elem5 = elem; - break; - - case 6: - this.elem6 = elem; - break; - - case 7: - this.elem7 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 4: + this.elem4 = elem; + break; + + case 5: + this.elem5 = elem; + break; + + case 6: + this.elem6 = elem; + break; + + case 7: + this.elem7 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } else { - switch (index) { - case 8: - this.elem8 = elem; - break; - - case 9: - this.elem9 = elem; - break; - - case 10: - this.elem10 = elem; - break; - - case 11: - this.elem11 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 8: + this.elem8 = elem; + break; + + case 9: + this.elem9 = elem; + break; + + case 10: + this.elem10 = elem; + break; + + case 11: + this.elem11 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set2.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set2.java index f621cbb..edb32cc 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set2.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set2.java @@ -2,7 +2,7 @@ public class Set2 extends PrimitiveSet implements Set { T elem0, elem1; - + public Set2(T elem0, T elem1) { this.elem0 = elem0; this.elem1 = elem1; @@ -20,16 +20,16 @@ public Object[] elements() { protected void write(int index, T elem) { switch (index) { - case 0: - elem0 = elem; - break; - - case 1: - elem1 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + case 0: + elem0 = elem; + break; + + case 1: + elem1 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } @@ -37,7 +37,6 @@ protected void write(int index, T elem) { Set expand(T elem) { return new Set3(this, elem); } - @Override int contractThreshold() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set24.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set24.java index 045b12a..ae0ee83 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set24.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set24.java @@ -1,9 +1,31 @@ package com.lambdazen.bitsy.ads.set; public class Set24 extends PrimitiveSet implements Set { - T elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11, - elem12, elem13, elem14, elem15, elem16, elem17, elem18, elem19, elem20, elem21, elem22, elem23; - + T elem0, + elem1, + elem2, + elem3, + elem4, + elem5, + elem6, + elem7, + elem8, + elem9, + elem10, + elem11, + elem12, + elem13, + elem14, + elem15, + elem16, + elem17, + elem18, + elem19, + elem20, + elem21, + elem22, + elem23; + public Set24(Set12 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -48,143 +70,146 @@ public Set24(Object[] elements) { } private T lookup(Object[] arr, int index) { - return (index < arr.length) ? (T)arr[index] : null; + return (index < arr.length) ? (T) arr[index] : null; } + @Override public Object[] elements() { - return new Object[] {elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11, - elem12, elem13, elem14, elem15, elem16, elem17, elem18, elem19, elem20, elem21, elem22, elem23}; + return new Object[] { + elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11, elem12, elem13, + elem14, elem15, elem16, elem17, elem18, elem19, elem20, elem21, elem22, elem23 + }; } protected void write(int index, T elem) { if (index < 12) { if (index < 4) { switch (index) { - case 0: - this.elem0 = elem; - break; - - case 1: - this.elem1 = elem; - break; - - case 2: - this.elem2 = elem; - break; - - case 3: - this.elem3 = elem; - break; - - default: - throw new RuntimeException("Bug in code"); + case 0: + this.elem0 = elem; + break; + + case 1: + this.elem1 = elem; + break; + + case 2: + this.elem2 = elem; + break; + + case 3: + this.elem3 = elem; + break; + + default: + throw new RuntimeException("Bug in code"); } } else if (index < 8) { - switch (index) { - case 4: - this.elem4 = elem; - break; - - case 5: - this.elem5 = elem; - break; - - case 6: - this.elem6 = elem; - break; - - case 7: - this.elem7 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 4: + this.elem4 = elem; + break; + + case 5: + this.elem5 = elem; + break; + + case 6: + this.elem6 = elem; + break; + + case 7: + this.elem7 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } else { - switch (index) { - case 8: - this.elem8 = elem; - break; - - case 9: - this.elem9 = elem; - break; - - case 10: - this.elem10 = elem; - break; - - case 11: - this.elem11 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 8: + this.elem8 = elem; + break; + + case 9: + this.elem9 = elem; + break; + + case 10: + this.elem10 = elem; + break; + + case 11: + this.elem11 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } } else { if (index < 16) { switch (index) { - case 12: - this.elem12 = elem; - break; - - case 13: - this.elem13 = elem; - break; - - case 14: - this.elem14 = elem; - break; - - case 15: - this.elem15 = elem; - break; - - default: - throw new RuntimeException("Bug in code"); + case 12: + this.elem12 = elem; + break; + + case 13: + this.elem13 = elem; + break; + + case 14: + this.elem14 = elem; + break; + + case 15: + this.elem15 = elem; + break; + + default: + throw new RuntimeException("Bug in code"); } } else if (index < 20) { - switch (index) { - case 16: - this.elem16 = elem; - break; - - case 17: - this.elem17 = elem; - break; - - case 18: - this.elem18 = elem; - break; - - case 19: - this.elem19 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 16: + this.elem16 = elem; + break; + + case 17: + this.elem17 = elem; + break; + + case 18: + this.elem18 = elem; + break; + + case 19: + this.elem19 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } else { - switch (index) { - case 20: - this.elem20 = elem; - break; - - case 21: - this.elem21 = elem; - break; - - case 22: - this.elem22 = elem; - break; - - case 23: - this.elem23 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 20: + this.elem20 = elem; + break; + + case 21: + this.elem21 = elem; + break; + + case 22: + this.elem22 = elem; + break; + + case 23: + this.elem23 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } } diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set3.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set3.java index 68ebaee..55655d7 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set3.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set3.java @@ -2,7 +2,7 @@ public class Set3 extends PrimitiveSet implements Set { T elem0, elem1, elem2; - + public Set3(Set2 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -22,20 +22,20 @@ public Object[] elements() { protected void write(int index, T elem) { switch (index) { - case 0: - elem0 = elem; - break; + case 0: + elem0 = elem; + break; - case 1: - elem1 = elem; - break; + case 1: + elem1 = elem; + break; - case 2: - elem2 = elem; - break; + case 2: + elem2 = elem; + break; - default: - throw new IllegalArgumentException("Invalid index " + index); + default: + throw new IllegalArgumentException("Invalid index " + index); } } @@ -43,7 +43,6 @@ protected void write(int index, T elem) { Set expand(T elem) { return new Set4(this, elem); } - @Override int contractThreshold() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set4.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set4.java index 2f06517..c6e2cc1 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set4.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set4.java @@ -2,7 +2,7 @@ public class Set4 extends PrimitiveSet implements Set { T elem0, elem1, elem2, elem3; - + public Set4(Set3 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -24,24 +24,24 @@ public Object[] elements() { protected void write(int index, T elem) { switch (index) { - case 0: - elem0 = elem; - break; + case 0: + elem0 = elem; + break; - case 1: - elem1 = elem; - break; + case 1: + elem1 = elem; + break; - case 2: - elem2 = elem; - break; + case 2: + elem2 = elem; + break; - case 3: - elem3 = elem; - break; + case 3: + elem3 = elem; + break; - default: - throw new IllegalArgumentException("Invalid index " + index); + default: + throw new IllegalArgumentException("Invalid index " + index); } } @@ -49,7 +49,6 @@ protected void write(int index, T elem) { Set expand(T elem) { return new Set6(this, elem); } - @Override int contractThreshold() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set6.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set6.java index bdf3f7d..566ff36 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set6.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set6.java @@ -2,7 +2,7 @@ public class Set6 extends PrimitiveSet implements Set { T elem0, elem1, elem2, elem3, elem4, elem5; - + public Set6(Set4 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -27,32 +27,32 @@ public Object[] elements() { protected void write(int index, T elem) { switch (index) { - case 0: - elem0 = elem; - break; + case 0: + elem0 = elem; + break; - case 1: - elem1 = elem; - break; + case 1: + elem1 = elem; + break; - case 2: - elem2 = elem; - break; + case 2: + elem2 = elem; + break; - case 3: - elem3 = elem; - break; + case 3: + elem3 = elem; + break; - case 4: - elem4 = elem; - break; + case 4: + elem4 = elem; + break; - case 5: - elem5 = elem; - break; + case 5: + elem5 = elem; + break; - default: - throw new IllegalArgumentException("Invalid index " + index); + default: + throw new IllegalArgumentException("Invalid index " + index); } } @@ -60,7 +60,6 @@ protected void write(int index, T elem) { Set expand(T elem) { return new Set8(this, elem); } - @Override int contractThreshold() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/Set8.java b/src/main/java/com/lambdazen/bitsy/ads/set/Set8.java index 4f52c37..b0ee832 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/Set8.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/Set8.java @@ -2,7 +2,7 @@ public class Set8 extends PrimitiveSet implements Set { T elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7; - + public Set8(Set6 oldSet, T elem) { this.elem0 = oldSet.elem0; this.elem1 = oldSet.elem1; @@ -32,45 +32,45 @@ public Object[] elements() { protected void write(int index, T elem) { if (index < 4) { switch (index) { - case 0: - this.elem0 = elem; - break; - - case 1: - this.elem1 = elem; - break; - - case 2: - this.elem2 = elem; - break; - - case 3: - this.elem3 = elem; - break; - - default: - throw new RuntimeException("Bug in code"); + case 0: + this.elem0 = elem; + break; + + case 1: + this.elem1 = elem; + break; + + case 2: + this.elem2 = elem; + break; + + case 3: + this.elem3 = elem; + break; + + default: + throw new RuntimeException("Bug in code"); } } else { - switch (index) { - case 4: - this.elem4 = elem; - break; - - case 5: - this.elem5 = elem; - break; - - case 6: - this.elem6 = elem; - break; - - case 7: - this.elem7 = elem; - break; - - default: - throw new IllegalArgumentException("Invalid index " + index); + switch (index) { + case 4: + this.elem4 = elem; + break; + + case 5: + this.elem5 = elem; + break; + + case 6: + this.elem6 = elem; + break; + + case 7: + this.elem7 = elem; + break; + + default: + throw new IllegalArgumentException("Invalid index " + index); } } } @@ -79,7 +79,6 @@ protected void write(int index, T elem) { Set expand(T elem) { return new Set12(this, elem); } - @Override int contractThreshold() { diff --git a/src/main/java/com/lambdazen/bitsy/ads/set/SetMax.java b/src/main/java/com/lambdazen/bitsy/ads/set/SetMax.java index 384681a..f1723b0 100644 --- a/src/main/java/com/lambdazen/bitsy/ads/set/SetMax.java +++ b/src/main/java/com/lambdazen/bitsy/ads/set/SetMax.java @@ -2,7 +2,7 @@ public class SetMax implements Set { private static final long serialVersionUID = 129583038274146507L; - + private static final ClassifierGetter identityClassifer = new ClassifierGetter() { @Override public Object getClassifier(Object obj) { @@ -17,14 +17,14 @@ public SetMax(Set24 oldSet, Object elem) { // When using a compact multi-set inside a set, it is better to use // safe-mode to avoid a cyclic dependency when all hash-codes are same hashSet = new CompactMultiSetMax(32, true); - + Object[] elems = oldSet.getElements(); - for (int i=0; i < elems.length; i++) { - T curElem = (T)elems[i]; + for (int i = 0; i < elems.length; i++) { + T curElem = (T) elems[i]; hashSet.addElementNoRehash(curElem.hashCode(), curElem); } - T curElem = (T)elem; + T curElem = (T) elem; hashSet.addElementNoRehash(curElem.hashCode(), curElem); this.size = 1 + elems.length; diff --git a/src/main/java/com/lambdazen/bitsy/gremlin/BitsyGraphStep.java b/src/main/java/com/lambdazen/bitsy/gremlin/BitsyGraphStep.java index a541b89..1176253 100644 --- a/src/main/java/com/lambdazen/bitsy/gremlin/BitsyGraphStep.java +++ b/src/main/java/com/lambdazen/bitsy/gremlin/BitsyGraphStep.java @@ -1,5 +1,13 @@ package com.lambdazen.bitsy.gremlin; +import com.lambdazen.bitsy.BitsyGraph; +import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; import org.apache.tinkerpop.gremlin.process.traversal.Compare; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder; @@ -14,33 +22,27 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import com.lambdazen.bitsy.BitsyGraph; -import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - // Bitsy graph step based Tinkerpop's Neo4j implementation public final class BitsyGraphStep extends GraphStep implements HasContainerHolder { private final List hasContainers = new ArrayList<>(); public BitsyGraphStep(final GraphStep originalGraphStep) { - super(originalGraphStep.getTraversal(), originalGraphStep.getReturnClass(), originalGraphStep.isStartStep(), originalGraphStep.getIds()); + super( + originalGraphStep.getTraversal(), + originalGraphStep.getReturnClass(), + originalGraphStep.isStartStep(), + originalGraphStep.getIds()); originalGraphStep.getLabels().forEach(this::addLabel); - this.setIteratorSupplier(() -> (Iterator) (Vertex.class.isAssignableFrom(this.returnClass) ? this.vertices() : this.edges())); + this.setIteratorSupplier( + () -> (Iterator) (Vertex.class.isAssignableFrom(this.returnClass) ? this.vertices() : this.edges())); } private BitsyGraph getBitsyGraph() { Graph baseGraph = this.getTraversal().getGraph().get(); final BitsyGraph graph; if (baseGraph instanceof BitsyAutoReloadingGraph) { - return ((BitsyAutoReloadingGraph)baseGraph).getBaseGraph(); + return ((BitsyAutoReloadingGraph) baseGraph).getBaseGraph(); } else { return (BitsyGraph) baseGraph; } @@ -50,20 +52,22 @@ private Iterator vertices() { return lookupVertices(getBitsyGraph(), this.hasContainers, this.ids); } - - private Iterator lookupVertices(final BitsyGraph graph, final List hasContainers, final Object... ids) { + private Iterator lookupVertices( + final BitsyGraph graph, final List hasContainers, final Object... ids) { // ids are present, filter on them first if (ids != null && ids.length > 0) return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers)); // Labels aren't indexed in Bitsy, only keys -- so do a full scan for (final HasContainer hasContainer : hasContainers) { - if (Compare.eq == hasContainer.getBiPredicate() && !Objects.equals(hasContainer.getKey(), T.label.getAccessor())) { + if (Compare.eq == hasContainer.getBiPredicate() + && !Objects.equals(hasContainer.getKey(), T.label.getAccessor())) { if (graph.getIndexedKeys(Vertex.class).contains(hasContainer.getKey())) { // Find a vertex by key/value return IteratorUtils.stream(graph.verticesByIndex(hasContainer.getKey(), hasContainer.getValue())) - .map(vertex -> (Vertex) vertex) - .filter(vertex -> HasContainer.testAll(vertex, hasContainers)).iterator(); + .map(vertex -> (Vertex) vertex) + .filter(vertex -> HasContainer.testAll(vertex, hasContainers)) + .iterator(); } } } @@ -71,23 +75,27 @@ private Iterator lookupVertices(final BitsyGraph graph, final List edges() { - //return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.ids), edge -> HasContainer.testAll(edge, this.hasContainers)); + // return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.ids), edge -> + // HasContainer.testAll(edge, this.hasContainers)); return lookupEdges(getBitsyGraph(), this.hasContainers, this.ids); } - private Iterator lookupEdges(final BitsyGraph graph, final List hasContainers, final Object... ids) { + private Iterator lookupEdges( + final BitsyGraph graph, final List hasContainers, final Object... ids) { // ids are present, filter on them first if (ids != null && ids.length > 0) return IteratorUtils.filter(graph.edges(ids), vertex -> HasContainer.testAll(vertex, hasContainers)); // Labels aren't indexed in Bitsy, only keys -- so do a full scan for (final HasContainer hasContainer : hasContainers) { - if (Compare.eq == hasContainer.getBiPredicate() && !Objects.equals(hasContainer.getKey(), T.label.getAccessor())) { + if (Compare.eq == hasContainer.getBiPredicate() + && !Objects.equals(hasContainer.getKey(), T.label.getAccessor())) { if (graph.getIndexedKeys(Vertex.class).contains(hasContainer.getKey())) { // Find a vertex by key/value return IteratorUtils.stream(graph.edgesByIndex(hasContainer.getKey(), hasContainer.getValue())) - .map(edge -> (Edge) edge) - .filter(edge -> HasContainer.testAll(edge, hasContainers)).iterator(); + .map(edge -> (Edge) edge) + .filter(edge -> HasContainer.testAll(edge, hasContainers)) + .iterator(); } } } @@ -95,32 +103,35 @@ private Iterator lookupEdges(final BitsyGraph graph, final List getHasContainers() { + public List getHasContainers() { return Collections.unmodifiableList(this.hasContainers); } @Override - public void addHasContainer(final HasContainer hasContainer) { + public void addHasContainer(final HasContainer hasContainer) { if (hasContainer.getPredicate() instanceof AndP) { for (final P predicate : ((AndP) hasContainer.getPredicate()).getPredicates()) { this.addHasContainer(new HasContainer(hasContainer.getKey(), predicate)); } - } else - this.hasContainers.add(hasContainer); + } else this.hasContainers.add(hasContainer); } @Override - public int hashCode() { + public int hashCode() { return super.hashCode() ^ this.hasContainers.hashCode(); } } diff --git a/src/main/java/com/lambdazen/bitsy/gremlin/BitsyTraversalStrategy.java b/src/main/java/com/lambdazen/bitsy/gremlin/BitsyTraversalStrategy.java index fc5130a..9824ea6 100644 --- a/src/main/java/com/lambdazen/bitsy/gremlin/BitsyTraversalStrategy.java +++ b/src/main/java/com/lambdazen/bitsy/gremlin/BitsyTraversalStrategy.java @@ -11,36 +11,35 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; -//Bitsy traversal strategy based Tinkerpop's Neo4j implementation -public class BitsyTraversalStrategy extends AbstractTraversalStrategy implements TraversalStrategy.ProviderOptimizationStrategy { - private static final long serialVersionUID = 6405194525894707932L; - private static final BitsyTraversalStrategy INSTANCE = new BitsyTraversalStrategy(); +// Bitsy traversal strategy based Tinkerpop's Neo4j implementation +public class BitsyTraversalStrategy extends AbstractTraversalStrategy + implements TraversalStrategy.ProviderOptimizationStrategy { + private static final long serialVersionUID = 6405194525894707932L; + private static final BitsyTraversalStrategy INSTANCE = new BitsyTraversalStrategy(); - private BitsyTraversalStrategy() { - } + private BitsyTraversalStrategy() {} - @Override - public void apply(final Traversal.Admin traversal) { - for (final GraphStep originalGraphStep : TraversalHelper.getStepsOfClass(GraphStep.class, traversal)) { - final BitsyGraphStep bitsyGraphStep = new BitsyGraphStep<>(originalGraphStep); - TraversalHelper.replaceStep(originalGraphStep, bitsyGraphStep, traversal); - Step currentStep = bitsyGraphStep.getNextStep(); - while (currentStep instanceof HasStep || currentStep instanceof NoOpBarrierStep) { - if (currentStep instanceof HasStep) { - for (final HasContainer hasContainer : ((HasContainerHolder) currentStep).getHasContainers()) { - if (!GraphStep.processHasContainerIds(bitsyGraphStep, hasContainer)) - bitsyGraphStep.addHasContainer(hasContainer); - } - TraversalHelper.copyLabels(currentStep, currentStep.getPreviousStep(), false); - traversal.removeStep(currentStep); - } - currentStep = currentStep.getNextStep(); - } - } - } - - public static BitsyTraversalStrategy instance() { - return INSTANCE; - } + @Override + public void apply(final Traversal.Admin traversal) { + for (final GraphStep originalGraphStep : TraversalHelper.getStepsOfClass(GraphStep.class, traversal)) { + final BitsyGraphStep bitsyGraphStep = new BitsyGraphStep<>(originalGraphStep); + TraversalHelper.replaceStep(originalGraphStep, bitsyGraphStep, traversal); + Step currentStep = bitsyGraphStep.getNextStep(); + while (currentStep instanceof HasStep || currentStep instanceof NoOpBarrierStep) { + if (currentStep instanceof HasStep) { + for (final HasContainer hasContainer : ((HasContainerHolder) currentStep).getHasContainers()) { + if (!GraphStep.processHasContainerIds(bitsyGraphStep, hasContainer)) + bitsyGraphStep.addHasContainer(hasContainer); + } + TraversalHelper.copyLabels(currentStep, currentStep.getPreviousStep(), false); + traversal.removeStep(currentStep); + } + currentStep = currentStep.getNextStep(); + } + } + } + public static BitsyTraversalStrategy instance() { + return INSTANCE; + } } diff --git a/src/main/java/com/lambdazen/bitsy/index/BitsyIndex.java b/src/main/java/com/lambdazen/bitsy/index/BitsyIndex.java index 5f13a80..9aecf7b 100644 --- a/src/main/java/com/lambdazen/bitsy/index/BitsyIndex.java +++ b/src/main/java/com/lambdazen/bitsy/index/BitsyIndex.java @@ -1,23 +1,22 @@ package com.lambdazen.bitsy.index; +import com.lambdazen.bitsy.ads.set.CompactSet; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.lambdazen.bitsy.ads.set.CompactSet; - public abstract class BitsyIndex { Map index; - + public BitsyIndex() { this.index = new ConcurrentHashMap(); } - + public abstract Object getValue(T bean); + public abstract T copy(T bean); public void load(Iterator initialContents) { @@ -26,7 +25,7 @@ public void load(Iterator initialContents) { add(elem); } } - + public List get(Object value) { Object idxValue = index.get(value); @@ -36,17 +35,17 @@ public List get(Object value) { Object[] objs = CompactSet.getElements(idxValue); List ans = new ArrayList(objs.length); int len = objs.length; - for (int i=0; i < len; i++) { + for (int i = 0; i < len; i++) { // Always check for nulls on getElements() because reads don't acquire locks if (objs[i] != null) { - ans.add(copy((T)objs[i])); + ans.add(copy((T) objs[i])); } } - + return ans; } } - + public void add(T bean) { Object value = getValue(bean); if (value == null) { @@ -62,7 +61,7 @@ public void add(T bean) { index.put(value, newSet); } } - + public void remove(T bean) { Object value = getValue(bean); if (value == null) { diff --git a/src/main/java/com/lambdazen/bitsy/index/BitsyIndexMap.java b/src/main/java/com/lambdazen/bitsy/index/BitsyIndexMap.java index d36a1e8..465867b 100644 --- a/src/main/java/com/lambdazen/bitsy/index/BitsyIndexMap.java +++ b/src/main/java/com/lambdazen/bitsy/index/BitsyIndexMap.java @@ -1,48 +1,50 @@ package com.lambdazen.bitsy.index; +import com.lambdazen.bitsy.BitsyErrorCodes; +import com.lambdazen.bitsy.BitsyException; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import com.lambdazen.bitsy.BitsyErrorCodes; -import com.lambdazen.bitsy.BitsyException; - public class BitsyIndexMap> { - // Read operations on IndexMap don't require locks. + // Read operations on IndexMap don't require locks. Map indexMap; - + public BitsyIndexMap() { this.indexMap = new ConcurrentHashMap(); } - // LOCK-FREE methods: The member indexNames can not be used. /** This method returns a copy of the edges/vertices held for the given key and value */ public Collection get(String key, Object value) { IndexType index = indexMap.get(key); - + if (index == null) { - throw new BitsyException(BitsyErrorCodes.MISSING_INDEX, "An index on " + key + " must be created before querying vertices/edges by that key. Defined indexes: " + indexMap.keySet()); + throw new BitsyException( + BitsyErrorCodes.MISSING_INDEX, + "An index on " + key + + " must be created before querying vertices/edges by that key. Defined indexes: " + + indexMap.keySet()); } else { return index.get(value); } } - + // LOCKED methods public void add(BeanType bean) { for (IndexType index : indexMap.values()) { index.add(bean); } } - + public void remove(BeanType bean) { if (bean == null) { // Nothing to do return; } - + for (IndexType index : indexMap.values()) { index.remove(bean); } @@ -55,11 +57,11 @@ protected void addKeyIndex(String key, IndexType index) { indexMap.put(key, index); } - + public void dropKeyIndex(String key) { indexMap.remove(key); } - + public Set getIndexedKeys() { return new HashSet(indexMap.keySet()); } diff --git a/src/main/java/com/lambdazen/bitsy/index/EdgeIndex.java b/src/main/java/com/lambdazen/bitsy/index/EdgeIndex.java index 98ba0c6..ef56639 100644 --- a/src/main/java/com/lambdazen/bitsy/index/EdgeIndex.java +++ b/src/main/java/com/lambdazen/bitsy/index/EdgeIndex.java @@ -1,26 +1,24 @@ package com.lambdazen.bitsy.index; -import java.util.Iterator; -import java.util.Map; - import com.lambdazen.bitsy.ads.dict.Dictionary; import com.lambdazen.bitsy.store.EdgeBean; +import java.util.Iterator; public class EdgeIndex extends BitsyIndex { String key; - + public EdgeIndex(String key, Iterator initialContents) { super(); this.key = key; - + load(initialContents); } - + @Override public Object getValue(EdgeBean bean) { Dictionary props = bean.getPropertiesDict(); - return (props == null) ? null : props.getProperty(key); + return (props == null) ? null : props.getProperty(key); } @Override diff --git a/src/main/java/com/lambdazen/bitsy/index/EdgeIndexMap.java b/src/main/java/com/lambdazen/bitsy/index/EdgeIndexMap.java index ea3314f..83deae1 100644 --- a/src/main/java/com/lambdazen/bitsy/index/EdgeIndexMap.java +++ b/src/main/java/com/lambdazen/bitsy/index/EdgeIndexMap.java @@ -1,8 +1,7 @@ package com.lambdazen.bitsy.index; -import java.util.Iterator; - import com.lambdazen.bitsy.store.EdgeBean; +import java.util.Iterator; public class EdgeIndexMap extends BitsyIndexMap { public EdgeIndexMap() { diff --git a/src/main/java/com/lambdazen/bitsy/index/IndexHelper.java b/src/main/java/com/lambdazen/bitsy/index/IndexHelper.java index f4bb6c9..e1c47f1 100644 --- a/src/main/java/com/lambdazen/bitsy/index/IndexHelper.java +++ b/src/main/java/com/lambdazen/bitsy/index/IndexHelper.java @@ -1,58 +1,62 @@ package com.lambdazen.bitsy.index; -import java.util.ArrayList; -import java.util.Collection; - import com.lambdazen.bitsy.BitsyElement; import com.lambdazen.bitsy.BitsyState; import com.lambdazen.bitsy.store.EdgeBean; import com.lambdazen.bitsy.store.VertexBean; +import java.util.ArrayList; +import java.util.Collection; public class IndexHelper { - public static Collection filterElementsByKeyValue(Collection elems, String key, Object value) { + public static Collection filterElementsByKeyValue( + Collection elems, String key, Object value) { ArrayList ans = new ArrayList(); - + for (T elem : elems) { if (elem.getState() == BitsyState.D) { continue; } - + Object elemVal = elem.value(key); - + if ((elemVal != null) && (elemVal.equals(value))) { ans.add(elem); } - } - + } + return ans; } - - public static Collection filterVertexBeansByKeyValue(Collection elems, String key, Object value) { + + public static Collection filterVertexBeansByKeyValue( + Collection elems, String key, Object value) { ArrayList ans = new ArrayList(); - + for (VertexBean elem : elems) { - Object elemVal = (elem.getProperties() == null) ? null : (elem.getProperties().get(key)); - + Object elemVal = (elem.getProperties() == null) + ? null + : (elem.getProperties().get(key)); + if ((elemVal != null) && (elemVal.equals(value))) { ans.add(elem); } - } - + } + return ans; } public static Collection filterEdgeBeansByKeyValue(Collection elems, String key, Object value) { ArrayList ans = new ArrayList(); - + for (EdgeBean elem : elems) { - Object elemVal = (elem.getPropertiesDict() == null) ? null : (elem.getPropertiesDict().getProperty(key)); - + Object elemVal = (elem.getPropertiesDict() == null) + ? null + : (elem.getPropertiesDict().getProperty(key)); + if ((elemVal != null) && (elemVal.equals(value))) { ans.add(elem); } - } - + } + return ans; } - } diff --git a/src/main/java/com/lambdazen/bitsy/index/VertexIndex.java b/src/main/java/com/lambdazen/bitsy/index/VertexIndex.java index 1f710a6..cc974d5 100644 --- a/src/main/java/com/lambdazen/bitsy/index/VertexIndex.java +++ b/src/main/java/com/lambdazen/bitsy/index/VertexIndex.java @@ -1,25 +1,24 @@ package com.lambdazen.bitsy.index; +import com.lambdazen.bitsy.store.VertexBean; import java.util.Iterator; import java.util.Map; -import com.lambdazen.bitsy.store.VertexBean; - public class VertexIndex extends BitsyIndex { String key; - + public VertexIndex(String key, Iterator initialContents) { super(); this.key = key; - + load(initialContents); } - + @Override public Object getValue(VertexBean bean) { Map props = bean.getProperties(); - return (props == null) ? null : props.get(key); + return (props == null) ? null : props.get(key); } @Override diff --git a/src/main/java/com/lambdazen/bitsy/index/VertexIndexMap.java b/src/main/java/com/lambdazen/bitsy/index/VertexIndexMap.java index d676241..705fa44 100644 --- a/src/main/java/com/lambdazen/bitsy/index/VertexIndexMap.java +++ b/src/main/java/com/lambdazen/bitsy/index/VertexIndexMap.java @@ -1,8 +1,7 @@ package com.lambdazen.bitsy.index; -import java.util.Iterator; - import com.lambdazen.bitsy.store.VertexBean; +import java.util.Iterator; public class VertexIndexMap extends BitsyIndexMap { public VertexIndexMap() { diff --git a/src/main/java/com/lambdazen/bitsy/jsr223/BitsyGremlinPlugin.java b/src/main/java/com/lambdazen/bitsy/jsr223/BitsyGremlinPlugin.java index a5c4d7a..57154a8 100644 --- a/src/main/java/com/lambdazen/bitsy/jsr223/BitsyGremlinPlugin.java +++ b/src/main/java/com/lambdazen/bitsy/jsr223/BitsyGremlinPlugin.java @@ -14,34 +14,32 @@ import org.apache.tinkerpop.gremlin.jsr223.DefaultImportCustomizer; import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer; -public class BitsyGremlinPlugin - extends AbstractGremlinPlugin -{ - private static final String NAME = "lambdazen.bitsy"; +public class BitsyGremlinPlugin extends AbstractGremlinPlugin { + private static final String NAME = "lambdazen.bitsy"; - private static ImportCustomizer imports() { - return DefaultImportCustomizer.build() - .addClassImports( - BitsyEdge.class, - BitsyElement.class, - BitsyGraph.class, - ThreadedBitsyGraph.class, - BitsyProperty.class, - BitsyVertex.class, - BitsyVertexProperty.class, - UUID.class, - BitsyTransaction.class, - BitsyIoRegistryV3d0.class - ).create(); - } + private static ImportCustomizer imports() { + return DefaultImportCustomizer.build() + .addClassImports( + BitsyEdge.class, + BitsyElement.class, + BitsyGraph.class, + ThreadedBitsyGraph.class, + BitsyProperty.class, + BitsyVertex.class, + BitsyVertexProperty.class, + UUID.class, + BitsyTransaction.class, + BitsyIoRegistryV3d0.class) + .create(); + } - private static final BitsyGremlinPlugin INSTANCE = new BitsyGremlinPlugin(); + private static final BitsyGremlinPlugin INSTANCE = new BitsyGremlinPlugin(); - public BitsyGremlinPlugin() { - super(NAME, imports()); - } + public BitsyGremlinPlugin() { + super(NAME, imports()); + } - public static BitsyGremlinPlugin instance() { - return INSTANCE; - } + public static BitsyGremlinPlugin instance() { + return INSTANCE; + } } diff --git a/src/main/java/com/lambdazen/bitsy/store/AdjacencyMap.java b/src/main/java/com/lambdazen/bitsy/store/AdjacencyMap.java index 065a95b..4ede1dd 100644 --- a/src/main/java/com/lambdazen/bitsy/store/AdjacencyMap.java +++ b/src/main/java/com/lambdazen/bitsy/store/AdjacencyMap.java @@ -1,5 +1,7 @@ package com.lambdazen.bitsy.store; +import com.lambdazen.bitsy.IEdge; +import com.lambdazen.bitsy.UUID; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -8,56 +10,52 @@ import java.util.Map; import java.util.NavigableMap; import java.util.TreeMap; - import org.apache.tinkerpop.gremlin.structure.Direction; -import com.lambdazen.bitsy.IEdge; -import com.lambdazen.bitsy.UUID; - -/** This map is used to keep track of edges between vertices in the transaction context. */ +/** This map is used to keep track of edges between vertices in the transaction context. */ public class AdjacencyMap { Map> outV; Map> inV; IEdgeRemover edgeRemover; - + public AdjacencyMap(boolean isConcurrent, IEdgeRemover edgeRemover) { this.edgeRemover = edgeRemover; this.outV = new HashMap>(); this.inV = new HashMap>(); } - + public void clear() { outV.clear(); inV.clear(); } - + public void addEdge(UUID edgeId, UUID outVId, String label, UUID inVId, int version) { // Update in and out vertices addToTreeMap(outV, outVId, new Endpoint(label, edgeId), version); addToTreeMap(inV, inVId, new Endpoint(label, edgeId), version); } - + private void addToTreeMap(Map> adjMap, UUID id, Endpoint endpoint, int version) { TreeMap value = adjMap.get(id); if (value == null) { value = new TreeMap(); adjMap.put(id, value); } - + value.put(endpoint, version); } - + public void removeEdge(UUID edgeId, UUID outVId, String label, UUID inVId) { // If the combination of given parameters don't match an existing edge, it won't be removed if (removeMatchingKeys(outV.get(outVId), new Endpoint(label, edgeId), null, null)) { outV.remove(outVId); } - + if (removeMatchingKeys(inV.get(inVId), new Endpoint(label, edgeId), null, null)) { inV.remove(inVId); } } - + public void removeVertex(UUID vertexId) { // Remove incoming and outgoing vertices if (removeMatchingKeys(outV.get(vertexId), new Endpoint(null, null), inV, Direction.OUT)) { @@ -68,48 +66,52 @@ public void removeVertex(UUID vertexId) { inV.remove(vertexId); } } - + public List getEdges(UUID vertexId, Direction dir, String[] edgeLabels) { NavigableMap map = (dir == Direction.IN) ? inV.get(vertexId) : outV.get(vertexId); if (map == null) { return Collections.emptyList(); } - + Endpoint[] matches; // Var-args appear as empty arrays if ((edgeLabels == null) || edgeLabels.length == 0) { - matches = new Endpoint[] { new Endpoint(null, null) }; + matches = new Endpoint[] {new Endpoint(null, null)}; } else { int len = edgeLabels.length; matches = new Endpoint[len]; - for (int i=0; i < len; i++) { + for (int i = 0; i < len; i++) { matches[i] = new Endpoint(edgeLabels[i], null); } } - + List edgeIds = new ArrayList(); - + for (Endpoint match : matches) { findMatchingValues(map, match, edgeIds); } - + return edgeIds; } - - // This method removes all keys that match the given value - private boolean removeMatchingKeys(NavigableMap map, Endpoint endpoint, Map> otherMap, Direction dir) { + + // This method removes all keys that match the given value + private boolean removeMatchingKeys( + NavigableMap map, + Endpoint endpoint, + Map> otherMap, + Direction dir) { if (map == null) { return false; } - + // Mark this endpoint as a marker, because it is used to do a tailMap traversal to remove matching edges endpoint.setMarker(); - - // Find the first key + + // Find the first key Endpoint floorKey = map.floorKey(endpoint); - + Map view; if (floorKey == null) { // This means that the element being searched is the minimum @@ -117,27 +119,27 @@ private boolean removeMatchingKeys(NavigableMap map, Endpoint } else { view = map.tailMap(floorKey); } - + Iterator> entryIter = view.entrySet().iterator(); boolean isFirst = true; while (entryIter.hasNext()) { Map.Entry entry = entryIter.next(); Endpoint key = entry.getKey(); - + if (endpoint.isMatch(key)) { // Remove it from this index entryIter.remove(); - + // and from the underlying edge map if necessary if (dir != null) { // Direction is null if this is a recursive all - // Remove the edge if the map is provided for this purpose + // Remove the edge if the map is provided for this purpose UUID edgeId = key.getEdgeId(); IEdge edge = edgeRemover.removeEdge(edgeId); - + assert (edge != null); - + // Remove the other endpoint of this edge. NOTE: Self loops are not allowed. Endpoint otherEndpoint; UUID otherVertexId; @@ -161,21 +163,21 @@ private boolean removeMatchingKeys(NavigableMap map, Endpoint break; } } - + isFirst = false; } - + return (map.size() == 0); } - - // This method removes all keys that match the given value + + // This method removes all keys that match the given value private void findMatchingValues(NavigableMap map, Endpoint endpoint, List result) { // Mark this endpoint as a marker, because it is used to do a tailMap traversal to query matching edges endpoint.setMarker(); - - // Find the first key + + // Find the first key Endpoint floorKey = map.floorKey(endpoint); - + Map view; if (floorKey == null) { // This means that the element being searched is the minimum @@ -183,7 +185,7 @@ private void findMatchingValues(NavigableMap map, Endpoint en } else { view = map.tailMap(floorKey); } - + boolean isFirst = true; for (Map.Entry entry : view.entrySet()) { Endpoint key = entry.getKey(); @@ -193,14 +195,14 @@ private void findMatchingValues(NavigableMap map, Endpoint en result.add(key.getEdgeId()); } else { // Done with the search -- the tree map is sorted - + if (isFirst) { // continue } else { break; } } - + isFirst = false; } } diff --git a/src/main/java/com/lambdazen/bitsy/store/AdjacencyMapForBeans.java b/src/main/java/com/lambdazen/bitsy/store/AdjacencyMapForBeans.java index 59e8f58..d2adcbe 100644 --- a/src/main/java/com/lambdazen/bitsy/store/AdjacencyMapForBeans.java +++ b/src/main/java/com/lambdazen/bitsy/store/AdjacencyMapForBeans.java @@ -1,22 +1,20 @@ package com.lambdazen.bitsy.store; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.tinkerpop.gremlin.structure.Direction; - import com.lambdazen.bitsy.ads.set.ClassifierGetter; import com.lambdazen.bitsy.ads.set.CompactMultiSetMax; import com.lambdazen.bitsy.ads.set.CompactSet; import com.lambdazen.bitsy.ads.set.Set24; import com.lambdazen.bitsy.ads.set.SetMax; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.tinkerpop.gremlin.structure.Direction; -/** This map is used to keep track of edges between vertices in the memory graph store. */ +/** This map is used to keep track of edges between vertices in the memory graph store. */ public class AdjacencyMapForBeans { IEdgeRemover edgeRemover; ClassifierGetter edgeBeanClassifier; - + public AdjacencyMapForBeans(boolean isConcurrent, IEdgeRemover edgeRemover) { this.edgeRemover = edgeRemover; this.edgeBeanClassifier = new ClassifierGetter() { @@ -31,21 +29,21 @@ public void addEdge(EdgeBean eBean) { // Update in and out vertices VertexBean outV = eBean.outVertex; VertexBean inV = eBean.inVertex; - + outV.outEdges = addEdgeToAdjList(outV.outEdges, eBean); inV.inEdges = addEdgeToAdjList(inV.inEdges, eBean); } private Object addEdgeToAdjList(Object adjList, EdgeBean eBean) { if (adjList instanceof CompactMultiSetMax) { - CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList; - - return adjListMultiSet.add(eBean, edgeBeanClassifier); + CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax) adjList; + + return adjListMultiSet.add(eBean, edgeBeanClassifier); } else { Object ans = CompactSet.add(adjList, eBean); - + if (ans instanceof SetMax) { - return convertToMultiSet((SetMax)ans); + return convertToMultiSet((SetMax) ans); } else { return ans; } @@ -62,17 +60,19 @@ protected void removeEdgeWithoutCallback(EdgeBean eBean) { VertexBean outV = eBean.outVertex; VertexBean inV = eBean.inVertex; - outV.outEdges = removeEdgeFromAdjList(outV.outEdges, eBean); // CompactSet.remove(outV.outEdges, eBean); - inV.inEdges = removeEdgeFromAdjList(inV.inEdges, eBean);; // CompactSet.remove(inV.inEdges, eBean); + outV.outEdges = + removeEdgeFromAdjList(outV.outEdges, eBean); // CompactSet.remove(outV.outEdges, eBean); + inV.inEdges = removeEdgeFromAdjList(inV.inEdges, eBean); + ; // CompactSet.remove(inV.inEdges, eBean); } - + private Object removeEdgeFromAdjList(Object adjList, EdgeBean eBean) { if (adjList instanceof CompactMultiSetMax) { - CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList; - + CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax) adjList; + CompactMultiSetMax ans = adjListMultiSet.remove(eBean, edgeBeanClassifier); - - // The first check is fast and increases the chances of hitting the second one + + // The first check is fast and increases the chances of hitting the second one if ((ans.getOccupiedCells() <= 13) && !ans.sizeBiggerThan24()) { return convertToSet(ans); } else { @@ -82,11 +82,11 @@ private Object removeEdgeFromAdjList(Object adjList, EdgeBean eBean) { return CompactSet.remove(adjList, eBean); } } - + private Object[] getEdgesFromAdjList(Object adjList) { if (adjList instanceof CompactMultiSetMax) { - CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax)adjList; - + CompactMultiSetMax adjListMultiSet = (CompactMultiSetMax) adjList; + return adjListMultiSet.getAllElements(); } else { return CompactSet.getElements(adjList); @@ -102,10 +102,10 @@ private Object convertToSet(CompactMultiSetMax set) { private Object convertToMultiSet(SetMax set) { // Use safe = false, which means that the multi-set can use the default SetMax implementation CompactMultiSetMax ans = new CompactMultiSetMax(36, false); - + for (Object obj : set.getElements()) { if (obj != null) { - ans.add((EdgeBean)obj, edgeBeanClassifier); + ans.add((EdgeBean) obj, edgeBeanClassifier); } } @@ -119,19 +119,21 @@ public void removeVertex(VertexBean vBean) { // Remove outgoing edges for (Object obj : getEdgesFromAdjList(vBean.outEdges)) { - EdgeBean eBean = (EdgeBean)obj; - eBean.inVertex.inEdges = removeEdgeFromAdjList(eBean.inVertex.inEdges, eBean); // CompactSet.remove(eBean.inVertex.inEdges, eBean); + EdgeBean eBean = (EdgeBean) obj; + eBean.inVertex.inEdges = removeEdgeFromAdjList( + eBean.inVertex.inEdges, eBean); // CompactSet.remove(eBean.inVertex.inEdges, eBean); // Callback edgeRemover.removeEdge(eBean.getId()); } - + vBean.outEdges = null; // Remove incoming edges for (Object obj : getEdgesFromAdjList(vBean.inEdges)) { - EdgeBean eBean = (EdgeBean)obj; - eBean.outVertex.outEdges = removeEdgeFromAdjList(eBean.outVertex.outEdges, eBean); // CompactSet.remove(eBean.outVertex.outEdges, eBean); + EdgeBean eBean = (EdgeBean) obj; + eBean.outVertex.outEdges = removeEdgeFromAdjList( + eBean.outVertex.outEdges, eBean); // CompactSet.remove(eBean.outVertex.outEdges, eBean); // Callback edgeRemover.removeEdge(eBean.getId()); @@ -139,7 +141,7 @@ public void removeVertex(VertexBean vBean) { vBean.inEdges = null; } - + public List getEdges(VertexBean vBean, Direction dir, String[] edgeLabels) { if (vBean == null) { return Collections.emptyList(); @@ -157,26 +159,26 @@ public List getEdges(VertexBean vBean, Direction dir, String[] edgeLab boolean origMatch = (edgeLabels == null) || edgeLabels.length == 0; - boolean multiSet = (edges instanceof CompactMultiSetMax); + boolean multiSet = (edges instanceof CompactMultiSetMax); String[] edgeLabelsToQuery = (multiSet && (!origMatch)) ? edgeLabels : new String[] {null}; - + for (String edgeLabelToQuery : edgeLabelsToQuery) { Object[] edgeBeans; if (multiSet) { - edgeBeans = ((CompactMultiSetMax)edges).getSuperSetWithClassifier(edgeLabelToQuery); + edgeBeans = ((CompactMultiSetMax) edges).getSuperSetWithClassifier(edgeLabelToQuery); } else { edgeBeans = CompactSet.getElements(edges); } - + for (Object obj : edgeBeans) { // Always check for nulls on getElements() because reads don't acquire locks if (obj == null) { continue; } - + boolean match = origMatch; - - EdgeBean eBean = (EdgeBean)obj; + + EdgeBean eBean = (EdgeBean) obj; if (!match) { String eLabel = eBean.getLabel(); @@ -191,7 +193,7 @@ public List getEdges(VertexBean vBean, Direction dir, String[] edgeLab } } } - + if (match) { // Always copy objects that are directly picked up from the memory store // These objects can be updated later while the query is in progress diff --git a/src/main/java/com/lambdazen/bitsy/store/BackupJob.java b/src/main/java/com/lambdazen/bitsy/store/BackupJob.java index f631b5c..3619a20 100644 --- a/src/main/java/com/lambdazen/bitsy/store/BackupJob.java +++ b/src/main/java/com/lambdazen/bitsy/store/BackupJob.java @@ -1,21 +1,20 @@ package com.lambdazen.bitsy.store; -import java.nio.file.Path; - import com.lambdazen.bitsy.BitsyException; +import java.nio.file.Path; public class BackupJob extends JobWithCountDownLatch implements IVeReorgJob { private Path backupDir; private BitsyException bex; - + public BackupJob(Path backupDir) { this.backupDir = backupDir; } - + public Path getBackupDir() { return backupDir; } - + public BitsyException getException() { return bex; } diff --git a/src/main/java/com/lambdazen/bitsy/store/CompactAndCopyTask.java b/src/main/java/com/lambdazen/bitsy/store/CompactAndCopyTask.java index 4f9bb1a..360dfa5 100644 --- a/src/main/java/com/lambdazen/bitsy/store/CompactAndCopyTask.java +++ b/src/main/java/com/lambdazen/bitsy/store/CompactAndCopyTask.java @@ -1,13 +1,12 @@ package com.lambdazen.bitsy.store; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.lambdazen.bitsy.BitsyErrorCodes; import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.IGraphStore; import com.lambdazen.bitsy.store.Record.RecordType; import com.lambdazen.bitsy.util.CommittableFileLog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class takes an array of input file logs and appends their contents (in @@ -16,18 +15,23 @@ */ public class CompactAndCopyTask implements Runnable { private static final Logger log = LoggerFactory.getLogger(CompactAndCopyTask.class); - - // 4KB initial buffer size to avoid too many resizings + + // 4KB initial buffer size to avoid too many resizings private static final int INIT_STRING_BUFFER_SIZE = 4096; - + CommittableFileLog[] inputs; CommittableFileLog vLog; CommittableFileLog eLog; IGraphStore store; int addedLines; long nextTxCounter; - - public CompactAndCopyTask(CommittableFileLog[] inputs, CommittableFileLog vos, CommittableFileLog eos, IGraphStore store, long nextTxCounter) { + + public CompactAndCopyTask( + CommittableFileLog[] inputs, + CommittableFileLog vos, + CommittableFileLog eos, + IGraphStore store, + long nextTxCounter) { this.inputs = inputs; this.vLog = vos; this.eLog = eos; @@ -35,23 +39,23 @@ public CompactAndCopyTask(CommittableFileLog[] inputs, CommittableFileLog vos, C this.addedLines = 0; this.nextTxCounter = nextTxCounter; } - + public void run() { - StringBuffer tempV = new StringBuffer(INIT_STRING_BUFFER_SIZE); - StringBuffer tempE = new StringBuffer(INIT_STRING_BUFFER_SIZE); - + StringBuilder tempV = new StringBuilder(INIT_STRING_BUFFER_SIZE); + StringBuilder tempE = new StringBuilder(INIT_STRING_BUFFER_SIZE); + // If the first log is not a tx log, this is a reorg // A reorg goes through the entire set of database files, which means // that D records can be dropped. boolean isReorg = !inputs[0].isTxLog(); - + int i = 0; String fileName = null; int lineNo = 0; - + BitsyException toThrow = null; try { - for (i=0; i < inputs.length; i++) { + for (i = 0; i < inputs.length; i++) { CommittableFileLog inputLog = inputs[i]; try { @@ -60,7 +64,8 @@ public void run() { inputLog.openForRead(); // In transational mode, only transactions that are completed will be writted to V/E txt files - boolean isTransactional = inputLog.isTxLog() && (i == inputs.length - 1); // Only the last TX LOG may be incomplete in recovery mode + boolean isTransactional = inputLog.isTxLog() + && (i == inputs.length - 1); // Only the last TX LOG may be incomplete in recovery mode String line; lineNo = 0; @@ -71,7 +76,7 @@ public void run() { Record rec = Record.parseRecord(line, lineNo, fileName); if (rec.checkObsolete(store, isReorg, lineNo, fileName)) { - //log.debug("Ignoring obsolete record {}", line); + // log.debug("Ignoring obsolete record {}", line); continue; } @@ -90,64 +95,70 @@ public void run() { tempV.setLength(0); tempE.setLength(0); } - + // No special handling is needed switch (recType) { - case T: // Transaction marker can be ignored - case L: // Old log marker can be ignored -- only happens during rollover - break; - - case E: - //eLog.append(line.getBytes(FileBackedMemoryGraphStore.utf8)); - //eLog.append(newLine); - tempE.append(line); - tempE.append('\n'); - break; - - case V: - //vLog.append(line.getBytes(FileBackedMemoryGraphStore.utf8)); - //vLog.append(newLine); - tempV.append(line); - tempV.append('\n'); - break; - - default: - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Unhandled record type " + recType + " in file " + fileName + " at line " + lineNo); + case T: // Transaction marker can be ignored + case L: // Old log marker can be ignored -- only happens during rollover + break; + + case E: + // eLog.append(line.getBytes(FileBackedMemoryGraphStore.utf8)); + // eLog.append(newLine); + tempE.append(line); + tempE.append('\n'); + break; + + case V: + // vLog.append(line.getBytes(FileBackedMemoryGraphStore.utf8)); + // vLog.append(newLine); + tempV.append(line); + tempV.append('\n'); + break; + + default: + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Unhandled record type " + recType + " in file " + fileName + " at line " + + lineNo); } } else { - // A transactional file -- this requires each block that ends with a T records to be flushed + // A transactional file -- this requires each block that ends with a T records to be flushed switch (recType) { - case L: // Old log marker can be ignored - break; - - case T: - // Write out the temporary data to the files - vLog.append(tempV.toString().getBytes(FileBackedMemoryGraphStore.utf8)); - eLog.append(tempE.toString().getBytes(FileBackedMemoryGraphStore.utf8)); - - // Reset the temporary buffers - tempV.setLength(0); - tempE.setLength(0); - - // All set - break; - - case E: - tempE.append(line); - tempE.append('\n'); - break; - - case V: - tempV.append(line); - tempV.append('\n'); - break; - - default: - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Unhandled record type " + recType + " in file " + fileName + " at line " + lineNo); + case L: // Old log marker can be ignored + break; + + case T: + // Write out the temporary data to the files + vLog.append(tempV.toString().getBytes(FileBackedMemoryGraphStore.utf8)); + eLog.append(tempE.toString().getBytes(FileBackedMemoryGraphStore.utf8)); + + // Reset the temporary buffers + tempV.setLength(0); + tempE.setLength(0); + + // All set + break; + + case E: + tempE.append(line); + tempE.append('\n'); + break; + + case V: + tempV.append(line); + tempV.append('\n'); + break; + + default: + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Unhandled record type " + recType + " in file " + fileName + " at line " + + lineNo); } } } - + if (!isTransactional) { // Write out the temporary data to the files vLog.append(tempV.toString().getBytes(FileBackedMemoryGraphStore.utf8)); @@ -162,20 +173,29 @@ public void run() { inputLog.close(); } } - - // After all inputs log(s) have been processed, an L entry is added to recover the V/E logs in case of crash in the middle of the NEXT copy process + + // After all inputs log(s) have been processed, an L entry is added to recover the V/E logs in case of crash + // in the middle of the NEXT copy process String logRec = Record.generateDBLine(RecordType.L, "" + nextTxCounter); vLog.append(logRec.getBytes(FileBackedMemoryGraphStore.utf8)); eLog.append(logRec.getBytes(FileBackedMemoryGraphStore.utf8)); } catch (BitsyException e) { - // There was an error in the hash-code or elsewhere. This is not a recoverable error -- may be the next load can fix it. - log.error("Unrecoverable error while copying database files during a " + ((isReorg) ? "reorganization" : "transaction flush"), e); + // There was an error in the hash-code or elsewhere. This is not a recoverable error -- may be the next load + // can fix it. + log.error( + "Unrecoverable error while copying database files during a " + + ((isReorg) ? "reorganization" : "transaction flush"), + e); toThrow = e; } catch (Exception e) { // This is an IO error - toThrow = new BitsyException(BitsyErrorCodes.ERROR_READING_FROM_FILE, "File " + fileName + " at line " + lineNo, e); - log.error("Unrecoverable error while copying database files during a " + ((isReorg) ? "reorganization" : "transaction flush"), e); + toThrow = new BitsyException( + BitsyErrorCodes.ERROR_READING_FROM_FILE, "File " + fileName + " at line " + lineNo, e); + log.error( + "Unrecoverable error while copying database files during a " + + ((isReorg) ? "reorganization" : "transaction flush"), + e); } finally { try { vLog.commit(); @@ -195,13 +215,14 @@ public void run() { } } } - - // The exception may have happened in the catch-block or inside the commit. But only the first one (toThrow) is the root cause + + // The exception may have happened in the catch-block or inside the commit. But only the first one (toThrow) is + // the root cause if (toThrow != null) { throw toThrow; } } - + public int getOutputLines() { return addedLines; } diff --git a/src/main/java/com/lambdazen/bitsy/store/EdgeBean.java b/src/main/java/com/lambdazen/bitsy/store/EdgeBean.java index 72c9913..2a117b6 100644 --- a/src/main/java/com/lambdazen/bitsy/store/EdgeBean.java +++ b/src/main/java/com/lambdazen/bitsy/store/EdgeBean.java @@ -1,26 +1,26 @@ package com.lambdazen.bitsy.store; -import java.io.Serializable; -import java.util.TreeMap; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.lambdazen.bitsy.IEdge; import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.ads.dict.Dictionary; +import java.io.Serializable; +import java.util.TreeMap; @JsonPropertyOrder({"class", "id", "v", "s", "o", "l", "i", "p"}) public class EdgeBean extends UUID implements IEdge, Serializable { private static final long serialVersionUID = -5962479601393604124L; - + Dictionary properties; String label; VertexBean outVertex; VertexBean inVertex; int version; - - public EdgeBean(UUID id, Dictionary properties, int version, String label, VertexBean outVertex, VertexBean inVertex) { + + public EdgeBean( + UUID id, Dictionary properties, int version, String label, VertexBean outVertex, VertexBean inVertex) { super(id.getMostSignificantBits(), id.getLeastSignificantBits()); this.properties = properties; @@ -29,7 +29,7 @@ public EdgeBean(UUID id, Dictionary properties, int version, String label, Verte this.outVertex = outVertex; this.inVertex = inVertex; } - + /** Shallow copy constructor */ public EdgeBean(EdgeBean orig) { super(orig.getMostSignificantBits(), orig.getLeastSignificantBits()); @@ -41,17 +41,18 @@ public EdgeBean(EdgeBean orig) { this.inVertex = orig.inVertex; } - // Use UUID's toString() -// public String toString() { -// return "EdgeBean(id = " + getIdStr() + ", props " + getProperties() + ", version = " + version + ", label = " + label + ", outV = " + outVertex + ", inV = " + inVertex + ")"; -// } + // Use UUID's toString() + // public String toString() { + // return "EdgeBean(id = " + getIdStr() + ", props " + getProperties() + ", version = " + version + ", label + // = " + label + ", outV = " + outVertex + ", inV = " + inVertex + ")"; + // } @JsonIgnore public UUID getId() { - // I am the ID! Saves on object creation and equals checks. + // I am the ID! Saves on object creation and equals checks. return this; } - + @JsonProperty("id") public String getIdStr() { return uuidRepr(); @@ -71,7 +72,7 @@ public TreeMap getProperties() { return ans; } } - + @JsonIgnore public Dictionary getPropertiesDict() { return properties; diff --git a/src/main/java/com/lambdazen/bitsy/store/EdgeBeanJson.java b/src/main/java/com/lambdazen/bitsy/store/EdgeBeanJson.java index 940a768..a9a3b52 100644 --- a/src/main/java/com/lambdazen/bitsy/store/EdgeBeanJson.java +++ b/src/main/java/com/lambdazen/bitsy/store/EdgeBeanJson.java @@ -1,7 +1,5 @@ package com.lambdazen.bitsy.store; -import java.util.TreeMap; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -9,6 +7,7 @@ import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.ads.dict.Dictionary; import com.lambdazen.bitsy.ads.dict.DictionaryFactory; +import java.util.TreeMap; public class EdgeBeanJson extends EdgeBean { private static final long serialVersionUID = 3554788509798848887L; @@ -17,20 +16,31 @@ public class EdgeBeanJson extends EdgeBean { private BitsyState state; @JsonCreator - public EdgeBeanJson(@JsonProperty("id") String idStr, - @JsonProperty("p") TreeMap properties, - @JsonProperty("v") int version, - @JsonProperty("l") String label, - @JsonProperty("o") String outVertexIdStr, - @JsonProperty("i") String inVertexIdStr, + public EdgeBeanJson( + @JsonProperty("id") String idStr, + @JsonProperty("p") TreeMap properties, + @JsonProperty("v") int version, + @JsonProperty("l") String label, + @JsonProperty("o") String outVertexIdStr, + @JsonProperty("i") String inVertexIdStr, @JsonProperty("s") BitsyState state) { - this(UUID.fromString(idStr), DictionaryFactory.fromMap(properties), version, - label, UUID.fromString(outVertexIdStr), UUID.fromString(inVertexIdStr), + this( + UUID.fromString(idStr), + DictionaryFactory.fromMap(properties), + version, + label, + UUID.fromString(outVertexIdStr), + UUID.fromString(inVertexIdStr), state); } - - public EdgeBeanJson(UUID id, Dictionary properties, int version, - String label, UUID outVertexId, UUID inVertexId, + + public EdgeBeanJson( + UUID id, + Dictionary properties, + int version, + String label, + UUID outVertexId, + UUID inVertexId, BitsyState state) { super(id, properties, version, label, null, null); @@ -44,7 +54,7 @@ public EdgeBeanJson(UUID id, Dictionary properties, int version, public UUID getInVertexId() { return inVertexId; } - + @JsonIgnore @Override public UUID getOutVertexId() { @@ -55,7 +65,7 @@ public UUID getOutVertexId() { public String getInVertexIdStr() { return UUID.toString(inVertexId); } - + @JsonProperty("o") public String getOutVertexIdStr() { return UUID.toString(outVertexId); diff --git a/src/main/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStore.java b/src/main/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStore.java index 46d2e66..351c888 100644 --- a/src/main/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStore.java +++ b/src/main/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStore.java @@ -1,10 +1,34 @@ package com.lambdazen.bitsy.store; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyErrorCodes; +import com.lambdazen.bitsy.BitsyException; +import com.lambdazen.bitsy.BitsyVertex; +import com.lambdazen.bitsy.ICommitChanges; +import com.lambdazen.bitsy.IGraphStore; +import com.lambdazen.bitsy.UUID; +import com.lambdazen.bitsy.store.Record.RecordType; +import com.lambdazen.bitsy.tx.BitsyTransaction; +import com.lambdazen.bitsy.util.BufferFlusher; +import com.lambdazen.bitsy.util.BufferPotential; +import com.lambdazen.bitsy.util.BufferQueuer; +import com.lambdazen.bitsy.util.CommittableFileLog; +import com.lambdazen.bitsy.util.DoubleBuffer; +import com.lambdazen.bitsy.util.DoubleBuffer.BufferName; +import com.lambdazen.bitsy.util.DoubleBufferWithExecWork; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -18,9 +42,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.json.JsonMapper; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; @@ -28,31 +49,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyErrorCodes; -import com.lambdazen.bitsy.BitsyException; -import com.lambdazen.bitsy.BitsyVertex; -import com.lambdazen.bitsy.ICommitChanges; -import com.lambdazen.bitsy.IGraphStore; -import com.lambdazen.bitsy.UUID; -import com.lambdazen.bitsy.store.Record.RecordType; -import com.lambdazen.bitsy.tx.BitsyTransaction; -import com.lambdazen.bitsy.util.BufferFlusher; -import com.lambdazen.bitsy.util.BufferPotential; -import com.lambdazen.bitsy.util.BufferQueuer; -import com.lambdazen.bitsy.util.CommittableFileLog; -import com.lambdazen.bitsy.util.DoubleBuffer; -import com.lambdazen.bitsy.util.DoubleBuffer.BufferName; -import com.lambdazen.bitsy.util.DoubleBufferWithExecWork; - /** This class represents a memory graph store that is backed by a durable files */ public class FileBackedMemoryGraphStore implements IGraphStore { - private static final Logger log = LoggerFactory.getLogger(FileBackedMemoryGraphStore.class); + private static final Logger log = LoggerFactory.getLogger(FileBackedMemoryGraphStore.class); private static final String META_PREFIX = "meta"; private static final String META_B_TXT = "metaB.txt"; @@ -63,20 +62,20 @@ public class FileBackedMemoryGraphStore implements IGraphStore { private static final String V_A_TXT = "vA.txt"; private static final String TX_B_TXT = "txB.txt"; private static final String TX_A_TXT = "txA.txt"; - + // Commit 10K ops per load in the V/E files public static final int DEFAULT_LOAD_OPS_PER_COMMIT = 10000; public static final int DEFAULT_MIN_LINES_BEFORE_REORG = 1000; - + public static final Random rand = new Random(); - - public static final Charset utf8 = Charset.forName("utf-8"); + + public static final Charset utf8 = StandardCharsets.UTF_8; private static final int JOIN_TIMEOUT = 60000; // 1 minute private static AtomicInteger idCounter = new AtomicInteger(1); private static AtomicBoolean backupInProgress = new AtomicBoolean(false); - - private int id; + + private int id; private ObjectMapper mapper; private MemoryGraphStore memStore; private Path dbPath; @@ -89,28 +88,33 @@ public class FileBackedMemoryGraphStore implements IGraphStore { private CommittableFileLog eB; private CommittableFileLog mA; private CommittableFileLog mB; - + private DoubleBuffer txToTxLogBuf; private DoubleBufferWithExecWork txLogToVEBuf; private DoubleBufferWithExecWork veReorgBuf; - + private TxLogFlushPotential txLogFlushPotential; private VEObsolescencePotential veReorgPotential; - + private long logCounter; private BufferName lastFlushedBuffer = null; - private Object flushCompleteSignal = new Object(); - + private Object flushCompleteSignal = new Object(); + // Major version number - public static String CURRENT_MAJOR_VERSION_NUMBER = "1.5"; + public static String CURRENT_MAJOR_VERSION_NUMBER = "1.5"; private String majorVersionNumber = "1.0"; public FileBackedMemoryGraphStore(MemoryGraphStore memStore, Path dbPath, long txLogThreshold, double reorgFactor) { - this(memStore, dbPath, txLogThreshold, reorgFactor, false); + this(memStore, dbPath, txLogThreshold, reorgFactor, false); } - - public FileBackedMemoryGraphStore(MemoryGraphStore memStore, Path dbPath, long txLogThreshold, double reorgFactor, boolean createDirIfMissing) { + + public FileBackedMemoryGraphStore( + MemoryGraphStore memStore, + Path dbPath, + long txLogThreshold, + double reorgFactor, + boolean createDirIfMissing) { this.id = idCounter.getAndIncrement(); this.memStore = memStore; this.dbPath = dbPath; @@ -121,27 +125,31 @@ public FileBackedMemoryGraphStore(MemoryGraphStore memStore, Path dbPath, long t builder.configure(SerializationFeature.INDENT_OUTPUT, false); builder.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); mapper = builder.build(); - mapper.configOverride(Map.class).setInclude(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)); + mapper.configOverride(Map.class) + .setInclude(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)); mapper.setSerializationInclusion(Include.NON_NULL); mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator()); - + if (!dbPath.toFile().isDirectory()) { - if (!createDirIfMissing) { - throw new BitsyException(BitsyErrorCodes.BAD_DB_PATH, "Expecting " + dbPath + " to be a folder. Exists? " + dbPath.toFile().exists()); - } else { - if (!dbPath.toFile().exists()) { - try { - Files.createDirectory(dbPath); - } catch (IOException ex) { - throw new BitsyException(BitsyErrorCodes.BAD_DB_PATH, "Couldn't create " + dbPath); - } - } - } + if (!createDirIfMissing) { + throw new BitsyException( + BitsyErrorCodes.BAD_DB_PATH, + "Expecting " + dbPath + " to be a folder. Exists? " + + dbPath.toFile().exists()); + } else { + if (!dbPath.toFile().exists()) { + try { + Files.createDirectory(dbPath); + } catch (IOException ex) { + throw new BitsyException(BitsyErrorCodes.BAD_DB_PATH, "Couldn't create " + dbPath); + } + } + } } // Start off the Log Counter as 1. openForRead() will update this to the maximum so far. this.logCounter = 1; - + this.txA = openFileLog(TX_A_TXT, true); this.txB = openFileLog(TX_B_TXT, true); this.vA = openFileLog(V_A_TXT, false); @@ -150,44 +158,59 @@ public FileBackedMemoryGraphStore(MemoryGraphStore memStore, Path dbPath, long t this.eB = openFileLog(E_B_TXT, false); this.mA = openFileLog(META_A_TXT, false); this.mB = openFileLog(META_B_TXT, false); - + log.debug("Initial log counter is {}", logCounter); - + // Find the earlier of the two CommittableFileLog vToLoad = getEarlierBuffer(vA, vB); CommittableFileLog eToLoad = getEarlierBuffer(eA, eB); CommittableFileLog[] txToLoad = getOrderedTxLogs(txA, txB); List logsToLoad = new ArrayList(); - + logsToLoad.add(vToLoad); logsToLoad.add(eToLoad); logsToLoad.addAll(Arrays.asList(txToLoad)); // Load the records from files to the memory graphs store log.debug("Loading logs in this order: {}", logsToLoad); - + LoadTask loadTask; try { - loadTask = new LoadTask(logsToLoad.toArray(new CommittableFileLog[0]), (MemoryGraphStore)memStore, DEFAULT_LOAD_OPS_PER_COMMIT, mapper, false); + loadTask = new LoadTask( + logsToLoad.toArray(new CommittableFileLog[0]), + (MemoryGraphStore) memStore, + DEFAULT_LOAD_OPS_PER_COMMIT, + mapper, + false); loadTask.run(); } catch (BitsyException e) { // Failed -- not try in repair mode log.info("Loading the database failed -- Trying again in repair mode"); memStore.reset(); - loadTask = new LoadTask(logsToLoad.toArray(new CommittableFileLog[0]), (MemoryGraphStore)memStore, DEFAULT_LOAD_OPS_PER_COMMIT, mapper, true); + loadTask = new LoadTask( + logsToLoad.toArray(new CommittableFileLog[0]), + (MemoryGraphStore) memStore, + DEFAULT_LOAD_OPS_PER_COMMIT, + mapper, + true); loadTask.run(); } long initialVE = loadTask.getTotalVE(); - + loadVersionAndIndexes(); if (!majorVersionNumber.equals(CURRENT_MAJOR_VERSION_NUMBER)) { - log.error("Can not load database with major version number {}. Expecting major version number {}", majorVersionNumber, CURRENT_MAJOR_VERSION_NUMBER); - - throw new BitsyException(BitsyErrorCodes.MAJOR_VERSION_MISMATCH, "Database has major version number " + majorVersionNumber + ". Expecting major version " + CURRENT_MAJOR_VERSION_NUMBER); + log.error( + "Can not load database with major version number {}. Expecting major version number {}", + majorVersionNumber, + CURRENT_MAJOR_VERSION_NUMBER); + + throw new BitsyException( + BitsyErrorCodes.MAJOR_VERSION_MISMATCH, + "Database has major version number " + majorVersionNumber + ". Expecting major version " + + CURRENT_MAJOR_VERSION_NUMBER); } - // Find out the transaction log that must be queued into first BufferName txBufName = (txToLoad[1] == txA) ? BufferName.A : BufferName.B; @@ -202,73 +225,80 @@ public FileBackedMemoryGraphStore(MemoryGraphStore memStore, Path dbPath, long t prepareForAppend(vToLoad); prepareForAppend(eToLoad); - CompactAndCopyTask txFlushTask = new CompactAndCopyTask(new CommittableFileLog[] {txToFlush}, vToLoad, eToLoad, memStore, nextTxCounter); + CompactAndCopyTask txFlushTask = + new CompactAndCopyTask(new CommittableFileLog[] {txToFlush}, vToLoad, eToLoad, memStore, nextTxCounter); txFlushTask.run(); if (txFlushTask.getOutputLines() > 0) { log.debug("Flushed partially flushed Tx Log {} to {} and {}", txToFlush, vToLoad, eToLoad); } - - // Clear the TX file + + // Clear the TX file txToFlush.openForOverwrite(logCounter++); // Clear the unused V and E buffers - CommittableFileLog vToClear = (vToLoad == vA) ? vB : vA; + CommittableFileLog vToClear = (vToLoad == vA) ? vB : vA; CommittableFileLog eToClear = (eToLoad == eA) ? eB : eA; vToClear.openForOverwrite(null); eToClear.openForOverwrite(null); - + // Find latest V and E buffers BufferName vBufName = (vToLoad == vA) ? BufferName.A : BufferName.B; BufferName eBufName = (eToLoad == eA) ? BufferName.A : BufferName.B; - + // See if for some reason, the V and E files have been swapped. This could happen if a reorg happens partially if (vBufName != eBufName) { // Yes. Now the edge will flip from A to B or vice versa - CommittableFileLog eToSave = (eToLoad == eA) ? eB : eA; - + CommittableFileLog eToSave = (eToLoad == eA) ? eB : eA; + eToLoad.openForRead(); eToSave.openForOverwrite(logCounter++); - + log.info("Moving out-of-sync edge file from {} to {}", eToLoad, eToSave); - CompactAndCopyTask eCopyTask = new CompactAndCopyTask(new CommittableFileLog[] {eToLoad}, vToLoad, eToSave, memStore, nextTxCounter); + CompactAndCopyTask eCopyTask = new CompactAndCopyTask( + new CommittableFileLog[] {eToLoad}, vToLoad, eToSave, memStore, nextTxCounter); eCopyTask.run(); - + eToLoad.openForOverwrite(null); eToLoad.close(); } - - this.txToTxLogBuf = new DoubleBuffer(new BufferPotential() { - @Override - public boolean addWork(TxUnit newWork) { - return true; - } - - @Override - public void reset() { - // Nothing to do - } - }, new TxUnitFlusher(), "MemToTxLogWriter-" + id); - + + this.txToTxLogBuf = new DoubleBuffer( + new BufferPotential() { + @Override + public boolean addWork(TxUnit newWork) { + return true; + } + + @Override + public void reset() { + // Nothing to do + } + }, + new TxUnitFlusher(), + "MemToTxLogWriter-" + id); + this.txLogFlushPotential = new TxLogFlushPotential(txLogThreshold); - - this.txLogToVEBuf = new DoubleBufferWithExecWork(txLogFlushPotential, + + this.txLogToVEBuf = new DoubleBufferWithExecWork( + txLogFlushPotential, new TxBatchQueuer(), - new TxBatchFlusher(), + new TxBatchFlusher(), "TxFlusher-" + id, false, // Don't keep track of the list of all Txs written to log false, // It is OK for the flusher and queuer to run at the same time - txBufName); // Start enqueuing into the Tx from the last start/stop - + txBufName); // Start enqueuing into the Tx from the last start/stop + this.veReorgPotential = new VEObsolescencePotential(DEFAULT_MIN_LINES_BEFORE_REORG, reorgFactor, initialVE); - this.veReorgBuf = new DoubleBufferWithExecWork(veReorgPotential, + this.veReorgBuf = new DoubleBufferWithExecWork( + veReorgPotential, new TxLogQueuer(), - new TxLogFlusher(), + new TxLogFlusher(), "VEReorg-" + id, false, // Don't keep track of the entire list of TxLogs -- too much memory true, // Ensure that the flusher and queuer don't run at the same time - vBufName); // Start enqueuing into the V/E file from the last start/stop + vBufName); // Start enqueuing into the V/E file from the last start/stop } - + public TxLogFlushPotential getTxLogFlushPotential() { return txLogFlushPotential; } @@ -283,12 +313,12 @@ private void loadVersionAndIndexes() { try { inputLog.openForRead(); String fileName = inputLog.getPath().toString(); - + int lineNo = 1; String line; while ((line = inputLog.readLine()) != null) { Record rec = Record.parseRecord(line, lineNo++, fileName); - + if (rec.getType() == RecordType.I) { IndexBean iBean = mapper.readValue(rec.getJson(), IndexBean.class); @@ -296,20 +326,24 @@ private void loadVersionAndIndexes() { } else if (rec.getType() == RecordType.M) { this.majorVersionNumber = rec.getJson(); } else { - throw new BitsyException(BitsyErrorCodes.DATABASE_IS_CORRUPT, "Only M and I records are valid in the metadata file. Found " + line + " in line number " + lineNo + " of file " + fileName); + throw new BitsyException( + BitsyErrorCodes.DATABASE_IS_CORRUPT, + "Only M and I records are valid in the metadata file. Found " + line + " in line number " + + lineNo + " of file " + fileName); } } inputLog.close(); } catch (Exception e) { if (e instanceof BitsyException) { - throw (BitsyException)e; + throw (BitsyException) e; } else { - throw new BitsyException(BitsyErrorCodes.DATABASE_IS_CORRUPT, "Unable to load indexes due to the given exception", e); + throw new BitsyException( + BitsyErrorCodes.DATABASE_IS_CORRUPT, "Unable to load indexes due to the given exception", e); } } } - + private void saveVersionAndIndexes() { CommittableFileLog oldLog = getEarlierBuffer(mA, mB); CommittableFileLog outputLog = (oldLog == mA) ? mB : mA; @@ -318,32 +352,36 @@ private void saveVersionAndIndexes() { outputLog.openForOverwrite(logCounter++); // Save the version - outputLog.append(Record.generateDBLine(RecordType.M, CURRENT_MAJOR_VERSION_NUMBER).getBytes(utf8)); + outputLog.append(Record.generateDBLine(RecordType.M, CURRENT_MAJOR_VERSION_NUMBER) + .getBytes(utf8)); // Vertex indexes for (String key : memStore.getIndexedKeys(Vertex.class)) { IndexBean indexBean = new IndexBean(0, key); - byte[] line = Record.generateDBLine(RecordType.I, mapper.writeValueAsString(indexBean)).getBytes(utf8); + byte[] line = Record.generateDBLine(RecordType.I, mapper.writeValueAsString(indexBean)) + .getBytes(utf8); outputLog.append(line); } - + // Edge indexes for (String key : memStore.getIndexedKeys(Edge.class)) { IndexBean indexBean = new IndexBean(1, key); - byte[] line = Record.generateDBLine(RecordType.I, mapper.writeValueAsString(indexBean)).getBytes(utf8); + byte[] line = Record.generateDBLine(RecordType.I, mapper.writeValueAsString(indexBean)) + .getBytes(utf8); outputLog.append(line); } - + outputLog.commit(); outputLog.close(); - + oldLog.openForOverwrite(null); oldLog.close(); } catch (Exception e) { if (e instanceof BitsyException) { - throw (BitsyException)e; + throw (BitsyException) e; } else { - throw new BitsyException(BitsyErrorCodes.DATABASE_IS_CORRUPT, "Unable to load indexes due to the given exception", e); + throw new BitsyException( + BitsyErrorCodes.DATABASE_IS_CORRUPT, "Unable to load indexes due to the given exception", e); } } } @@ -352,9 +390,9 @@ private CommittableFileLog[] getOrderedTxLogs(CommittableFileLog txLog1, Committ assert txLog1.getCounter() != null; assert txLog2.getCounter() != null; assert txLog1.getCounter().longValue() != txLog2.getCounter().longValue(); - + if (txLog1.getCounter().longValue() < txLog2.getCounter().longValue()) { - return new CommittableFileLog[] {txLog1, txLog2}; + return new CommittableFileLog[] {txLog1, txLog2}; } else { return new CommittableFileLog[] {txLog2, txLog1}; } @@ -367,7 +405,7 @@ private CommittableFileLog getEarlierBuffer(CommittableFileLog log1, Committable return log1; } else { assert log1.getCounter().longValue() != log2.getCounter().longValue(); - + return (log1.getCounter().longValue() < log2.getCounter().longValue()) ? log1 : log2; } } @@ -375,13 +413,13 @@ private CommittableFileLog getEarlierBuffer(CommittableFileLog log1, Committable public String toString() { return "FileBackedMemoryGraphStore-" + id + "(path = " + dbPath + ")"; } - + public void shutdown() { log.info("Stopping graph {}", toString()); this.txLogToVEBuf.stop(JOIN_TIMEOUT); this.veReorgBuf.stop(JOIN_TIMEOUT); this.txToTxLogBuf.stop(JOIN_TIMEOUT); - + txA.close(); txB.close(); vA.close(); @@ -391,14 +429,14 @@ public void shutdown() { mA.close(); mB.close(); - this.memStore.shutdown(); + this.memStore.shutdown(); } private CommittableFileLog openFileLog(String fileName, boolean isTxLog) throws BitsyException { Path toOpen = dbPath.resolve(fileName); try { CommittableFileLog cfl = new CommittableFileLog(toOpen, isTxLog); - + // First check if the file exists if (!cfl.exists()) { // Otherwise create it using openForOverwrite @@ -406,27 +444,28 @@ private CommittableFileLog openFileLog(String fileName, boolean isTxLog) throws // Set the version for meta files if (fileName.startsWith(META_PREFIX)) { - cfl.append(Record.generateDBLine(RecordType.M, CURRENT_MAJOR_VERSION_NUMBER).getBytes(utf8)); + cfl.append(Record.generateDBLine(RecordType.M, CURRENT_MAJOR_VERSION_NUMBER) + .getBytes(utf8)); } cfl.close(); } - + // Then open for read cfl.openForRead(); - + log.debug("Checking file: {} with log counter {}. Size = {}", cfl.getPath(), cfl.getCounter(), cfl.size()); - + if ((cfl.getCounter() != null) && (cfl.getCounter().longValue() >= logCounter)) { this.logCounter = cfl.getCounter().longValue() + 1; } - + return cfl; } catch (IOException e) { throw new BitsyException(BitsyErrorCodes.ERROR_INITIALIZING_DB_FILES, "File: " + toOpen, e); } } - + private void prepareForAppend(CommittableFileLog cfl) { if (cfl.getCounter() == null) { // An empty file. Need to write the header first @@ -436,7 +475,7 @@ private void prepareForAppend(CommittableFileLog cfl) { cfl.openForAppend(); } } - + @Override public VertexBean getVertex(UUID id) { return memStore.getVertex(id); @@ -464,22 +503,23 @@ public List getEdges(UUID vertexId, Direction dir, String[] edgeLabels @Override public void commit(ICommitChanges changes) { - if ((changes.getVertexChanges().size() == 0) && (changes.getEdgeChanges().size() == 0)) { + if ((changes.getVertexChanges().size() == 0) + && (changes.getEdgeChanges().size() == 0)) { return; } // Phase I: Serialize the objects to make sure that they can go into the file TxUnit txw; - StringWriter lineOutput = new StringWriter(); // Reused for vertex and edge lines + StringWriter lineOutput = new StringWriter(); // Reused for vertex and edge lines try { StringWriter vWriter = new StringWriter(); for (BitsyVertex v : changes.getVertexChanges()) { // Increment the version before the commit v.incrementVersion(); - + VertexBeanJson vBean = v.asJsonBean(); - //vWriter.write(Record.generateDBLine(RecordType.V, mapper.writeValueAsString(vBean))); - + // vWriter.write(Record.generateDBLine(RecordType.V, mapper.writeValueAsString(vBean))); + Record.generateVertexLine(lineOutput, mapper, vBean); vWriter.write(lineOutput.toString()); } @@ -490,17 +530,18 @@ public void commit(ICommitChanges changes) { e.incrementVersion(); EdgeBeanJson eBean = e.asJsonBean(); - //eWriter.write(Record.generateDBLine(RecordType.E, mapper.writeValueAsString(eBean))); - + // eWriter.write(Record.generateDBLine(RecordType.E, mapper.writeValueAsString(eBean))); + Record.generateEdgeLine(lineOutput, mapper, eBean); eWriter.write(lineOutput.toString()); } byte[] vBytes = vWriter.getBuffer().toString().getBytes(utf8); byte[] eBytes = eWriter.getBuffer().toString().getBytes(utf8); - - // Transaction boundary. Has a random integer and its hashcode to verify end of Tx. - byte[] tBytes = Record.generateDBLine(RecordType.T, "" + rand.nextInt()).getBytes(utf8); + + // Transaction boundary. Has a random integer and its hashcode to verify end of Tx. + byte[] tBytes = + Record.generateDBLine(RecordType.T, "" + rand.nextInt()).getBytes(utf8); txw = new TxUnit(ByteBuffer.wrap(vBytes), ByteBuffer.wrap(eBytes), ByteBuffer.wrap(tBytes)); } catch (JsonProcessingException e) { @@ -508,11 +549,11 @@ public void commit(ICommitChanges changes) { } catch (IOException e) { throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Unable to serialize to StringBuffer", e); } - + // Phase II: Update the memory store and push the commits to the double - // buffer. The write-lock inside the commit() is active during the call to - // add the transaction to the buffer. This ensures that the transactions - // are written in the same order as they enter the memory store. + // buffer. The write-lock inside the commit() is active during the call to + // add the transaction to the buffer. This ensures that the transactions + // are written in the same order as they enter the memory store. final TxUnit txwf = txw; // Note that the memory store reject the transaction by throwing an exception, such as BitsyRetryException @@ -527,30 +568,33 @@ public void run() { try { txw.getCountDownLatch().await(); } catch (InterruptedException e) { - BitsyException toThrow = new BitsyException(BitsyErrorCodes.TRANSACTION_INTERRUPTED, "Exception while waiting for transaction log to commit", e); - + BitsyException toThrow = new BitsyException( + BitsyErrorCodes.TRANSACTION_INTERRUPTED, + "Exception while waiting for transaction log to commit", + e); + log.error("Error while committing transaction", toThrow); - + throw toThrow; } - + BitsyException toThrow = txw.getException(); if (toThrow != null) { throw toThrow; } } - + /** This method flushes the transaction log to the V/E text files */ public void flushTxLog() { synchronized (flushCompleteSignal) { BufferName enqueueBuffer; synchronized (txLogToVEBuf.getPot()) { // Enqueue the backup task - enqueueBuffer = txLogToVEBuf.getEnqueueBuffer(); + enqueueBuffer = txLogToVEBuf.getEnqueueBuffer(); FlushNowJob flushJob = new FlushNowJob(); txLogToVEBuf.addAndExecuteWork(flushJob); } - + try { do { log.debug("Waiting for flush to complete in buffer {}", enqueueBuffer); @@ -558,18 +602,21 @@ public void flushTxLog() { log.debug("Flush complete in buffer {}", lastFlushedBuffer); } while (lastFlushedBuffer != enqueueBuffer); } catch (InterruptedException e) { - BitsyException toThrow = new BitsyException(BitsyErrorCodes.FLUSH_INTERRUPTED, "Exception while waiting for a transaction-log flush to be performed", e); + BitsyException toThrow = new BitsyException( + BitsyErrorCodes.FLUSH_INTERRUPTED, + "Exception while waiting for a transaction-log flush to be performed", + e); log.error("Error while flushing the transaction log", toThrow); throw toThrow; } - } + } } - - /** This method backs up the database while it is still operational. Only one backup can be in progress at a time. - * - * @param backupDir directory to which the database must be backed up. + + /** This method backs up the database while it is still operational. Only one backup can be in progress at a time. + * + * @param backupDir directory to which the database must be backed up. */ public void backup(Path backupDir) { if (!backupInProgress.compareAndSet(false, true)) { @@ -579,7 +626,8 @@ public void backup(Path backupDir) { File backupDirFile = backupDir.toFile(); if (!backupDirFile.isDirectory()) { - throw new BitsyException(BitsyErrorCodes.BAD_BACKUP_PATH, "Expecting " + backupDir + " to be a folder"); + throw new BitsyException( + BitsyErrorCodes.BAD_BACKUP_PATH, "Expecting " + backupDir + " to be a folder"); } // Flush the transaction buffer @@ -588,18 +636,21 @@ public void backup(Path backupDir) { // Enqueue the backup task BackupJob backupJob = new BackupJob(backupDir); veReorgBuf.addAndExecuteWork(backupJob); - + // Wait for the response try { backupJob.getCountDownLatch().await(); } catch (InterruptedException e) { - BitsyException toThrow = new BitsyException(BitsyErrorCodes.BACKUP_INTERRUPTED, "Exception while waiting for a backup to be performed", e); - + BitsyException toThrow = new BitsyException( + BitsyErrorCodes.BACKUP_INTERRUPTED, + "Exception while waiting for a backup to be performed", + e); + log.error("Error while backing up the database", toThrow); - + throw toThrow; } - + BitsyException toThrow = backupJob.getException(); if (toThrow != null) { throw toThrow; @@ -609,21 +660,20 @@ public void backup(Path backupDir) { } } } - - /** This class represents a "flush-now" action on the transaction log */ - public class FlushNowJob implements ITxBatchJob { - } - + /** This class represents a "flush-now" action on the transaction log */ + public class FlushNowJob implements ITxBatchJob {} + /** This class handles the flushing of the Memory to TxLog double buffer */ public class TxUnitFlusher implements BufferFlusher { @Override - public void flushBuffer(BufferName bufName, final List workList) throws BitsyException, InterruptedException { - // Queue the batch of transactions into the transaction log + public void flushBuffer(BufferName bufName, final List workList) + throws BitsyException, InterruptedException { + // Queue the batch of transactions into the transaction log txLogToVEBuf.addAndExecuteWork(new TxBatch(workList)); } } - + /** This class handles the queueing of the TxLog to VE files double buffer, which performs the actual work of the TxLogWriteFlusher */ public class TxBatchQueuer implements BufferQueuer { @Override @@ -633,7 +683,7 @@ public void onQueue(BufferName bufName, ITxBatchJob batchJob) throws BitsyExcept } else if (!(batchJob instanceof TxBatch)) { log.error("Unsupported type of work in TxLogFlushPotential: {}", batchJob.getClass()); } else { - TxBatch trans = (TxBatch)batchJob; + TxBatch trans = (TxBatch) batchJob; CommittableFileLog cfl = (bufName == BufferName.A) ? txA : txB; @@ -646,12 +696,12 @@ public void onQueue(BufferName bufName, ITxBatchJob batchJob) throws BitsyExcept size += work.writeToFile(cfl); } - // Force the contents into the TA/B file + // Force the contents into the TA/B file cfl.commit(); // Set the size to calculate potential trans.setSize(size); - + log.trace("Wrote {} bytes to {}", size, cfl.getPath()); } catch (BitsyException e) { bex = e; @@ -670,15 +720,15 @@ public void onQueue(BufferName bufName, ITxBatchJob batchJob) throws BitsyExcept } } } - + /** This class handles the flushing of TxLog to VE double buffer */ public class TxBatchFlusher implements BufferFlusher { @Override public void flushBuffer(BufferName bufName, List x) throws BitsyException { // Write the transaction log to the appropriate V/E files - CommittableFileLog txLogToFlush = (bufName == BufferName.A) ? txA : txB; + CommittableFileLog txLogToFlush = (bufName == BufferName.A) ? txA : txB; veReorgBuf.addAndExecuteWork(new TxLog(txLogToFlush)); - + synchronized (flushCompleteSignal) { // An explicit flush operation using flushTxLog() will wait for this signal lastFlushedBuffer = bufName; @@ -687,30 +737,31 @@ public void flushBuffer(BufferName bufName, List x) throws BitsyExc } } } - + /** This class handles the queueing of the TxLog to VE files double buffer, which performs the actual work of the TxLogWriteFlusher */ public class TxLogQueuer implements BufferQueuer { @Override public void onQueue(BufferName bufName, IVeReorgJob job) throws BitsyException { CommittableFileLog cflV = (bufName == BufferName.A) ? vA : vB; CommittableFileLog cflE = (bufName == BufferName.A) ? eA : eB; - + if (job instanceof TxLog) { // A transaction log must be flushed to V/E text files - TxLog txLog = (TxLog)job; + TxLog txLog = (TxLog) job; CommittableFileLog inputLog = txLog.getCommittableFileLog(); - CommittableFileLog otherTxLog = (inputLog == txA) ? txB : txA; + CommittableFileLog otherTxLog = (inputLog == txA) ? txB : txA; prepareForAppend(cflV); prepareForAppend(cflE); - inputLog.openForRead(); + inputLog.openForRead(); // Move and compact the transaction log into the vertex and edge logs Long nextTxCounter = otherTxLog.getCounter(); assert nextTxCounter != null; - CompactAndCopyTask cp = new CompactAndCopyTask(new CommittableFileLog[] {inputLog}, cflV, cflE, memStore, nextTxCounter); + CompactAndCopyTask cp = new CompactAndCopyTask( + new CommittableFileLog[] {inputLog}, cflV, cflE, memStore, nextTxCounter); cp.run(); log.debug("Done writing to: {} of size {}", cflV.getPath(), cflV.size()); @@ -721,10 +772,10 @@ public void onQueue(BufferName bufName, IVeReorgJob job) throws BitsyException { // Zap the txLog for the next flush log.debug("Zapping transaction log {}", inputLog); inputLog.openForOverwrite(logCounter++); - + } else if (job instanceof BackupJob) { // A backup of V/E text files must be performed - BackupJob backupJob = (BackupJob)job; + BackupJob backupJob = (BackupJob) job; Path backupDir = backupJob.getBackupDir(); try { @@ -733,17 +784,17 @@ public void onQueue(BufferName bufName, IVeReorgJob job) throws BitsyException { CommittableFileLog cflOutA = new CommittableFileLog(backupDir.resolve(Paths.get(TX_A_TXT)), true); cflOutA.openForOverwrite(txACounter); cflOutA.close(); - + Long txBCounter = txB.getCounter(); CommittableFileLog cflOutB = new CommittableFileLog(backupDir.resolve(Paths.get(TX_B_TXT)), true); cflOutB.openForOverwrite(txBCounter); cflOutB.close(); - + // 2. Copy V?.txt to VA.txt cflV.close(); Path sourceV = cflV.getPath(); Path targetV = backupDir.resolve(Paths.get(V_A_TXT)); - + log.debug("Copying {} to {}", sourceV, targetV); Files.copy(sourceV, targetV, StandardCopyOption.REPLACE_EXISTING); @@ -751,7 +802,7 @@ public void onQueue(BufferName bufName, IVeReorgJob job) throws BitsyException { cflE.close(); Path sourceE = cflE.getPath(); Path targetE = backupDir.resolve(Paths.get(E_A_TXT)); - + log.debug("Copying {} to {}", sourceE, targetE); Files.copy(sourceE, targetE, StandardCopyOption.REPLACE_EXISTING); @@ -767,16 +818,19 @@ public void onQueue(BufferName bufName, IVeReorgJob job) throws BitsyException { Files.copy(sourceM, targetM, StandardCopyOption.REPLACE_EXISTING); } } catch (Exception e) { - backupJob.setException(new BitsyException(BitsyErrorCodes.BACKUP_FAILED, "Encountered exception while backing up the database to " + backupDir, e)); + backupJob.setException(new BitsyException( + BitsyErrorCodes.BACKUP_FAILED, + "Encountered exception while backing up the database to " + backupDir, + e)); } finally { backupJob.getCountDownLatch().countDown(); } - + log.info("Completed backup to directory {}", backupDir); } } } - + /** This class handles the reorganization of the V and E A/B files */ public class TxLogFlusher implements BufferFlusher { @Override @@ -787,23 +841,29 @@ public void flushBuffer(BufferName bufName, List x) throws BitsyExc CommittableFileLog targetV = (bufName == BufferName.B) ? vA : vB; CommittableFileLog targetE = (bufName == BufferName.B) ? eA : eB; - log.debug("Re-organizing {} and {} into {} and {} respectively", sourceV.getPath(), sourceE.getPath(), targetV.getPath(), targetE.getPath()); - + log.debug( + "Re-organizing {} and {} into {} and {} respectively", + sourceV.getPath(), + sourceE.getPath(), + targetV.getPath(), + targetE.getPath()); + // Open the source files for reading sourceV.openForRead(); sourceE.openForRead(); - + // Clear the target files and set the proper counter in the header targetV.openForOverwrite(logCounter++); targetE.openForOverwrite(logCounter++); - + // Find the lesser of the two counters -- synchronization is not // needed because tx logs can't be flushed in the middle of a re-org Long nextTxCounter = getEarlierBuffer(txA, txB).getCounter(); assert (nextTxCounter != null); - + // Move and compact the source V/E files into the target V/E files - CompactAndCopyTask cp = new CompactAndCopyTask(new CommittableFileLog[] {sourceV, sourceE}, targetV, targetE, memStore, nextTxCounter); + CompactAndCopyTask cp = new CompactAndCopyTask( + new CommittableFileLog[] {sourceV, sourceE}, targetV, targetE, memStore, nextTxCounter); cp.run(); log.debug("Done writing to: {}. Post-reorg size {}", targetV.getPath(), targetV.size()); @@ -817,8 +877,8 @@ public void flushBuffer(BufferName bufName, List x) throws BitsyExc veReorgPotential.setOrigLines(cp.getOutputLines()); } - } - + } + @Override public Collection getAllVertices() { return memStore.getAllVertices(); @@ -832,7 +892,7 @@ public Collection getAllEdges() { @Override public synchronized void createKeyIndex(String key, Class elementType) { memStore.createKeyIndex(key, elementType); - + // Rewrite the metadata file -- all metadata file ops are synchronized on the mA object synchronized (mA) { saveVersionAndIndexes(); diff --git a/src/main/java/com/lambdazen/bitsy/store/ITxBatchJob.java b/src/main/java/com/lambdazen/bitsy/store/ITxBatchJob.java index 44a33b4..54dafbd 100644 --- a/src/main/java/com/lambdazen/bitsy/store/ITxBatchJob.java +++ b/src/main/java/com/lambdazen/bitsy/store/ITxBatchJob.java @@ -1,5 +1,3 @@ package com.lambdazen.bitsy.store; -public interface ITxBatchJob { - -} +public interface ITxBatchJob {} diff --git a/src/main/java/com/lambdazen/bitsy/store/IVeReorgJob.java b/src/main/java/com/lambdazen/bitsy/store/IVeReorgJob.java index 4b73ccb..3a61910 100644 --- a/src/main/java/com/lambdazen/bitsy/store/IVeReorgJob.java +++ b/src/main/java/com/lambdazen/bitsy/store/IVeReorgJob.java @@ -1,5 +1,3 @@ package com.lambdazen.bitsy.store; -public interface IVeReorgJob { - -} +public interface IVeReorgJob {} diff --git a/src/main/java/com/lambdazen/bitsy/store/IndexBean.java b/src/main/java/com/lambdazen/bitsy/store/IndexBean.java index 278d587..4bb31d1 100644 --- a/src/main/java/com/lambdazen/bitsy/store/IndexBean.java +++ b/src/main/java/com/lambdazen/bitsy/store/IndexBean.java @@ -1,38 +1,35 @@ package com.lambdazen.bitsy.store; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; - import com.lambdazen.bitsy.BitsyErrorCodes; import com.lambdazen.bitsy.BitsyException; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; @JsonPropertyOrder({"type", "key"}) public class IndexBean { int type; String key; - + @JsonCreator - public IndexBean(@JsonProperty("type") int type, - @JsonProperty("key") String key) { + public IndexBean(@JsonProperty("type") int type, @JsonProperty("key") String key) { this.type = type; - this.key = key; + this.key = key; } - + @JsonProperty("type") public int getType() { return type; } - + @JsonProperty("key") public String getKey() { return key; } - + @JsonIgnore public Class getIndexClass() { if (type == 0) { diff --git a/src/main/java/com/lambdazen/bitsy/store/JobWithCountDownLatch.java b/src/main/java/com/lambdazen/bitsy/store/JobWithCountDownLatch.java index 6573415..cd3d009 100644 --- a/src/main/java/com/lambdazen/bitsy/store/JobWithCountDownLatch.java +++ b/src/main/java/com/lambdazen/bitsy/store/JobWithCountDownLatch.java @@ -4,11 +4,11 @@ public class JobWithCountDownLatch { CountDownLatch cdl; - + public JobWithCountDownLatch() { this.cdl = new CountDownLatch(1); } - + public CountDownLatch getCountDownLatch() { return cdl; } diff --git a/src/main/java/com/lambdazen/bitsy/store/LoadTask.java b/src/main/java/com/lambdazen/bitsy/store/LoadTask.java index 75934b7..a1c7adf 100644 --- a/src/main/java/com/lambdazen/bitsy/store/LoadTask.java +++ b/src/main/java/com/lambdazen/bitsy/store/LoadTask.java @@ -1,8 +1,5 @@ package com.lambdazen.bitsy.store; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.lambdazen.bitsy.BitsyEdge; @@ -12,6 +9,8 @@ import com.lambdazen.bitsy.store.Record.RecordType; import com.lambdazen.bitsy.util.CommittableFileLog; import com.lambdazen.bitsy.util.DefaultCommitChanges; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class loads a list of input files to an (empty) graph store, which is @@ -21,8 +20,8 @@ public class LoadTask implements Runnable { private static final Logger log = LoggerFactory.getLogger(LoadTask.class); /** Files larger than this setting (default 1MB) will use parallel record reader. Can be changed by the application */ - public static long MIN_SIZE_FOR_PARALLEL_LOADER = 1024 * 1024; - + public static long MIN_SIZE_FOR_PARALLEL_LOADER = 1024 * 1024; + CommittableFileLog[] inputs; MemoryGraphStore store; long totalVE; @@ -30,8 +29,13 @@ public class LoadTask implements Runnable { ObjectMapper mapper; ObjectReader vReader, eReader; boolean repairMode; - - public LoadTask(CommittableFileLog[] inputs, MemoryGraphStore store, int opsPerNonTxCommit, ObjectMapper mapper, boolean safeMode) { + + public LoadTask( + CommittableFileLog[] inputs, + MemoryGraphStore store, + int opsPerNonTxCommit, + ObjectMapper mapper, + boolean safeMode) { this.inputs = inputs; this.store = store; this.totalVE = 0; @@ -41,35 +45,35 @@ public LoadTask(CommittableFileLog[] inputs, MemoryGraphStore store, int opsPerN this.eReader = mapper.readerFor(EdgeBeanJson.class); this.repairMode = safeMode; } - + public long getTotalVE() { return totalVE; } public void run() { IStringCanonicalizer canonicalizer = new SingleThreadedStringCanonicalizer(); - + // Find the minimum counter among transaction logs which marks the end of an incomplete V/E txt file long lastTxLogNumber = Long.MAX_VALUE; - for (int i=0; i < inputs.length; i++) { + for (int i = 0; i < inputs.length; i++) { inputs[i].openForRead(); if (inputs[i].isTxLog() && (lastTxLogNumber > inputs[i].getCounter())) { lastTxLogNumber = inputs[i].getCounter().longValue(); } } - + // Loop through files and load them BitsyException toThrow = null; - for (int i=0; i < inputs.length; i++) { + for (int i = 0; i < inputs.length; i++) { CommittableFileLog inputLog = inputs[i]; - + String fileName = inputLog.getPath().toString(); - int lineNo = 1; // Start with 1 because the header is the counter + int lineNo = 1; // Start with 1 because the header is the counter boolean isTxLog = inputLog.isTxLog(); - + RecordReader recordReader; - boolean usingSerialLoader; + boolean usingSerialLoader; if (repairMode || isTxLog || (inputLog.size() < MIN_SIZE_FOR_PARALLEL_LOADER)) { log.debug("Using RecordReader for {}", inputLog); recordReader = new RecordReader(inputLog, vReader, eReader); @@ -79,17 +83,18 @@ public void run() { recordReader = new ParallelRecordReader(inputLog, 10000, vReader, eReader); usingSerialLoader = false; } - + DefaultCommitChanges cc = new DefaultCommitChanges(); try { Record rec; while ((rec = recordReader.next()) != null) { - //log.debug("Loading line: {}", rec.getJson()); + // log.debug("Loading line: {}", rec.getJson()); lineNo++; - + // Logic to commit if (isTxLog) { - // Commit only on Tx records. This is to ensure that the last bad Tx (if one exists) doesn't get loaded + // Commit only on Tx records. This is to ensure that the last bad Tx (if one exists) doesn't get + // loaded if (rec.getType() == RecordType.T) { // Keep track of this line in case we run into an error later if (usingSerialLoader) { @@ -103,79 +108,94 @@ public void run() { // Process the next line in the while loop continue; - } + } } - // Insert/update V and E records + // Insert/update V and E records switch (rec.getType()) { - case L: - // This only happens for non-transactional logs - if (isTxLog) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Found an unexpected log (L) record in file " + fileName + " at line " + lineNo); - } - - // If the record matches the last Tx, it must be truncated now. - if (Long.parseLong(rec.getJson()) == lastTxLogNumber) { - // Mark the L record's end to truncate - if (usingSerialLoader) { - inputLog.mark(); + case L: + // This only happens for non-transactional logs + if (isTxLog) { + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Found an unexpected log (L) record in file " + fileName + " at line " + + lineNo); + } + + // If the record matches the last Tx, it must be truncated now. + if (Long.parseLong(rec.getJson()) == lastTxLogNumber) { + // Mark the L record's end to truncate + if (usingSerialLoader) { + inputLog.mark(); + } + + // Check to see if this is the last line -- otherwise, the file must be truncated here + if (recordReader.next() == null) { + // All OK + continue; + } else { + // And throw an exception to trigger the truncate + throw new BitsyException( + BitsyErrorCodes.INCOMPLETE_TX_FLUSH, + "File " + inputLog + " has an L record in line " + lineNo + + " with the last valid Tx log number " + lastTxLogNumber); + } } - - // Check to see if this is the last line -- otherwise, the file must be truncated here - if (recordReader.next() == null) { - // All OK - continue; + break; + + case T: + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Found an unexpected transaction (T) record in file " + fileName + " at line " + + lineNo); + + case E: + BitsyEdge edge = rec.getEdge(); + if (isTxLog) { + // Add to commit log + cc.changeEdge(edge); } else { - // And throw an exception to trigger the truncate - throw new BitsyException(BitsyErrorCodes.INCOMPLETE_TX_FLUSH, "File " + inputLog + " has an L record in line " + lineNo + " with the last valid Tx log number " + lastTxLogNumber); + // Directly save into the store + totalVE = store.saveEdge(totalVE, edge, canonicalizer); } - } - break; - - case T: - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Found an unexpected transaction (T) record in file " + fileName + " at line " + lineNo); - - case E: - BitsyEdge edge = rec.getEdge(); - if (isTxLog) { - // Add to commit log - cc.changeEdge(edge); - } else { - // Directly save into the store - totalVE = store.saveEdge(totalVE, edge, canonicalizer); - } - break; - - case V: - BitsyVertex vertex = rec.getVertex(); - if (isTxLog) { - // Add to commit log - cc.changeVertex(vertex); - } else { - // Directly save into the store - totalVE = store.saveVertex(totalVE, vertex, canonicalizer); - } - break; + break; + + case V: + BitsyVertex vertex = rec.getVertex(); + if (isTxLog) { + // Add to commit log + cc.changeVertex(vertex); + } else { + // Directly save into the store + totalVE = store.saveVertex(totalVE, vertex, canonicalizer); + } + break; - default: - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Unhandled record type " + rec.getType() + " in file " + fileName + " at line " + lineNo); + default: + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Unhandled record type " + rec.getType() + " in file " + fileName + " at line " + + lineNo); } } - // For Tx logs, rollback at the end (incomplete Tx). Otherwise commit. + // For Tx logs, rollback at the end (incomplete Tx). Otherwise commit. if (isTxLog) { // Throw away the commit changes int vCount = cc.getVertexChanges().size(); int eCount = cc.getEdgeChanges().size(); if ((vCount > 0) || (eCount > 0)) { assert isTxLog; - - log.warn("Throwing away {} vertices and {} edges that were not successfully committed", vCount, eCount); + + log.warn( + "Throwing away {} vertices and {} edges that were not successfully committed", + vCount, + eCount); if (inputLog.getMarkPosition() > 0) { inputLog.truncateAtMark(); } - + log.info("Recovery of {} is complete", fileName); } } else { @@ -186,7 +206,7 @@ public void run() { if (usingSerialLoader && isTxLog) { // Fix the TX Log log.warn("Recovering from exception while loading from file " + fileName + " at line " + lineNo, e); - + if (inputLog.getMarkPosition() == -1) { inputLog.openForOverwrite(inputLog.getCounter()); log.warn("Zapped file {} to recover from error", fileName); @@ -196,26 +216,31 @@ public void run() { } log.info("Recovery of {} is complete", fileName); - + // Since this is the last file, we can return return; } - - if (usingSerialLoader && (e instanceof BitsyException) && (((BitsyException)e).getErrorCode() == BitsyErrorCodes.INCOMPLETE_TX_FLUSH)) { + + if (usingSerialLoader + && (e instanceof BitsyException) + && (((BitsyException) e).getErrorCode() == BitsyErrorCodes.INCOMPLETE_TX_FLUSH)) { // Fix the V/E log - assert !isTxLog: "Only loading V/E logs can throw INCOMPLETE_TX_FLUSH exception"; - + assert !isTxLog : "Only loading V/E logs can throw INCOMPLETE_TX_FLUSH exception"; + log.warn("Recovering from an incomplete flush operation from a transactional log", e); // A Tx flush was not complete inputLog.truncateAtMark(); - + log.info("Recovery of {} is complete", fileName); - + // Continue to the next file in the for loop } else { // Unrecoverable exception - toThrow = new BitsyException(BitsyErrorCodes.DATABASE_IS_CORRUPT, "The database files are corrupt. Please restore a backup version", e); + toThrow = new BitsyException( + BitsyErrorCodes.DATABASE_IS_CORRUPT, + "The database files are corrupt. Please restore a backup version", + e); if (repairMode) { log.error("Encountered an unrecoverable exception while loading the database", toThrow); @@ -234,7 +259,7 @@ public void run() { } } } - + if (toThrow != null) { throw toThrow; } diff --git a/src/main/java/com/lambdazen/bitsy/store/MemoryGraphStore.java b/src/main/java/com/lambdazen/bitsy/store/MemoryGraphStore.java index d6bafac..e97a4ef 100644 --- a/src/main/java/com/lambdazen/bitsy/store/MemoryGraphStore.java +++ b/src/main/java/com/lambdazen/bitsy/store/MemoryGraphStore.java @@ -1,19 +1,5 @@ package com.lambdazen.bitsy.store; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.tinkerpop.gremlin.structure.Direction; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Element; -import org.apache.tinkerpop.gremlin.structure.Vertex; - import com.lambdazen.bitsy.BitsyEdge; import com.lambdazen.bitsy.BitsyErrorCodes; import com.lambdazen.bitsy.BitsyException; @@ -27,21 +13,34 @@ import com.lambdazen.bitsy.index.EdgeIndexMap; import com.lambdazen.bitsy.index.VertexIndexMap; import com.lambdazen.bitsy.tx.BitsyTransaction; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Vertex; /** * This class implements a MapDB-backed store for a graph, along with its key * indexes. */ public class MemoryGraphStore implements IGraphStore { -// private static final Logger log = LoggerFactory.getLogger(MemoryGraphStore.class); + // private static final Logger log = LoggerFactory.getLogger(MemoryGraphStore.class); - private static final int MAX_COUNTER_INCREASE_BEFORE_READ_LOCK = 2 * 5; // After 5 writes go through, the reader will lock + private static final int MAX_COUNTER_INCREASE_BEFORE_READ_LOCK = + 2 * 5; // After 5 writes go through, the reader will lock private static final int MAX_RETRIES_BEFORE_READ_LOCK = 3; // After 3 writes go through, the reader will lock private ReadWriteLock rwLock; - + private AtomicLong spinCounter; - + private Map vertices; // Map from VertexBean.getUUID().hashCode() -> VertexBean @@ -96,7 +95,7 @@ public void commit(ICommitChanges changes, boolean incrementVersions, Runnable r checkForConcurrentModifications(changes, incrementVersions); saveChanges(changes); - + if (r != null) { r.run(); } @@ -107,32 +106,32 @@ public void commit(ICommitChanges changes, boolean incrementVersions, Runnable r private void beginWrite() { rwLock.writeLock().lock(); - + // There is a possibility that the counter is odd. This happens when a // writer thread is done unlocking, but not done incrementing the // counter. Calling beginRead() ensures that the counter is even RetryDetails retryDetails = new RetryDetails(); beginRead(retryDetails, false); - + assert (retryDetails.counter & 1L) == 0L : "Bug in beginRead -- counter is odd!"; // must be even long newCounter = (retryDetails.counter + 1) & 0x3fffffffffffffffL; // Don't let it go negative - + boolean updated = spinCounter.compareAndSet(retryDetails.counter, newCounter); assert updated : "Someone messed with an even counter without a lock!"; } - + private void endWrite() { // Unlock first -- this creates the synchronization barrier ensuring - // that all writes are visible to readers + // that all writes are visible to readers rwLock.writeLock().unlock(); // Now increment the counter allowing readers & writers to proceed // At this point -- both readers and writers will wait till the counter - // turns even + // turns even long counter = spinCounter.get(); assert (counter & 1L) == 1L : "Some writer did not leave the counter odd!"; // must be odd long newCounter = (counter + 1) & 0x3fffffffffffffffL; // Don't let it go negative - + boolean updated = spinCounter.compareAndSet(counter, newCounter); assert updated : "Someone messed with the counter without a lock!"; } @@ -145,31 +144,31 @@ private void beginRead(RetryDetails retryDetails, boolean degradeToReadLock) { long tryCount = retryDetails.counter - retryDetails.startCounter; // The counter is odd -- which means that a write is in process - if (degradeToReadLock + if (degradeToReadLock && ((tryCount > MAX_COUNTER_INCREASE_BEFORE_READ_LOCK) - || (retryDetails.retryCount > MAX_RETRIES_BEFORE_READ_LOCK)) ) { + || (retryDetails.retryCount > MAX_RETRIES_BEFORE_READ_LOCK))) { rwLock.readLock().lock(); - + retryDetails.counter = -1; return; } - + // No work left for this thread Thread.yield(); - + // Try again retryDetails.counter = spinCounter.get(); } - - assert((retryDetails.counter & 1L) == 0L); + + assert ((retryDetails.counter & 1L) == 0L); } - + private void endRead(RetryDetails retryDetails) { if (retryDetails.counter == -1) { rwLock.readLock().unlock(); } } - + private boolean shouldRetryRead(RetryDetails retryDetails) { // Retry if there is no read lock AND the counter doesn't match if (retryDetails.counter == -1) { @@ -198,16 +197,18 @@ private void checkForConcurrentModifications(ICommitChanges changes, boolean inc UUID key = (UUID) vertex.id(); switch (vertex.getState()) { - case U: - break; - - case D: - case M: - VertexBean vb = vertices.get(key); - if (vb != null && (vb.getVersion() + 1 != vertex.getVersion())) { - throw new BitsyRetryException(BitsyErrorCodes.CONCURRENT_MODIFICATION, "Vertex " + key + " was modified. Loaded version " - + (vertex.getVersion() - 1) + ". Current version in DB: " + vb.getVersion()); - } + case U: + break; + + case D: + case M: + VertexBean vb = vertices.get(key); + if (vb != null && (vb.getVersion() + 1 != vertex.getVersion())) { + throw new BitsyRetryException( + BitsyErrorCodes.CONCURRENT_MODIFICATION, + "Vertex " + key + " was modified. Loaded version " + (vertex.getVersion() - 1) + + ". Current version in DB: " + vb.getVersion()); + } } } @@ -221,16 +222,18 @@ private void checkForConcurrentModifications(ICommitChanges changes, boolean inc UUID key = (UUID) edge.id(); switch (edge.getState()) { - case U: - break; - - case D: - case M: - EdgeBean eb = edges.get(key); - if (eb != null && (eb.getVersion() + 1) != edge.getVersion()) { - throw new BitsyRetryException(BitsyErrorCodes.CONCURRENT_MODIFICATION, "Edge " + key + " was modified. Loaded version " - + (edge.getVersion() - 1) + ". Current version in DB: " + eb.getVersion()); - } + case U: + break; + + case D: + case M: + EdgeBean eb = edges.get(key); + if (eb != null && (eb.getVersion() + 1) != edge.getVersion()) { + throw new BitsyRetryException( + BitsyErrorCodes.CONCURRENT_MODIFICATION, + "Edge " + key + " was modified. Loaded version " + (edge.getVersion() - 1) + + ". Current version in DB: " + eb.getVersion()); + } } } } @@ -238,7 +241,7 @@ private void checkForConcurrentModifications(ICommitChanges changes, boolean inc protected long saveChanges(ICommitChanges changes) { return saveChanges(changes, null); } - + // This method is used by commit (with increment option) and the initial // load from DB (without increment option) protected long saveChanges(ICommitChanges changes, IStringCanonicalizer canonicalizer) { @@ -261,44 +264,44 @@ protected long saveEdge(long addedVE, BitsyEdge edge, IStringCanonicalizer canon UUID key = (UUID) edge.id(); switch (edge.getState()) { - case U: - break; + case U: + break; - case D: - eIndexMap.remove(edges.get(key)); - //log.debug("Removing edge {}", edge.getId()); + case D: + eIndexMap.remove(edges.get(key)); + // log.debug("Removing edge {}", edge.getId()); - // Remove this edge from incoming and outgoing vertices - EdgeBean eBeanToRemove = edges.remove(key); - adjMap.removeEdgeWithoutCallback(eBeanToRemove); - addedVE--; + // Remove this edge from incoming and outgoing vertices + EdgeBean eBeanToRemove = edges.remove(key); + adjMap.removeEdgeWithoutCallback(eBeanToRemove); + addedVE--; - break; + break; - case M: - EdgeBean eBean = (canonicalizer == null) ? asBean(edge) : asBean(edge, canonicalizer); - if (eBean == null) { - //log.debug("Skipping edge {}", edge.getId()); - } else { - //log.debug("Modifying edge {}", edge.getId()); - EdgeBean oldEBean = edges.get(key); - eIndexMap.remove(oldEBean); - eIndexMap.add(eBean); - - EdgeBean oldEBean2 = edges.put(eBean, eBean); - - // NOTE: Because this is a write operation, there is an - // exclusive lock -- no one else is updating eIndexMap - assert (oldEBean == oldEBean2); - - if (oldEBean != null) { - adjMap.removeEdgeWithoutCallback(oldEBean); // Don't callback + case M: + EdgeBean eBean = (canonicalizer == null) ? asBean(edge) : asBean(edge, canonicalizer); + if (eBean == null) { + // log.debug("Skipping edge {}", edge.getId()); } else { - addedVE++; + // log.debug("Modifying edge {}", edge.getId()); + EdgeBean oldEBean = edges.get(key); + eIndexMap.remove(oldEBean); + eIndexMap.add(eBean); + + EdgeBean oldEBean2 = edges.put(eBean, eBean); + + // NOTE: Because this is a write operation, there is an + // exclusive lock -- no one else is updating eIndexMap + assert (oldEBean == oldEBean2); + + if (oldEBean != null) { + adjMap.removeEdgeWithoutCallback(oldEBean); // Don't callback + } else { + addedVE++; + } + + adjMap.addEdge(eBean); } - - adjMap.addEdge(eBean); - } } return addedVE; } @@ -307,32 +310,32 @@ protected long saveVertex(long addedVE, BitsyVertex vertex, IStringCanonicalizer UUID key = (UUID) vertex.id(); switch (vertex.getState()) { - case U: - break; - - case D: - //log.debug("Deleting vertex {}", key); - vIndexMap.remove(vertices.get(key)); - VertexBean vBeanToRemove = vertices.remove(key); - adjMap.removeVertex(vBeanToRemove); - addedVE--; - - break; - - case M: - //log.debug("Updating vertex {}", key); - VertexBean vBean = (canonicalizer == null) ? vertex.asBean() : vertex.asBean(canonicalizer); - VertexBean oldVBean = vertices.get(key); - vIndexMap.remove(oldVBean); - - if (oldVBean == null) { - vertices.put(vBean, vBean); - vIndexMap.add(vBean); - addedVE++; - } else { - oldVBean.copyFrom(vBean); - vIndexMap.add(oldVBean); - } + case U: + break; + + case D: + // log.debug("Deleting vertex {}", key); + vIndexMap.remove(vertices.get(key)); + VertexBean vBeanToRemove = vertices.remove(key); + adjMap.removeVertex(vBeanToRemove); + addedVE--; + + break; + + case M: + // log.debug("Updating vertex {}", key); + VertexBean vBean = (canonicalizer == null) ? vertex.asBean() : vertex.asBean(canonicalizer); + VertexBean oldVBean = vertices.get(key); + vIndexMap.remove(oldVBean); + + if (oldVBean == null) { + vertices.put(vBean, vBean); + vIndexMap.add(vBean); + addedVE++; + } else { + oldVBean.copyFrom(vBean); + vIndexMap.add(oldVBean); + } } return addedVE; } @@ -345,7 +348,7 @@ public VertexBean getVertex(UUID id) { public EdgeBean getEdge(UUID id) { // This method is only for internal use - // Not using a read lock because the ID is available + // Not using a read lock because the ID is available return edges.get(id); } @@ -357,7 +360,7 @@ public BitsyVertex getBitsyVertex(BitsyTransaction tx, UUID id) { try { do { beginRead(retryDetails, true); - + VertexBean bean = getVertex(id); if (bean != null) { ans = new BitsyVertex(bean, tx, BitsyState.U); @@ -374,21 +377,21 @@ public BitsyVertex getBitsyVertex(BitsyTransaction tx, UUID id) { public BitsyEdge getBitsyEdge(BitsyTransaction tx, UUID id) { RetryDetails retryDetails = new RetryDetails(); BitsyEdge ans = null; - + try { do { beginRead(retryDetails, true); - + EdgeBean bean = getEdge(id); if (bean != null) { ans = new BitsyEdge(bean, tx, BitsyState.U); } - + } while (shouldRetryRead(retryDetails)); } finally { endRead(retryDetails); } - + return ans; } @@ -406,7 +409,7 @@ public List getEdges(UUID vertexId, Direction dir, String[] edgeLabels } finally { endRead(retryDetails); } - + return ans; } @@ -437,7 +440,8 @@ public void createKeyIndex(String key, Class elementType) } else if (elementType.equals(Edge.class)) { eIndexMap.createKeyIndex(key, getAllEdges().iterator()); } else { - throw new BitsyException(BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); + throw new BitsyException( + BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); } } finally { endWrite(); @@ -456,7 +460,8 @@ public void dropKeyIndex(String key, Class elementType) { } else if (elementType.equals(Edge.class)) { eIndexMap.dropKeyIndex(key); } else { - throw new BitsyException(BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); + throw new BitsyException( + BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); } } finally { endWrite(); @@ -476,7 +481,8 @@ public Set getIndexedKeys(Class elementType) { } else if (elementType.equals(Edge.class)) { return eIndexMap.getIndexedKeys(); } else { - throw new BitsyException(BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); + throw new BitsyException( + BitsyErrorCodes.UNSUPPORTED_INDEX_TYPE, "Encountered index type: " + elementType); } } finally { endWrite(); @@ -513,7 +519,7 @@ public Collection lookupEdges(String key, Object value) { } finally { endRead(retryDetails); } - + return ans; } @@ -521,43 +527,49 @@ public Collection lookupEdges(String key, Object value) { public void shutdown() { reset(); } - + // HELPER METHODS public EdgeBean asBean(BitsyEdge edge) { // The TX is usually not active at this point. So no checks. VertexBean outVertexBean = getVertex(edge.getOutVertexId()); VertexBean inVertexBean = getVertex(edge.getInVertexId()); - + if ((outVertexBean == null) || (inVertexBean == null)) { // The vertex has been deleted. return null; } else { assert (edge.getState() == BitsyState.M); - return new EdgeBean((UUID)edge.id(), edge.getPropertyDict(), edge.getVersion(), edge.label(), outVertexBean, inVertexBean); + return new EdgeBean( + (UUID) edge.id(), + edge.getPropertyDict(), + edge.getVersion(), + edge.label(), + outVertexBean, + inVertexBean); } } public EdgeBean asBean(BitsyEdge edge, IStringCanonicalizer canonicalizer) { EdgeBean ans = asBean(edge); - + if (ans != null) { // Canonicalize the label ans.label = (ans.label == null) ? null : canonicalizer.canonicalize(ans.label); } - + if (edge.getPropertyDict() != null) { edge.getPropertyDict().canonicalizeKeys(canonicalizer); } - + return ans; } - + // Retry details public class RetryDetails { long counter; long startCounter; int retryCount; - + public RetryDetails() { this.startCounter = spinCounter.get(); this.counter = startCounter; diff --git a/src/main/java/com/lambdazen/bitsy/store/ParallelRecordReader.java b/src/main/java/com/lambdazen/bitsy/store/ParallelRecordReader.java index 65df04c..17da464 100644 --- a/src/main/java/com/lambdazen/bitsy/store/ParallelRecordReader.java +++ b/src/main/java/com/lambdazen/bitsy/store/ParallelRecordReader.java @@ -1,5 +1,9 @@ package com.lambdazen.bitsy.store; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectReader; +import com.lambdazen.bitsy.BitsyException; +import com.lambdazen.bitsy.util.CommittableFileLog; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; @@ -8,20 +12,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectReader; -import com.lambdazen.bitsy.BitsyException; -import com.lambdazen.bitsy.util.CommittableFileLog; - public class ParallelRecordReader extends RecordReader { private static final Logger log = LoggerFactory.getLogger(ParallelRecordReader.class); - + public static int QUEUE_TO_PROCESSOR_RATIO = 3; - + private int numLinesPerBatch; private int numBatchInQueue; private int numProcessors; @@ -34,21 +32,22 @@ public class ParallelRecordReader extends RecordReader { private boolean stopped = false; private Iterator currentIterator; - - public ParallelRecordReader(CommittableFileLog cfl, int numLinesPerBatch, ObjectReader vReader, ObjectReader eReader) { + + public ParallelRecordReader( + CommittableFileLog cfl, int numLinesPerBatch, ObjectReader vReader, ObjectReader eReader) { super(cfl, vReader, eReader); - + this.numLinesPerBatch = numLinesPerBatch; - + this.numProcessors = Runtime.getRuntime().availableProcessors() - 1; // one to insert, read is not 100% busy if (numProcessors < 1) { this.numProcessors = 1; } else if (numProcessors > 4) { this.numProcessors = 4; // Don't need more than 4 threads } - + this.numBatchInQueue = QUEUE_TO_PROCESSOR_RATIO * numProcessors; - + this.producerService = Executors.newSingleThreadExecutor(); this.deserializerService = Executors.newFixedThreadPool(numProcessors); this.queue = new ArrayBlockingQueue(numBatchInQueue); @@ -56,7 +55,7 @@ public ParallelRecordReader(CommittableFileLog cfl, int numLinesPerBatch, Object // This keeps filling up the queue producerService.submit(new ProducerTask()); } - + public Record next() throws Exception { if ((currentIterator == null) || (!currentIterator.hasNext())) { // The current iterator is done. Need to get the next iterator @@ -64,26 +63,26 @@ public Record next() throws Exception { // Shutdown remaining services log.debug("Shutting down services"); shutdownServices(); - + return null; } - + // There should be more in the buffer Batch nextBatch = queue.take(); if (nextBatch.isLastBatch() || (nextBatch.getException() != null)) { // This boolean won't be used till the iterator is drained out isDone = true; - + if (nextBatch.getException() != null) { throw nextBatch.getException(); } } - + // Get the records, waiting for serialization if necessary currentIterator = nextBatch.getRecords().iterator(); } - + if (currentIterator.hasNext()) { return currentIterator.next(); } else { @@ -96,22 +95,22 @@ public Record next() throws Exception { private void shutdownServices() { if (producerService != null) { producerService.shutdown(); - producerService = null; + producerService = null; } - + if (deserializerService != null) { deserializerService.shutdown(); deserializerService = null; } } - + public class Batch { List lines = new ArrayList(numBatchInQueue); List records = new ArrayList(numBatchInQueue); boolean lastBatch = false; CountDownLatch cdl = new CountDownLatch(1); Exception exception; - + public Batch() { try { log.debug("Reading a new batch from {}", cfl.getPath()); @@ -121,7 +120,7 @@ public Batch() { count++; lines.add(line); - //log.debug("Read line: {}", line); + // log.debug("Read line: {}", line); if (count >= numLinesPerBatch) { return; @@ -135,11 +134,11 @@ public Batch() { exception = e; } } - + public boolean isLastBatch() { return lastBatch; } - + public void deserialize() throws JsonProcessingException, IOException { try { if (exception == null) { @@ -152,32 +151,32 @@ public void deserialize() throws JsonProcessingException, IOException { } } } finally { - // Don't hold up the next step irrespective of the exception + // Don't hold up the next step irrespective of the exception cdl.countDown(); } } - + public List getRecords() throws InterruptedException { // Wait if serialization is not complete cdl.await(); - - return records; + + return records; } public void setException(Exception e) { this.exception = e; } - + public Exception getException() { return exception; } } - + public class ProducerTask implements Runnable { public void run() { while (!stopped) { final Batch batch = new Batch(); - + // Add batch to the queue try { queue.put(batch); @@ -185,7 +184,7 @@ public void run() { log.error("Producer task has been interrupted", e); return; } - + // Schedule the serializer deserializerService.submit(new Runnable() { @Override @@ -197,7 +196,7 @@ public void run() { } } }); - + // Are we done yet? if (batch.isLastBatch()) { // Producer's work is done diff --git a/src/main/java/com/lambdazen/bitsy/store/Record.java b/src/main/java/com/lambdazen/bitsy/store/Record.java index 842e9f0..901da84 100644 --- a/src/main/java/com/lambdazen/bitsy/store/Record.java +++ b/src/main/java/com/lambdazen/bitsy/store/Record.java @@ -1,8 +1,5 @@ package com.lambdazen.bitsy.store; -import java.io.IOException; -import java.io.StringWriter; - import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonParser; @@ -17,24 +14,30 @@ import com.lambdazen.bitsy.BitsyVertex; import com.lambdazen.bitsy.IGraphStore; import com.lambdazen.bitsy.UUID; +import java.io.IOException; +import java.io.StringWriter; /** This class represents a line in a text file captured in the DB */ public class Record { private static final char[] HEX_CHAR_ARR = "0123456789abcdef".toCharArray(); public static final String newLine = "\n"; - //private static final ObjectMapper mapper = new ObjectMapper(); + // private static final ObjectMapper mapper = new ObjectMapper(); private static final JsonFactory factory = new JsonFactory(); - public static enum RecordType {H, // Header + public static enum RecordType { + H, // Header L, // Log marker V, // Vertex E, // Edges T, // Transaction I, // Index -- stored in meta?.txt files - M}; // Major version -- stored in meta?.txt files + M + }; // Major version -- stored in meta?.txt files private static final char[] recordChars = new char[] {'H', 'L', 'V', 'E', 'T', 'I', 'M'}; - private static final RecordType[] recordTypes = new RecordType[] {RecordType.H, RecordType.L, RecordType.V, RecordType.E, RecordType.T, RecordType.I, RecordType.M}; + private static final RecordType[] recordTypes = new RecordType[] { + RecordType.H, RecordType.L, RecordType.V, RecordType.E, RecordType.T, RecordType.I, RecordType.M + }; private static final int numRecChars = recordChars.length; RecordType type; @@ -47,8 +50,8 @@ public static enum RecordType {H, // Header public static int hashCode(String str) { if (!IS_ANDROID) { - // Backward compatible for non-Android systems - return str.hashCode(); + // Backward compatible for non-Android systems + return str.hashCode(); } else { return ANDROID_EOR; } @@ -80,7 +83,8 @@ public String getJson() { } // Efficient method to write a vertex -- avoids writeValueAsString - public static void generateVertexLine(StringWriter sw, ObjectMapper mapper, VertexBean vBean) throws JsonGenerationException, JsonMappingException, IOException { + public static void generateVertexLine(StringWriter sw, ObjectMapper mapper, VertexBean vBean) + throws JsonGenerationException, JsonMappingException, IOException { sw.getBuffer().setLength(0); sw.append('V'); // Record type @@ -96,7 +100,8 @@ public static void generateVertexLine(StringWriter sw, ObjectMapper mapper, Vert } // Efficient method to write an edge -- avoids writeValueAsString - public static void generateEdgeLine(StringWriter sw, ObjectMapper mapper, EdgeBean eBean) throws JsonGenerationException, JsonMappingException, IOException { + public static void generateEdgeLine(StringWriter sw, ObjectMapper mapper, EdgeBean eBean) + throws JsonGenerationException, JsonMappingException, IOException { sw.getBuffer().setLength(0); sw.append('E'); // Record type @@ -121,13 +126,20 @@ public static String generateDBLine(RecordType type, String line) { public static Record parseRecord(String dbLine, int lineNo, String fileName) { int hashPos = dbLine.lastIndexOf('#'); if (hashPos < 0) { - throw new BitsyException(BitsyErrorCodes.CHECKSUM_MISMATCH, "Line " + lineNo + " in file " + fileName + " has no hash-code. Encountered " + dbLine); + throw new BitsyException( + BitsyErrorCodes.CHECKSUM_MISMATCH, + "Line " + lineNo + " in file " + fileName + " has no hash-code. Encountered " + dbLine); } else { String hashCode = dbLine.substring(hashPos + 1); String expHashCode = toHex(hashCode(dbLine.substring(0, hashPos + 1))); - if ((hashCode == null) || !hashCode.trim().equals(expHashCode)) { // TODO: Currently DB is not portable between Android and Java - throw new BitsyException(BitsyErrorCodes.CHECKSUM_MISMATCH, "Line " + lineNo + " in file " + fileName + " has the wrong hash-code " + hashCode + ". Expected " + expHashCode); + if ((hashCode == null) + || !hashCode.trim() + .equals(expHashCode)) { // TODO: Currently DB is not portable between Android and Java + throw new BitsyException( + BitsyErrorCodes.CHECKSUM_MISMATCH, + "Line " + lineNo + " in file " + fileName + " has the wrong hash-code " + hashCode + + ". Expected " + expHashCode); } else { // All OK RecordType type = typeFromChar(dbLine.charAt(0)); @@ -139,7 +151,7 @@ public static Record parseRecord(String dbLine, int lineNo, String fileName) { // Faster than RecordType.valueof() private static RecordType typeFromChar(char recChar) { - for (int i=0; i < numRecChars; i++) { + for (int i = 0; i < numRecChars; i++) { if (recordChars[i] == recChar) { return recordTypes[i]; } @@ -151,9 +163,9 @@ private static RecordType typeFromChar(char recChar) { // Faster than Integer.toHexString() private static String toHex(int input) { final char[] sb = new char[8]; - final int len = (sb.length-1); + final int len = (sb.length - 1); for (int i = 0; i <= len; i++) { // MSB - sb[i] = HEX_CHAR_ARR[((int)(input >>> ((len - i)<<2))) & 0xF]; + sb[i] = HEX_CHAR_ARR[((int) (input >>> ((len - i) << 2))) & 0xF]; } return new String(sb); } @@ -204,9 +216,10 @@ public boolean checkObsolete(IGraphStore store, boolean isReorg, int lineNo, Str } } - if ((id == null) || (version == -1) || (state == null)) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Unable to parse record '" + json + "' in file " + fileName + " at line " + lineNo); + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Unable to parse record '" + json + "' in file " + fileName + " at line " + lineNo); } if (state.equals("D")) { @@ -242,7 +255,11 @@ public boolean checkObsolete(IGraphStore store, boolean isReorg, int lineNo, Str } } } catch (Exception e) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Possible bug in code. Error serializing line '" + json + "' in file " + fileName + " at line " + lineNo, e); + throw new BitsyException( + BitsyErrorCodes.INTERNAL_ERROR, + "Possible bug in code. Error serializing line '" + json + "' in file " + fileName + " at line " + + lineNo, + e); } } diff --git a/src/main/java/com/lambdazen/bitsy/store/RecordReader.java b/src/main/java/com/lambdazen/bitsy/store/RecordReader.java index 7d88090..9b1a23f 100644 --- a/src/main/java/com/lambdazen/bitsy/store/RecordReader.java +++ b/src/main/java/com/lambdazen/bitsy/store/RecordReader.java @@ -10,22 +10,22 @@ public class RecordReader { ObjectReader vReader; ObjectReader eReader; - + public RecordReader(CommittableFileLog cfl, ObjectReader vReader, ObjectReader eReader) { this.cfl = cfl; this.fileName = cfl.getPath().toString(); this.vReader = vReader; this.eReader = eReader; } - + public Record next() throws Exception { String line = cfl.readLine(); - + if (line == null) { return null; } else { lineNo++; - + Record ans = Record.parseRecord(line, lineNo, fileName); ans.deserialize(vReader, eReader); return ans; diff --git a/src/main/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizer.java b/src/main/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizer.java index 9d40ae9..f7e3df0 100644 --- a/src/main/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizer.java +++ b/src/main/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizer.java @@ -6,11 +6,11 @@ /* This class is not thread-safe */ public class SingleThreadedStringCanonicalizer implements IStringCanonicalizer { Map canonicalStrings; - + public SingleThreadedStringCanonicalizer() { canonicalStrings = new HashMap(); } - + public String canonicalize(String str) { String canonicalString = canonicalStrings.get(str); if (canonicalString != null) { diff --git a/src/main/java/com/lambdazen/bitsy/store/TxBatch.java b/src/main/java/com/lambdazen/bitsy/store/TxBatch.java index 25cd486..d080fb4 100644 --- a/src/main/java/com/lambdazen/bitsy/store/TxBatch.java +++ b/src/main/java/com/lambdazen/bitsy/store/TxBatch.java @@ -14,7 +14,7 @@ public TxBatch(List trans) { this.trans = trans; this.size = 0; } - + public List getTxUnitList() { return trans; } diff --git a/src/main/java/com/lambdazen/bitsy/store/TxLog.java b/src/main/java/com/lambdazen/bitsy/store/TxLog.java index 684a877..dad3e91 100644 --- a/src/main/java/com/lambdazen/bitsy/store/TxLog.java +++ b/src/main/java/com/lambdazen/bitsy/store/TxLog.java @@ -17,11 +17,11 @@ public TxLog(CommittableFileLog cfl) { public CommittableFileLog getCommittableFileLog() { return cfl; } - + public void setReorgPotDiff(int rpd) { this.rpd = rpd; } - + public int getReorgPotDiff() { return rpd; } diff --git a/src/main/java/com/lambdazen/bitsy/store/TxLogFlushPotential.java b/src/main/java/com/lambdazen/bitsy/store/TxLogFlushPotential.java index 6ee6ed8..c46ffb6 100644 --- a/src/main/java/com/lambdazen/bitsy/store/TxLogFlushPotential.java +++ b/src/main/java/com/lambdazen/bitsy/store/TxLogFlushPotential.java @@ -1,10 +1,9 @@ package com.lambdazen.bitsy.store; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore.FlushNowJob; import com.lambdazen.bitsy.util.BufferPotential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This potential function keeps track of the total bytes written to TA or @@ -13,16 +12,15 @@ */ public class TxLogFlushPotential implements BufferPotential { private static final Logger log = LoggerFactory.getLogger(TxLogFlushPotential.class); - + long txLogThreshold; long curBufSize; - + public TxLogFlushPotential(long txLogThreshold) { this.txLogThreshold = txLogThreshold; this.curBufSize = 0; } - - + public long getTxLogThreshold() { return txLogThreshold; } @@ -34,7 +32,7 @@ public void setTxLogThreshold(long txLogThreshold) { @Override public boolean addWork(ITxBatchJob newWork) { if (newWork instanceof TxBatch) { - curBufSize += ((TxBatch)newWork).getSize(); + curBufSize += ((TxBatch) newWork).getSize(); return (curBufSize > txLogThreshold); } else if (newWork instanceof FlushNowJob) { @@ -44,7 +42,7 @@ public boolean addWork(ITxBatchJob newWork) { } else { // Error has already been logged before log.debug("Unsupported type of work in TxLogFlushPotential: {}", newWork.getClass()); - + return false; } } diff --git a/src/main/java/com/lambdazen/bitsy/store/TxUnit.java b/src/main/java/com/lambdazen/bitsy/store/TxUnit.java index bab1284..0886b3f 100644 --- a/src/main/java/com/lambdazen/bitsy/store/TxUnit.java +++ b/src/main/java/com/lambdazen/bitsy/store/TxUnit.java @@ -1,9 +1,8 @@ package com.lambdazen.bitsy.store; -import java.nio.ByteBuffer; - import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.util.CommittableFileLog; +import java.nio.ByteBuffer; /** This class captures a transaction to be written to the TA/B transaction files */ public class TxUnit extends JobWithCountDownLatch { @@ -11,7 +10,7 @@ public class TxUnit extends JobWithCountDownLatch { ByteBuffer edges; ByteBuffer tx; BitsyException bex; - + public TxUnit(ByteBuffer vertices, ByteBuffer edges, ByteBuffer tx) { this.vertices = vertices; this.edges = edges; @@ -20,19 +19,19 @@ public TxUnit(ByteBuffer vertices, ByteBuffer edges, ByteBuffer tx) { public ByteBuffer getByteBufferForV() { vertices.position(0); - + return vertices; } public ByteBuffer getByteBufferForE() { edges.position(0); - + return edges; - } + } public ByteBuffer getByteBufferForT() { tx.position(0); - + return tx; } @@ -40,20 +39,20 @@ public int writeToFile(CommittableFileLog cfl) { ByteBuffer vbb = getByteBufferForV(); ByteBuffer ebb = getByteBufferForE(); ByteBuffer tbb = getByteBufferForT(); - + int size = vbb.remaining() + ebb.remaining() + tbb.remaining(); - + cfl.append(vbb); cfl.append(ebb); cfl.append(tbb); - + return size; } public BitsyException getException() { return bex; } - + public void setException(BitsyException bex) { this.bex = bex; } diff --git a/src/main/java/com/lambdazen/bitsy/store/VEObsolescencePotential.java b/src/main/java/com/lambdazen/bitsy/store/VEObsolescencePotential.java index d0a650a..2b650ba 100644 --- a/src/main/java/com/lambdazen/bitsy/store/VEObsolescencePotential.java +++ b/src/main/java/com/lambdazen/bitsy/store/VEObsolescencePotential.java @@ -1,33 +1,36 @@ package com.lambdazen.bitsy.store; +import com.lambdazen.bitsy.util.BufferPotential; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.lambdazen.bitsy.util.BufferPotential; - public class VEObsolescencePotential implements BufferPotential { private static final Logger log = LoggerFactory.getLogger(VEObsolescencePotential.class); - + double factor; long origLines; long addedLines; int minLinesPerReorg; - + public VEObsolescencePotential(int minLinesPerReorg, double factor, long origLines) { this.factor = factor; this.origLines = origLines; this.addedLines = 0; this.minLinesPerReorg = minLinesPerReorg; } - + @Override public boolean addWork(IVeReorgJob newWork) { if (newWork instanceof TxLog) { - this.addedLines += ((TxLog)newWork).getReorgPotDiff(); + this.addedLines += ((TxLog) newWork).getReorgPotDiff(); double factorTimesOrigLines = factor * origLines; - log.debug("VE obsolescence potential: {}. Threshold is maximum of {} and {}", addedLines, factorTimesOrigLines, minLinesPerReorg); + log.debug( + "VE obsolescence potential: {}. Threshold is maximum of {} and {}", + addedLines, + factorTimesOrigLines, + minLinesPerReorg); return (addedLines > factorTimesOrigLines) && (addedLines > minLinesPerReorg); } else { @@ -40,12 +43,12 @@ public boolean addWork(IVeReorgJob newWork) { public void reset() { addedLines = 0; } - + // This method is called by the flusher public void setOrigLines(int origLines) { this.origLines = origLines; } - + public double getFactor() { return factor; } diff --git a/src/main/java/com/lambdazen/bitsy/store/VertexBean.java b/src/main/java/com/lambdazen/bitsy/store/VertexBean.java index d0d2396..0112c66 100644 --- a/src/main/java/com/lambdazen/bitsy/store/VertexBean.java +++ b/src/main/java/com/lambdazen/bitsy/store/VertexBean.java @@ -1,13 +1,11 @@ package com.lambdazen.bitsy.store; -import java.io.Serializable; -import java.util.TreeMap; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.ads.dict.Dictionary; -import com.lambdazen.bitsy.ads.set.CompactSet; +import java.io.Serializable; +import java.util.TreeMap; public class VertexBean extends UUID implements Serializable { private static final long serialVersionUID = -2867517568410927192L; @@ -15,7 +13,7 @@ public class VertexBean extends UUID implements Serializable { int version; String label; Dictionary properties; - + Object outEdges; Object inEdges; @@ -26,7 +24,7 @@ public VertexBean(UUID uuid, String label, Dictionary properties, int version) { this.properties = properties; this.version = version; } - + /** Shallow copy constructor */ public VertexBean(VertexBean orig) { super(orig.getMostSignificantBits(), orig.getLeastSignificantBits()); @@ -40,7 +38,7 @@ public VertexBean(VertexBean orig) { @JsonIgnore public UUID getId() { - // I am the ID! Saves on object creation and equals checks. + // I am the ID! Saves on object creation and equals checks. return this; } @@ -63,7 +61,7 @@ public TreeMap getProperties() { return ans; } } - + @JsonIgnore public Dictionary getPropertiesDict() { return properties; @@ -76,8 +74,8 @@ public int getVersion() { @JsonProperty("l") public String getLabel() { - return label; - } + return label; + } public void copyFrom(VertexBean vBean) { this.version = vBean.version; diff --git a/src/main/java/com/lambdazen/bitsy/store/VertexBeanJson.java b/src/main/java/com/lambdazen/bitsy/store/VertexBeanJson.java index fe516f8..2e89360 100644 --- a/src/main/java/com/lambdazen/bitsy/store/VertexBeanJson.java +++ b/src/main/java/com/lambdazen/bitsy/store/VertexBeanJson.java @@ -1,8 +1,5 @@ package com.lambdazen.bitsy.store; -import java.io.Serializable; -import java.util.TreeMap; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -10,6 +7,8 @@ import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.ads.dict.Dictionary; import com.lambdazen.bitsy.ads.dict.DictionaryFactory; +import java.io.Serializable; +import java.util.TreeMap; @JsonPropertyOrder({"id", "v", "s", "p"}) public final class VertexBeanJson extends VertexBean implements Serializable { @@ -18,10 +17,11 @@ public final class VertexBeanJson extends VertexBean implements Serializable { BitsyState state; @JsonCreator - public VertexBeanJson(@JsonProperty("id") String uuidStr, - @JsonProperty("l") String label, - @JsonProperty("p") TreeMap properties, - @JsonProperty("v") int version, + public VertexBeanJson( + @JsonProperty("id") String uuidStr, + @JsonProperty("l") String label, + @JsonProperty("p") TreeMap properties, + @JsonProperty("v") int version, @JsonProperty("s") BitsyState state) { super(UUID.fromString(uuidStr), label, DictionaryFactory.fromMap(properties), version); diff --git a/src/main/java/com/lambdazen/bitsy/tx/BitsyTransaction.java b/src/main/java/com/lambdazen/bitsy/tx/BitsyTransaction.java index d9ef0b5..d7c44e6 100644 --- a/src/main/java/com/lambdazen/bitsy/tx/BitsyTransaction.java +++ b/src/main/java/com/lambdazen/bitsy/tx/BitsyTransaction.java @@ -1,20 +1,5 @@ package com.lambdazen.bitsy.tx; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; -import org.apache.tinkerpop.gremlin.structure.Direction; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Graph; -import org.apache.tinkerpop.gremlin.structure.Transaction; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; - import com.lambdazen.bitsy.BitsyEdge; import com.lambdazen.bitsy.BitsyElement; import com.lambdazen.bitsy.BitsyErrorCodes; @@ -31,6 +16,17 @@ import com.lambdazen.bitsy.store.VertexBean; import com.lambdazen.bitsy.util.EdgeIterator; import com.lambdazen.bitsy.util.VertexIterator; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Transaction; +import org.apache.tinkerpop.gremlin.structure.Vertex; /** This class captures a transaction that is NOT thread-safe */ public class BitsyTransaction implements ITransaction, ICommitChanges { @@ -71,10 +67,10 @@ public void open() { } } - //@Override - //public T begin(final Class traversalSourceClass) { + // @Override + // public T begin(final Class traversalSourceClass) { // return graph.traversal(traversalSourceClass); - //} + // } @Override public void commit() { @@ -152,7 +148,7 @@ private boolean isDeleted(BitsyElement bitsyElement) { } if (bitsyElement instanceof BitsyEdge) { - BitsyEdge edge = (BitsyEdge)bitsyElement; + BitsyEdge edge = (BitsyEdge) bitsyElement; return (isDeletedVertex(edge.getInVertexId()) || isDeletedVertex(edge.getOutVertexId())); } else { return false; @@ -183,7 +179,7 @@ public Vertex getVertex(UUID id) throws BitsyException { if (ans != null) { // 3. Keep a reference if the isolation level is repeatable read if (isolationLevel == BitsyIsolationLevel.REPEATABLE_READ) { - context.unmodifiedVertices.put((UUID)(ans.id()), ans); + context.unmodifiedVertices.put((UUID) (ans.id()), ans); } } @@ -223,7 +219,7 @@ public Edge getEdge(UUID id) throws BitsyException { // 4. Keep a reference when the isolation level is repeatable read if (isolationLevel == BitsyIsolationLevel.REPEATABLE_READ) { - context.unmodifiedEdges.put((UUID)(ans.id()), ans); + context.unmodifiedEdges.put((UUID) (ans.id()), ans); } return ans; @@ -244,8 +240,8 @@ public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... for (Direction myDir : directions) { if ((myDir == dir) || (dir == Direction.BOTH)) { - //log.debug("Getting edges for dir {} and labels {}", myDir, Arrays.asList(edgeLabels)); - List txEdgeIds = context.adjMap.getEdges((UUID)bitsyVertex.id(), myDir, edgeLabels); + // log.debug("Getting edges for dir {} and labels {}", myDir, Arrays.asList(edgeLabels)); + List txEdgeIds = context.adjMap.getEdges((UUID) bitsyVertex.id(), myDir, edgeLabels); // Go over each edge in storeEdges and merge it with the changedEdges to get mergedEdges for (UUID edgeId : txEdgeIds) { Edge edge = getEdge(edgeId); @@ -253,20 +249,20 @@ public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... // An end-point vertex may be deleted in this Tx, so this check is required if (edge != null) { mergedEdges.add(edge); - //log.debug("Merged edges.1 += {}", edge); + // log.debug("Merged edges.1 += {}", edge); } } // Get the edges from the store // TODO: See if this can be made into a lazy data-structure - List storeEdges = context.store.getEdges((UUID)bitsyVertex.id(), myDir, edgeLabels); + List storeEdges = context.store.getEdges((UUID) bitsyVertex.id(), myDir, edgeLabels); // Go over each edge in storeEdges and merge it with the changedEdges to get mergedEdges for (EdgeBean edge : storeEdges) { // Check if the edge has been changed - BitsyEdge changedEdge = context.changedEdges.get((UUID)edge.getId()); + BitsyEdge changedEdge = context.changedEdges.get((UUID) edge.getId()); if (changedEdge == null) { - changedEdge = context.unmodifiedEdges.get((UUID)edge.getId()); + changedEdge = context.unmodifiedEdges.get((UUID) edge.getId()); } if (changedEdge != null) { @@ -279,7 +275,7 @@ public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... // Keep this edge, but give the version from this transaction mergedEdges.add(changedEdge); - //log.debug("Merged edges.2 += {}", changedEdge); + // log.debug("Merged edges.2 += {}", changedEdge); } } } else { @@ -293,7 +289,7 @@ public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... // Keep this edge as provided by the graph store (i.e., outside tx context) mergedEdges.add(changedEdge); - //log.debug("Merged edges.3 += {}", changedEdge); + // log.debug("Merged edges.3 += {}", changedEdge); // Add it to the Tx context context.unmodifiedEdges.put(edge.getId(), changedEdge); @@ -314,14 +310,14 @@ public void markForPropertyUpdate(BitsyElement bitsyElement) throws BitsyExcepti bitsyElement.setState(BitsyState.M); // ...and must be added to the changedVertices if missing - UUID id = (UUID)bitsyElement.id(); + UUID id = (UUID) bitsyElement.id(); if (bitsyElement instanceof BitsyVertex) { context.unmodifiedVertices.remove(id); - context.changedVertices.put(id, (BitsyVertex)bitsyElement); + context.changedVertices.put(id, (BitsyVertex) bitsyElement); } else { context.unmodifiedEdges.remove(id); - BitsyEdge edge = (BitsyEdge)bitsyElement; + BitsyEdge edge = (BitsyEdge) bitsyElement; context.changedEdges.put(id, edge); } } @@ -331,7 +327,7 @@ public void addVertex(BitsyVertex vertex) throws BitsyException { checkIfActive(); // If so, the vertex must be added to changedVertices - UUID id = (UUID)vertex.id(); + UUID id = (UUID) vertex.id(); context.changedVertices.put(id, vertex); } @@ -341,14 +337,16 @@ public void removeVertex(BitsyVertex vertex) throws BitsyException { // Ensure that the edge was created in this transaction if (vertex.getTransaction() != this) { - throw new BitsyException(BitsyErrorCodes.REMOVING_VERTEX_FROM_ANOTHER_TX, "Vertex " + vertex.id() + " belongs to a different transaction"); + throw new BitsyException( + BitsyErrorCodes.REMOVING_VERTEX_FROM_ANOTHER_TX, + "Vertex " + vertex.id() + " belongs to a different transaction"); } // The element must be marked as deleted vertex.setState(BitsyState.D); // Add to changed vertices, if not already available - UUID id = (UUID)vertex.id(); + UUID id = (UUID) vertex.id(); context.changedVertices.put(id, vertex); context.unmodifiedVertices.remove(id); @@ -369,34 +367,34 @@ public void addEdge(BitsyEdge edge) throws BitsyException { throw new BitsyException(BitsyErrorCodes.ADDING_EDGE_FROM_A_DELETED_VERTEX); } - UUID id = (UUID)edge.id(); + UUID id = (UUID) edge.id(); context.changedEdges.put(id, edge); // and the adjacency map context.adjMap.addEdge(id, edge.getOutVertexId(), edge.label(), edge.getInVertexId(), edge.getVersion()); } - - public void removeEdge(BitsyEdge edge) throws BitsyException { // Only work on live transactions. It is OK if the vertex is already modified/deleted. checkIfActive(); // Ensure that the edge was created in this transaction if (edge.getTransaction() != this) { - throw new BitsyException(BitsyErrorCodes.REMOVING_EDGE_FROM_ANOTHER_TX, "Edge " + edge.id() + " belongs to a different transaction"); + throw new BitsyException( + BitsyErrorCodes.REMOVING_EDGE_FROM_ANOTHER_TX, + "Edge " + edge.id() + " belongs to a different transaction"); } // The element must be marked as deleted edge.setState(BitsyState.D); // Add to changed edges, if not already available - UUID id = (UUID)edge.id(); + UUID id = (UUID) edge.id(); context.changedEdges.put(id, edge); context.unmodifiedEdges.remove(id); // Remove from adjacency map - context.adjMap.removeEdge((UUID)edge.id(), edge.getOutVertexId(), edge.label(), edge.getInVertexId()); + context.adjMap.removeEdge((UUID) edge.id(), edge.getOutVertexId(), edge.label(), edge.getInVertexId()); } public Collection getVertexChanges() { @@ -418,7 +416,7 @@ public Iterator getAllVertices() { // 2. Wrap it around an iterator for this transaction. Idea is for the // transaction to take priority over vertices in the store. Creating a // copy to avoid concurrent modification exceptions - return (Iterator)new VertexIterator(this, new ArrayList(getVertexChanges()), allVertices); + return (Iterator) new VertexIterator(this, new ArrayList(getVertexChanges()), allVertices); } @Override @@ -432,7 +430,7 @@ public Iterator getAllEdges() { // 2. Wrap it around an iterator for this transaction. Idea is for the // transaction to take priority over vertices in the store. Creating a // copy to avoid concurrent modification exceptions - return (Iterator)new EdgeIterator(this, new ArrayList(getEdgeChanges()), allEdges); + return (Iterator) new EdgeIterator(this, new ArrayList(getEdgeChanges()), allEdges); } @Override @@ -538,7 +536,7 @@ public void clearTransactionListeners() { // Added for Tinkerpop 3.5 public T begin(final Class traversalSourceClass) { - throw new UnsupportedOperationException("Bitsy does not support begin(). Please use open, commit, rollback and close"); + throw new UnsupportedOperationException( + "Bitsy does not support begin(). Please use open, commit, rollback and close"); } - } diff --git a/src/main/java/com/lambdazen/bitsy/tx/BitsyTransactionContext.java b/src/main/java/com/lambdazen/bitsy/tx/BitsyTransactionContext.java index 6a14e9e..2a718bc 100644 --- a/src/main/java/com/lambdazen/bitsy/tx/BitsyTransactionContext.java +++ b/src/main/java/com/lambdazen/bitsy/tx/BitsyTransactionContext.java @@ -1,12 +1,5 @@ package com.lambdazen.bitsy.tx; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - import com.lambdazen.bitsy.BitsyEdge; import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.BitsyVertex; @@ -15,7 +8,12 @@ import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.store.AdjacencyMap; import com.lambdazen.bitsy.store.IEdgeRemover; - +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Transaction.CLOSE_BEHAVIOR; import org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR; @@ -31,9 +29,9 @@ public class BitsyTransactionContext { List> transactionListeners; Consumer readWriteConsumer = READ_WRITE_BEHAVIOR.AUTO; - + // The default close behavior in TP3 changed to rollback from commit in TP2 - Consumer closeConsumer = CLOSE_BEHAVIOR.ROLLBACK; + Consumer closeConsumer = CLOSE_BEHAVIOR.ROLLBACK; public BitsyTransactionContext(IGraphStore store) { this.unmodifiedVertices = new HashMap(); @@ -50,55 +48,56 @@ public IEdge removeEdge(UUID id) { } }); } - + // This method is called to remove an edge through the IEdgeRemover private IEdge removeEdgeOnVertexDelete(UUID edgeId) throws BitsyException { // This is called from remove on adjMap, which means that the edge was added in this Tx BitsyEdge edge = changedEdges.remove(edgeId); - + // Only an edge that is present in this Tx can be removed by the IEdgeRemover assert (edge != null); - + return edge; } - public void addTransactionListener(Consumer listener) { - transactionListeners.add(listener); - } + public void addTransactionListener(Consumer listener) { + transactionListeners.add(listener); + } - public void removeTransactionListener(Consumer listener) { - transactionListeners.remove(listener); - } + public void removeTransactionListener(Consumer listener) { + transactionListeners.remove(listener); + } - public void clearTransactionListeners() { - transactionListeners.clear(); - } + public void clearTransactionListeners() { + transactionListeners.clear(); + } - public void announceCommit(BitsyTransaction t) { - this.transactionListeners.forEach(c -> c.accept(Status.COMMIT)); - } + public void announceCommit(BitsyTransaction t) { + this.transactionListeners.forEach(c -> c.accept(Status.COMMIT)); + } - public void announceRollback(BitsyTransaction t) { - this.transactionListeners.forEach(c -> c.accept(Status.ROLLBACK)); - } + public void announceRollback(BitsyTransaction t) { + this.transactionListeners.forEach(c -> c.accept(Status.ROLLBACK)); + } - public void onReadWrite(Consumer consumer) { - readWriteConsumer = Optional.ofNullable(consumer).orElseThrow(Transaction.Exceptions::onReadWriteBehaviorCannotBeNull); - } + public void onReadWrite(Consumer consumer) { + readWriteConsumer = + Optional.ofNullable(consumer).orElseThrow(Transaction.Exceptions::onReadWriteBehaviorCannotBeNull); + } - public void onClose(Consumer consumer) { + public void onClose(Consumer consumer) { closeConsumer = Optional.ofNullable(consumer).orElseThrow(Transaction.Exceptions::onCloseBehaviorCannotBeNull); - } + } - public Consumer getReadWriteConsumer() { - return readWriteConsumer; - } + public Consumer getReadWriteConsumer() { + return readWriteConsumer; + } - public Consumer getCloseConsumer() { - return closeConsumer; - } + public Consumer getCloseConsumer() { + return closeConsumer; + } - public void clear() { + public void clear() { unmodifiedVertices.clear(); unmodifiedEdges.clear(); changedVertices.clear(); diff --git a/src/main/java/com/lambdazen/bitsy/util/BitsyElementIterator.java b/src/main/java/com/lambdazen/bitsy/util/BitsyElementIterator.java index cc8ea30..b91db01 100644 --- a/src/main/java/com/lambdazen/bitsy/util/BitsyElementIterator.java +++ b/src/main/java/com/lambdazen/bitsy/util/BitsyElementIterator.java @@ -1,65 +1,67 @@ package com.lambdazen.bitsy.util; +import com.lambdazen.bitsy.BitsyElement; +import com.lambdazen.bitsy.BitsyState; +import com.lambdazen.bitsy.UUID; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; - import org.apache.tinkerpop.gremlin.structure.Element; -import com.lambdazen.bitsy.BitsyElement; -import com.lambdazen.bitsy.BitsyState; -import com.lambdazen.bitsy.UUID; - public abstract class BitsyElementIterator implements Iterator { private Iterator changedElemIter; private Iterator elementIter; private HashSet changedIds; private ElementType readAhead; private HashSet allChangedIds; - + public BitsyElementIterator(Collection vertices, Iterator changedElemIter) { this.elementIter = vertices.iterator(); this.changedIds = new HashSet(); this.readAhead = null; this.changedElemIter = changedElemIter; } - - public BitsyElementIterator(Collection vertices, Iterator changedElemIter, Collection allChangedVertices) { + + public BitsyElementIterator( + Collection vertices, + Iterator changedElemIter, + Collection allChangedVertices) { this.elementIter = vertices.iterator(); this.changedIds = null; this.readAhead = null; this.changedElemIter = changedElemIter; this.allChangedIds = new HashSet(); for (Element elem : allChangedVertices) { - allChangedIds.add((UUID)elem.id()); + allChangedIds.add((UUID) elem.id()); } } public abstract UUID getId(BeanType bean); + public abstract ElementType getElement(BeanType bean); - + public boolean hasNext() { // First return the changed vertices while ((readAhead == null) && (changedElemIter.hasNext())) { ElementType elem = changedElemIter.next(); - + // Don't return this ID again if (changedIds != null) { - changedIds.add((UUID)elem.id()); + changedIds.add((UUID) elem.id()); } - + // Skip over deleted vertices - if (((BitsyElement)elem).getState() != BitsyState.D) { + if (((BitsyElement) elem).getState() != BitsyState.D) { // Found a good element readAhead = elem; break; } } - + // Found it? if (readAhead != null) return true; - + // Otherwise make sure that the next available vertex is not one of the changed IDs while ((readAhead == null) && (elementIter.hasNext())) { BeanType bean = elementIter.next(); @@ -71,22 +73,22 @@ public boolean hasNext() { } else { // For indexes, we can't be sure what the diffs are. So any changed ID must be ignored. if (!allChangedIds.contains(getId(bean))) { - //if ((changedIds == null) || !changedIds.contains(getId(bean))) { + // if ((changedIds == null) || !changedIds.contains(getId(bean))) { // A new vertex readAhead = getElement(bean); } } } - + return (readAhead != null); } public ElementType next() { if (readAhead == null) { - // Running hasNext() in case the caller did not call it + // Running hasNext() in case the caller did not call it hasNext(); } - + ElementType ans = readAhead; if (ans == null) { // Still couldn't find it diff --git a/src/main/java/com/lambdazen/bitsy/util/BufferFlusher.java b/src/main/java/com/lambdazen/bitsy/util/BufferFlusher.java index fe1cbd1..832aaee 100644 --- a/src/main/java/com/lambdazen/bitsy/util/BufferFlusher.java +++ b/src/main/java/com/lambdazen/bitsy/util/BufferFlusher.java @@ -1,13 +1,12 @@ package com.lambdazen.bitsy.util; -import java.util.List; - import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.util.DoubleBuffer.BufferName; +import java.util.List; /** This interface represents a flush worker that takes can empty a buffer (A/B) */ public interface BufferFlusher { // Any exception thrown by this method will stop further enqueues. // InterruptedExceptions must be rethrown to kill the flush thread - public void flushBuffer(BufferName bufName, List workList) throws BitsyException, InterruptedException; + public void flushBuffer(BufferName bufName, List workList) throws BitsyException, InterruptedException; } diff --git a/src/main/java/com/lambdazen/bitsy/util/BufferPotential.java b/src/main/java/com/lambdazen/bitsy/util/BufferPotential.java index 72b8fe8..6221795 100644 --- a/src/main/java/com/lambdazen/bitsy/util/BufferPotential.java +++ b/src/main/java/com/lambdazen/bitsy/util/BufferPotential.java @@ -14,7 +14,7 @@ public interface BufferPotential { * Otherwise, it can return false. */ public boolean addWork(T newWork); - + /** * This method is called to reset the potential, when the double buffer * flips the enqueue buffer diff --git a/src/main/java/com/lambdazen/bitsy/util/BufferQueuer.java b/src/main/java/com/lambdazen/bitsy/util/BufferQueuer.java index 52d9708..de8a7ea 100644 --- a/src/main/java/com/lambdazen/bitsy/util/BufferQueuer.java +++ b/src/main/java/com/lambdazen/bitsy/util/BufferQueuer.java @@ -7,5 +7,5 @@ public interface BufferQueuer { // Any exception thrown by this method will stop further enqueues. // InterruptedExceptions must be rethrown to kill the flush thread - public void onQueue(BufferName bufName, T work) throws BitsyException; + public void onQueue(BufferName bufName, T work) throws BitsyException; } diff --git a/src/main/java/com/lambdazen/bitsy/util/CommittableFileLog.java b/src/main/java/com/lambdazen/bitsy/util/CommittableFileLog.java index 1aefac8..4b72c27 100644 --- a/src/main/java/com/lambdazen/bitsy/util/CommittableFileLog.java +++ b/src/main/java/com/lambdazen/bitsy/util/CommittableFileLog.java @@ -1,5 +1,10 @@ package com.lambdazen.bitsy.util; +import com.lambdazen.bitsy.BitsyErrorCodes; +import com.lambdazen.bitsy.BitsyException; +import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; +import com.lambdazen.bitsy.store.Record; +import com.lambdazen.bitsy.store.Record.RecordType; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -7,21 +12,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.lambdazen.bitsy.BitsyErrorCodes; -import com.lambdazen.bitsy.BitsyException; -import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; -import com.lambdazen.bitsy.store.Record; -import com.lambdazen.bitsy.store.Record.RecordType; - -/** This class provides wrapper methods to append, commit and reset a file. It is not thread safe. */ +/** This class provides wrapper methods to append, commit and reset a file. It is not thread safe. */ public class CommittableFileLog { private static final Logger log = LoggerFactory.getLogger(CommittableFileLog.class); - /** Should the database lock files before writing to them? Yes by default, but can be changed by the application. **/ + /** Should the database lock files before writing to them? Yes by default, but can be changed by the application. **/ public static boolean LOCK_MODE = true; // 32K buffer for reading files during re-organization @@ -32,7 +30,7 @@ public class CommittableFileLog { FileChannel fileChannel; boolean isTxLog; Long counter; - + // Fields capturing the read state byte[] byteArr = new byte[BUFFER_SIZE]; ByteBuffer byteBuf = ByteBuffer.wrap(byteArr); @@ -55,7 +53,7 @@ public CommittableFileLog(Path filePath, boolean isTxLog) throws IOException { this.isTxLog = isTxLog; this.counter = null; } - + public Long getCounter() { return counter; } @@ -63,7 +61,7 @@ public Long getCounter() { public boolean isTxLog() { return isTxLog; } - + public Path getPath() { return filePath; } @@ -77,7 +75,7 @@ public void resetReadBuffers() { markPosition = -1; writeMode = false; } - + // Re-implementing readLine() to allow truncate public String readLine() { while (!endReached) { @@ -88,7 +86,10 @@ public String readLine() { try { bytesRead = fileChannel.read(byteBuf); } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_READING_FROM_FILE, "File " + getPath() + " can not be opened for reading", e); + throw new BitsyException( + BitsyErrorCodes.ERROR_READING_FROM_FILE, + "File " + getPath() + " can not be opened for reading", + e); } if (bytesRead == -1) { @@ -100,43 +101,43 @@ public String readLine() { // Get more chars into the buffer byteBuf.flip(); - + charBuf = FileBackedMemoryGraphStore.utf8.decode(byteBuf); - + // Reset the index byteIndex = 0; index = 0; } // Find where the \n is - int cbLen = charBuf.length(); + int cbLen = charBuf.length(); int oldIndex = index; for (; index < cbLen; index++, byteIndex++) { char ch = charBuf.charAt(index); - + // Handling UTF-8 characters. byteIndex is used for truncation - if (((int)ch & mask2) != 0) { - byteIndex ++; + if (((int) ch & mask2) != 0) { + byteIndex++; } - - if (((int)ch & mask3) != 0) { - byteIndex ++; + + if (((int) ch & mask3) != 0) { + byteIndex++; } - + if (ch == '\n') { - break; // out of the for loop + break; // out of the for loop } } // Add what was found (or till end) to the current line CharBuffer partialLine = charBuf.subSequence(oldIndex, index); - + // Did we reach the end of the buffer? if (index < cbLen) { // Skip the \n next time index++; byteIndex++; - + if (curLine.length() == 0) { // Common case return partialLine.toString(); @@ -164,56 +165,64 @@ public String readLine() { return ans; } } - + public void mark() { mark(0); } - + public void mark(int numBytesBehind) { try { assert (fileChannel != null); - + long ans = fileChannel.position() - numBytesBehind; if (charBuf != null) { // A char buffer read ahead already - // Adjust the position to point it to after the last readLine + // Adjust the position to point it to after the last readLine ans = ans - byteBuf.limit() + byteIndex; - //log.debug("Index is " + byteIndex + ". Char index " + index + ". Position is " + fileChannel.position() + ". Buffer size " + byteBuf.limit()); + // log.debug("Index is " + byteIndex + ". Char index " + index + ". Position is " + + // fileChannel.position() + ". Buffer size " + byteBuf.limit()); } this.markPosition = ans; } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " could not be marked", e); + throw new BitsyException( + BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " could not be marked", e); } } - + public long getMarkPosition() { return markPosition; } - + public void truncateAtMark() { - // Truncate at mark can only be called when the fileChannel is active + // Truncate at mark can only be called when the fileChannel is active assert (fileChannel != null); assert (markPosition != -1); - + try { - log.info("Truncating {} to recover from crash. {} bytes removed", getPath(), (fileChannel.size() - markPosition)); - + log.info( + "Truncating {} to recover from crash. {} bytes removed", + getPath(), + (fileChannel.size() - markPosition)); + fileChannel.truncate(markPosition); } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " could not truncated at marked position " + markPosition, e); + throw new BitsyException( + BitsyErrorCodes.ERROR_WRITING_TO_FILE, + "File " + getPath() + " could not truncated at marked position " + markPosition, + e); } } - + public void openForAppend() { if (writeMode) { return; } - + if (fileChannel != null) { close(); } - + try { // Try opening the file to append, and create it if necessary fileChannel = FileChannel.open(filePath, StandardOpenOption.APPEND); @@ -222,10 +231,11 @@ public void openForAppend() { if (LOCK_MODE) { fileChannel.lock(); } - + writeMode = true; } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " can not be opened to append", e); + throw new BitsyException( + BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " can not be opened to append", e); } } @@ -235,39 +245,44 @@ public void openForOverwrite(Long counter) { if (fileChannel != null) { close(); } - + try { // Try opening the file to write, and zap if it exists - fileChannel = FileChannel.open(filePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + fileChannel = FileChannel.open( + filePath, + StandardOpenOption.WRITE, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); // Lock it to avoid conflicts if (LOCK_MODE) { fileChannel.lock(); } - - // Write header if the counter is defined + + // Write header if the counter is defined if (counter != null) { - fileChannel.write(ByteBuffer.wrap(Record.generateDBLine(RecordType.H, "" + counter).getBytes(FileBackedMemoryGraphStore.utf8))); + fileChannel.write(ByteBuffer.wrap( + Record.generateDBLine(RecordType.H, "" + counter).getBytes(FileBackedMemoryGraphStore.utf8))); } // Save the meta-data in case it was created fileChannel.force(true); - + // Update the counter value this.counter = counter; - + // Set the write mode to true writeMode = true; } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " can not be opened to overwrite", e); + throw new BitsyException( + BitsyErrorCodes.ERROR_WRITING_TO_FILE, "File " + getPath() + " can not be opened to overwrite", e); } } - + public boolean exists() { return Files.exists(getPath()); } - public void openForRead() { // Set write mode to false -- safe to be false rather than true writeMode = false; @@ -276,22 +291,23 @@ public void openForRead() { if (fileChannel != null) { close(); } - + // Open using classic IO packages String header; try { // Try opening the file to read fileChannel = FileChannel.open(filePath, StandardOpenOption.READ, StandardOpenOption.WRITE); - + fileChannel.position(0); - + resetReadBuffers(); - + header = readLine(); } catch (IOException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_READING_FROM_FILE, "File " + getPath() + " can not be opened for reading", e); + throw new BitsyException( + BitsyErrorCodes.ERROR_READING_FROM_FILE, "File " + getPath() + " can not be opened for reading", e); } - + if (header == null) { // Empty file this.counter = null; @@ -301,53 +317,61 @@ public void openForRead() { rec = Record.parseRecord(header, 1, getPath().toString()); } catch (BitsyException e) { // Error parsing the line - throw new BitsyException(BitsyErrorCodes.ERROR_IN_FILE_HEADER, "File " + getPath() + " has a header line has an invalid checksum. Encountered: " + header, e); + throw new BitsyException( + BitsyErrorCodes.ERROR_IN_FILE_HEADER, + "File " + getPath() + " has a header line has an invalid checksum. Encountered: " + header, + e); } if (rec.getType() != RecordType.H) { - throw new BitsyException(BitsyErrorCodes.ERROR_IN_FILE_HEADER, "File " + getPath() + " has a header line with an invalid record type. Encountered: " + header); + throw new BitsyException( + BitsyErrorCodes.ERROR_IN_FILE_HEADER, + "File " + getPath() + " has a header line with an invalid record type. Encountered: " + header); } try { this.counter = new Long(rec.getJson()); } catch (NumberFormatException e) { - throw new BitsyException(BitsyErrorCodes.ERROR_IN_FILE_HEADER, "File " + getPath() + " has a non-numeric header counter. Encountered: " + header); + throw new BitsyException( + BitsyErrorCodes.ERROR_IN_FILE_HEADER, + "File " + getPath() + " has a non-numeric header counter. Encountered: " + header); } } - } - /** This method appends a line to the file channel */ + /** This method appends a line to the file channel */ public void append(byte[] toWrite) throws BitsyException { ByteBuffer buf = ByteBuffer.wrap(toWrite); append(buf); } - + public void append(ByteBuffer buf) throws BitsyException { try { while (buf.hasRemaining()) { fileChannel.write(buf); } } catch (IOException e) { - BitsyException be = new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "Could not write to " + toString(), e); + BitsyException be = + new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "Could not write to " + toString(), e); log.error("Raised exception", be); throw be; } } - + public void commit() throws BitsyException { try { // TODO: Write-ahead on Txlogs to use force(false) fileChannel.force(true); } catch (IOException e) { - BitsyException be = new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "Could not write to " + toString(), e); + BitsyException be = + new BitsyException(BitsyErrorCodes.ERROR_WRITING_TO_FILE, "Could not write to " + toString(), e); log.error("Raised exception", be); throw be; } } - + public void close() { writeMode = false; @@ -356,15 +380,15 @@ public void close() { fileChannel.force(true); fileChannel.close(); } - + fileChannel = null; } catch (IOException e) { log.error("Ignored error encountered while closing file ${}", getPath(), e); - - // Ignore exceptions. All operations explicitly commit + + // Ignore exceptions. All operations explicitly commit } } - + public String toString() { return "CommittableFileLog(" + filePath + ")"; } diff --git a/src/main/java/com/lambdazen/bitsy/util/DefaultCommitChanges.java b/src/main/java/com/lambdazen/bitsy/util/DefaultCommitChanges.java index 9b801ff..79c1a06 100644 --- a/src/main/java/com/lambdazen/bitsy/util/DefaultCommitChanges.java +++ b/src/main/java/com/lambdazen/bitsy/util/DefaultCommitChanges.java @@ -1,13 +1,12 @@ package com.lambdazen.bitsy.util; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.lambdazen.bitsy.BitsyEdge; import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.BitsyVertex; import com.lambdazen.bitsy.ICommitChanges; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; public class DefaultCommitChanges implements ICommitChanges { private List changedVertices; @@ -17,7 +16,7 @@ public DefaultCommitChanges() { this.changedVertices = new ArrayList(); this.changedEdges = new ArrayList(); } - + @Override public Collection getVertexChanges() { return changedVertices; @@ -27,13 +26,13 @@ public Collection getVertexChanges() { public Collection getEdgeChanges() { return changedEdges; } - + public void reset() { // Clear retains the size from previous round, which is useful to load V/E logs changedVertices.clear(); changedEdges.clear(); } - + public void changeVertex(BitsyVertex vertex) throws BitsyException { changedVertices.add(vertex); } diff --git a/src/main/java/com/lambdazen/bitsy/util/DoubleBuffer.java b/src/main/java/com/lambdazen/bitsy/util/DoubleBuffer.java index 1953ac2..a4cce1b 100644 --- a/src/main/java/com/lambdazen/bitsy/util/DoubleBuffer.java +++ b/src/main/java/com/lambdazen/bitsy/util/DoubleBuffer.java @@ -1,61 +1,66 @@ package com.lambdazen.bitsy.util; +import com.lambdazen.bitsy.BitsyException; import java.util.ArrayList; import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.lambdazen.bitsy.BitsyException; - /** * This class implements a double buffer that lets one set of Threads enqueue * work on one queue while a "flush thread" performs the work queued up on the * other queue - */ + */ public class DoubleBuffer { private static final Logger log = LoggerFactory.getLogger(DoubleBuffer.class); - - public enum BufferName {A, B}; - + + public enum BufferName { + A, + B + }; + // State of the double buffer int enqueueIdx; boolean[] needFlush; List workListA; List workListB; - + BitsyException toThrow; boolean trackWork; // Helper objects BufferPotential pot; DoubleBufferThread flushThread; - - + /** * This constructor takes an executor service on which the FlushWorker will - * be called when it is time to flush the buffer. + * be called when it is time to flush the buffer. */ public DoubleBuffer(BufferPotential initPot, BufferFlusher flusher, String flushThreadName) { this(initPot, flusher, flushThreadName, true, false); } - - public DoubleBuffer(BufferPotential initPot, BufferFlusher flusher, String flushThreadName, boolean trackWork, boolean syncMode) { + + public DoubleBuffer( + BufferPotential initPot, + BufferFlusher flusher, + String flushThreadName, + boolean trackWork, + boolean syncMode) { this.enqueueIdx = 0; - + this.pot = initPot; this.needFlush = new boolean[] {false, false}; this.flushThread = new DoubleBufferThread(flushThreadName, this, flusher, syncMode); this.trackWork = trackWork; - + if (trackWork) { this.workListA = new ArrayList(); this.workListB = new ArrayList(); } - + flushThread.start(); } - + public BufferPotential getPot() { return pot; } @@ -68,7 +73,7 @@ public void stop(int joinTimeout) { pot.notifyAll(); flushThread.safeStop(); } - + try { flushThread.join(joinTimeout); @@ -78,11 +83,11 @@ public void stop(int joinTimeout) { // Some other thread interrupted this one log.error(Thread.currentThread().getName() + " was interrupted during stop() by a different thread", e); } - + flushThread = null; } } - + public void addWork(final T work) throws BitsyException { synchronized (pot) { // There is actual work being enqueued by a thread @@ -93,7 +98,7 @@ public void addWork(final T work) throws BitsyException { if (trackWork) { (enqueueIdx == 0 ? workListA : workListB).add(work); } - + boolean needFlushThisTime = pot.addWork(work); this.needFlush[enqueueIdx] = needFlush[enqueueIdx] || needFlushThisTime; @@ -102,41 +107,41 @@ public void addWork(final T work) throws BitsyException { } } } - + public BufferName getBufferToFlush() throws InterruptedException { synchronized (pot) { - // Flush if need to flush is true on the enqueue index + // Flush if need to flush is true on the enqueue index while (!needFlush[enqueueIdx]) { pot.wait(); } - + // Flush buffer is now the enqueue index BufferName flushBuf = getEnqueueBuffer(); - + // The enqueue buffer moves to the other buffer enqueueIdx = 1 - enqueueIdx; - + // Now that we have moved to the other queue, the potential function can be reset pot.reset(); - + return flushBuf; } } - + public List getWorkList(BufferName bufName) { - // This method will return null if the object was initialized with trackWork = false + // This method will return null if the object was initialized with trackWork = false return (bufName == BufferName.A) ? workListA : workListB; } - + public BufferName getEnqueueBuffer() { return (enqueueIdx == 0) ? BufferName.A : BufferName.B; } - + public void completedFlush() { synchronized (pot) { - // Done with the flush on the 'other' queue + // Done with the flush on the 'other' queue needFlush[1 - enqueueIdx] = false; - + // Clear the work list if (trackWork) { ((enqueueIdx == 0) ? workListB : workListA).clear(); diff --git a/src/main/java/com/lambdazen/bitsy/util/DoubleBufferThread.java b/src/main/java/com/lambdazen/bitsy/util/DoubleBufferThread.java index 1ba1643..f27c62b 100644 --- a/src/main/java/com/lambdazen/bitsy/util/DoubleBufferThread.java +++ b/src/main/java/com/lambdazen/bitsy/util/DoubleBufferThread.java @@ -1,13 +1,11 @@ package com.lambdazen.bitsy.util; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.lambdazen.bitsy.BitsyErrorCodes; import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.util.DoubleBuffer.BufferName; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** This class flushes the double buffer based on the potential function provided to it */ public class DoubleBufferThread extends Thread { @@ -16,22 +14,22 @@ public class DoubleBufferThread extends Thread { DoubleBuffer buf; BufferFlusher flush; boolean syncMode; - boolean stopped; - + boolean stopped; + public DoubleBufferThread(String threadName, DoubleBuffer buf, BufferFlusher flush, boolean syncMode) { super(threadName); setDaemon(true); - + this.buf = buf; this.flush = flush; this.syncMode = syncMode; this.stopped = false; } - + public void safeStop() { this.stopped = true; } - + public void run() { try { while (!stopped) { @@ -45,10 +43,13 @@ public void run() { } } catch (InterruptedException e) { // Exiting thread - log.error(Thread.currentThread().getName() + " was interrupted, most likely because a safe stop was not possible. This may result in recovery-related warnings during the next startup", e); + log.error( + Thread.currentThread().getName() + + " was interrupted, most likely because a safe stop was not possible. This may result in recovery-related warnings during the next startup", + e); } } - + public void doFlush() throws InterruptedException { BufferName bufToFlush = buf.getBufferToFlush(); @@ -63,9 +64,10 @@ public void doFlush() throws InterruptedException { try { flush.flushBuffer(bufToFlush, workList); } catch (BitsyException e) { - BitsyException bitsyException = new BitsyException(BitsyErrorCodes.EXCEPTION_IN_FLUSH, "Encountered exception in thread " + getName(), e); + BitsyException bitsyException = new BitsyException( + BitsyErrorCodes.EXCEPTION_IN_FLUSH, "Encountered exception in thread " + getName(), e); buf.setException(bitsyException); - log.error(getName() + " encountered an unrecoverable exception", bitsyException); + log.error(getName() + " encountered an unrecoverable exception", bitsyException); // Exit to avoid completing the flush. The next time may have a chance. return; diff --git a/src/main/java/com/lambdazen/bitsy/util/DoubleBufferWithExecWork.java b/src/main/java/com/lambdazen/bitsy/util/DoubleBufferWithExecWork.java index 8d02040..1f6e9ff 100644 --- a/src/main/java/com/lambdazen/bitsy/util/DoubleBufferWithExecWork.java +++ b/src/main/java/com/lambdazen/bitsy/util/DoubleBufferWithExecWork.java @@ -4,15 +4,22 @@ public class DoubleBufferWithExecWork extends DoubleBuffer { BufferQueuer queuer; - - public DoubleBufferWithExecWork(BufferPotential initPot, BufferQueuer queuer, BufferFlusher flusher, String flushThreadName, boolean trackWork, boolean syncMode, BufferName initBuffer) { + + public DoubleBufferWithExecWork( + BufferPotential initPot, + BufferQueuer queuer, + BufferFlusher flusher, + String flushThreadName, + boolean trackWork, + boolean syncMode, + BufferName initBuffer) { super(initPot, flusher, flushThreadName, trackWork, syncMode); this.queuer = queuer; - // The starting buffer is based on initBuffer + // The starting buffer is based on initBuffer this.enqueueIdx = (initBuffer == BufferName.A) ? 0 : 1; } - + public void addAndExecuteWork(final T work) throws BitsyException { synchronized (pot) { // Do the work inside the synchronized block so that a buffer @@ -20,7 +27,7 @@ public void addAndExecuteWork(final T work) throws BitsyException { queuer.onQueue(getEnqueueBuffer(), work); // The work object may be modified in the previous step - addWork(work); + addWork(work); } } } diff --git a/src/main/java/com/lambdazen/bitsy/util/EdgeIterator.java b/src/main/java/com/lambdazen/bitsy/util/EdgeIterator.java index bd5785e..84e478b 100644 --- a/src/main/java/com/lambdazen/bitsy/util/EdgeIterator.java +++ b/src/main/java/com/lambdazen/bitsy/util/EdgeIterator.java @@ -1,25 +1,28 @@ package com.lambdazen.bitsy.util; -import java.util.Collection; -import java.util.Iterator; - import com.lambdazen.bitsy.BitsyEdge; import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.store.EdgeBean; import com.lambdazen.bitsy.tx.BitsyTransaction; +import java.util.Collection; +import java.util.Iterator; public class EdgeIterator extends BitsyElementIterator implements Iterator { private BitsyTransaction tx; - + public EdgeIterator(BitsyTransaction tx, Collection txEdges, Collection vertices) { super(vertices, txEdges.iterator()); - + this.tx = tx; } - public EdgeIterator(BitsyTransaction tx, Collection txEdges, Collection vertices, Collection allTxEdges) { + public EdgeIterator( + BitsyTransaction tx, + Collection txEdges, + Collection vertices, + Collection allTxEdges) { super(vertices, txEdges.iterator(), allTxEdges); - + this.tx = tx; } @@ -27,9 +30,9 @@ public EdgeIterator(BitsyTransaction tx, Collection txEdges, Collecti public UUID getId(EdgeBean bean) { return bean.getId(); } - + @Override public BitsyEdge getElement(EdgeBean bean) { - return (BitsyEdge)tx.getEdge(bean.getId()); + return (BitsyEdge) tx.getEdge(bean.getId()); } } diff --git a/src/main/java/com/lambdazen/bitsy/util/VertexIterator.java b/src/main/java/com/lambdazen/bitsy/util/VertexIterator.java index 77902aa..70f7d4a 100644 --- a/src/main/java/com/lambdazen/bitsy/util/VertexIterator.java +++ b/src/main/java/com/lambdazen/bitsy/util/VertexIterator.java @@ -1,25 +1,28 @@ package com.lambdazen.bitsy.util; -import java.util.Collection; -import java.util.Iterator; - import com.lambdazen.bitsy.BitsyVertex; import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.store.VertexBean; import com.lambdazen.bitsy.tx.BitsyTransaction; +import java.util.Collection; +import java.util.Iterator; public class VertexIterator extends BitsyElementIterator implements Iterator { private BitsyTransaction tx; - + public VertexIterator(BitsyTransaction tx, Collection txVertices, Collection vertices) { super(vertices, txVertices.iterator()); - + this.tx = tx; } - public VertexIterator(BitsyTransaction tx, Collection txVertices, Collection vertices, Collection allChangedVertices) { + public VertexIterator( + BitsyTransaction tx, + Collection txVertices, + Collection vertices, + Collection allChangedVertices) { super(vertices, txVertices.iterator(), allChangedVertices); - + this.tx = tx; } @@ -27,9 +30,9 @@ public VertexIterator(BitsyTransaction tx, Collection txVertices, C public UUID getId(VertexBean bean) { return bean.getId(); } - + @Override public BitsyVertex getElement(VertexBean bean) { - return (BitsyVertex)tx.getVertex(bean.getId()); + return (BitsyVertex) tx.getVertex(bean.getId()); } } diff --git a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingEdge.java b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingEdge.java index 986e5db..ebe6970 100644 --- a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingEdge.java +++ b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingEdge.java @@ -1,7 +1,9 @@ package com.lambdazen.bitsy.wrapper; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyGraph; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.Iterator; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -9,10 +11,6 @@ import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyGraph; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public class BitsyAutoReloadingEdge implements Edge { BitsyEdge edge; BitsyGraph graph; @@ -23,10 +21,10 @@ public BitsyAutoReloadingEdge(BitsyGraph g, BitsyEdge e) { } public Edge getBaseEdge() { - if (((BitsyTransaction)edge.getTransaction()).isStopped()) { - edge = (BitsyEdge)graph.edges(edge.id()).next(); + if (((BitsyTransaction) edge.getTransaction()).isStopped()) { + edge = (BitsyEdge) graph.edges(edge.id()).next(); } - + return edge; } @@ -49,32 +47,32 @@ public String label() { public int hashCode() { return getBaseEdge().hashCode(); } - + public boolean equals(Object o) { return getBaseEdge().equals(o); } - + public String toString() { return StringFactory.edgeString(this); } - @Override - public Graph graph() { - return getBaseEdge().graph(); - } + @Override + public Graph graph() { + return getBaseEdge().graph(); + } - @Override - public Property property(String key, V value) { - return getBaseEdge().property(key, value); - } + @Override + public Property property(String key, V value) { + return getBaseEdge().property(key, value); + } - @Override - public Iterator vertices(Direction direction) { - return new BitsyAutoReloadingGraph.VertexIterator(graph, getBaseEdge().vertices(direction)); - } + @Override + public Iterator vertices(Direction direction) { + return new BitsyAutoReloadingGraph.VertexIterator(graph, getBaseEdge().vertices(direction)); + } - @Override - public Iterator> properties(String... propertyKeys) { - return getBaseEdge().properties(propertyKeys); - } + @Override + public Iterator> properties(String... propertyKeys) { + return getBaseEdge().properties(propertyKeys); + } } diff --git a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingGraph.java b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingGraph.java index 6e6c17b..29d4b86 100644 --- a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingGraph.java +++ b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingGraph.java @@ -1,7 +1,9 @@ package com.lambdazen.bitsy.wrapper; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyGraph; +import com.lambdazen.bitsy.BitsyVertex; import java.util.Iterator; - import org.apache.commons.configuration2.Configuration; import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -9,10 +11,6 @@ import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Vertex; -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyGraph; -import com.lambdazen.bitsy.BitsyVertex; - public class BitsyAutoReloadingGraph implements Graph { private BitsyGraph graph; @@ -33,54 +31,54 @@ public static final BitsyAutoReloadingGraph open(Configuration configuration) { } @Override - public Vertex addVertex(Object... keyValues) { - BitsyVertex base = (BitsyVertex)(graph.addVertex(keyValues)); + public Vertex addVertex(Object... keyValues) { + BitsyVertex base = (BitsyVertex) (graph.addVertex(keyValues)); return new BitsyAutoReloadingVertex(graph, base); - } + } - @Override - public C compute(Class graphComputerClass) throws IllegalArgumentException { - return (C)graph.compute(graphComputerClass); - } + @Override + public C compute(Class graphComputerClass) throws IllegalArgumentException { + return (C) graph.compute(graphComputerClass); + } - @Override - public GraphComputer compute() throws IllegalArgumentException { - return graph.compute(); - } + @Override + public GraphComputer compute() throws IllegalArgumentException { + return graph.compute(); + } - @Override - public Iterator vertices(Object... vertexIds) { - Iterator result = graph.vertices(vertexIds); - return new VertexIterator(graph, result); - } + @Override + public Iterator vertices(Object... vertexIds) { + Iterator result = graph.vertices(vertexIds); + return new VertexIterator(graph, result); + } - @Override - public Iterator edges(Object... edgeIds) { - Iterator result = graph.edges(edgeIds); + @Override + public Iterator edges(Object... edgeIds) { + Iterator result = graph.edges(edgeIds); - return new EdgeIterator(graph, result); - } + return new EdgeIterator(graph, result); + } - @Override - public Transaction tx() { - return graph.tx(); - } + @Override + public Transaction tx() { + return graph.tx(); + } - @Override - public void close() throws Exception { - graph.close(); - } + @Override + public void close() throws Exception { + graph.close(); + } - @Override - public Variables variables() { - return graph.variables(); - } + @Override + public Variables variables() { + return graph.variables(); + } - @Override - public Configuration configuration() { - return graph.configuration(); - } + @Override + public Configuration configuration() { + return graph.configuration(); + } @Override public Graph.Features features() { @@ -103,7 +101,7 @@ public boolean hasNext() { @Override public Vertex next() { - return new BitsyAutoReloadingVertex(graph, (BitsyVertex)(iter.next())); + return new BitsyAutoReloadingVertex(graph, (BitsyVertex) (iter.next())); } @Override @@ -128,7 +126,7 @@ public boolean hasNext() { @Override public Edge next() { - return new BitsyAutoReloadingEdge(graph, (BitsyEdge)(iter.next())); + return new BitsyAutoReloadingEdge(graph, (BitsyEdge) (iter.next())); } @Override diff --git a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingVertex.java b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingVertex.java index cc8ce2b..fb51ec4 100644 --- a/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingVertex.java +++ b/src/main/java/com/lambdazen/bitsy/wrapper/BitsyAutoReloadingVertex.java @@ -1,7 +1,10 @@ package com.lambdazen.bitsy.wrapper; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyGraph; +import com.lambdazen.bitsy.BitsyVertex; +import com.lambdazen.bitsy.tx.BitsyTransaction; import java.util.Iterator; - import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -10,11 +13,6 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyGraph; -import com.lambdazen.bitsy.BitsyVertex; -import com.lambdazen.bitsy.tx.BitsyTransaction; - public class BitsyAutoReloadingVertex implements Vertex { BitsyVertex vertex; BitsyGraph graph; @@ -25,10 +23,10 @@ public BitsyAutoReloadingVertex(BitsyGraph g, BitsyVertex v) { } public Vertex getBaseVertex() { - if (((BitsyTransaction)vertex.getTransaction()).isStopped()) { - vertex = (BitsyVertex)graph.vertices(vertex.id()).next(); + if (((BitsyTransaction) vertex.getTransaction()).isStopped()) { + vertex = (BitsyVertex) graph.vertices(vertex.id()).next(); } - + return vertex; } @@ -38,65 +36,65 @@ public Object id() { return vertex.id(); } - @Override - public String label() { - return getBaseVertex().label(); - } + @Override + public String label() { + return getBaseVertex().label(); + } public int hashCode() { return getBaseVertex().hashCode(); } - + public boolean equals(Object o) { - return getBaseVertex().equals(o); + return getBaseVertex().equals(o); } - + public String toString() { return StringFactory.vertexString(this); } - @Override - public Graph graph() { - return graph; - } + @Override + public Graph graph() { + return graph; + } - @Override - public void remove() { - getBaseVertex().remove(); - } + @Override + public void remove() { + getBaseVertex().remove(); + } - @Override - public Edge addEdge(String label, Vertex inVertex, Object... keyValues) { - return new BitsyAutoReloadingEdge(graph, (BitsyEdge)(getBaseVertex().addEdge(label, inVertex, keyValues))); - } + @Override + public Edge addEdge(String label, Vertex inVertex, Object... keyValues) { + return new BitsyAutoReloadingEdge(graph, (BitsyEdge) (getBaseVertex().addEdge(label, inVertex, keyValues))); + } - @Override - public Iterator edges(Direction direction, String... labels) { + @Override + public Iterator edges(Direction direction, String... labels) { return new BitsyAutoReloadingGraph.EdgeIterator(graph, getBaseVertex().edges(direction, labels)); - } + } - @Override - public Iterator vertices(Direction direction, String... labels) { + @Override + public Iterator vertices(Direction direction, String... labels) { return new BitsyAutoReloadingGraph.VertexIterator(graph, getBaseVertex().vertices(direction, labels)); - } + } - @Override + @Override public VertexProperty property(String key) { - return getBaseVertex().property(key); + return getBaseVertex().property(key); } - @Override + @Override public VertexProperty property(String key, V value) { - return getBaseVertex().property(key, value); + return getBaseVertex().property(key, value); } - @Override - public VertexProperty property(Cardinality cardinality, String key, V value, Object... keyValues) { - return getBaseVertex().property(cardinality, key, value, keyValues); - } + @Override + public VertexProperty property(Cardinality cardinality, String key, V value, Object... keyValues) { + return getBaseVertex().property(cardinality, key, value, keyValues); + } @Override - public Iterator> properties(String... propertyKeys) { - return getBaseVertex().properties(propertyKeys); - } + public Iterator> properties(String... propertyKeys) { + return getBaseVertex().properties(propertyKeys); + } } diff --git a/src/test/java/com/lambdazen/bitsy/BitsyGraphIT.java b/src/test/java/com/lambdazen/bitsy/BitsyGraphIT.java index 93c72d2..6a6bc37 100644 --- a/src/test/java/com/lambdazen/bitsy/BitsyGraphIT.java +++ b/src/test/java/com/lambdazen/bitsy/BitsyGraphIT.java @@ -1,11 +1,13 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; +import com.lambdazen.bitsy.util.CommittableFileLog; import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -20,48 +22,43 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - -import org.apache.tinkerpop.gremlin.structure.Graph; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Property; - -import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; -import com.lambdazen.bitsy.util.CommittableFileLog; +import org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR; +import org.apache.tinkerpop.gremlin.structure.Vertex; public class BitsyGraphIT extends FileBasedTestCase { Graph graph; Path dbPath; Random rand = new Random(); private Throwable toThrow; - + public boolean isPersistent() { return true; } - + public void setUp() throws IOException { CommittableFileLog.setLockMode(false); - - setUp(true); + + doSetUp(true); } - - public void setUp(boolean delete) throws IOException { + + public void doSetUp(boolean delete) throws IOException { System.out.println("Setting up graph"); - + this.dbPath = tempDir("temp-bitsy-graph", delete); graph = new BitsyGraph(dbPath); -// this.dbPath = tempDir("temp-neo4j-graph", delete); -// graph = new Neo4jGraph(dbPath.toString()); + // this.dbPath = tempDir("temp-neo4j-graph", delete); + // graph = new Neo4jGraph(dbPath.toString()); } protected static void deleteDirectory(final File directory) { deleteDirectory(directory, true); } - + protected static void deleteDirectory(final File directory, boolean deleteDir) { if (directory.exists()) { for (File file : directory.listFiles()) { @@ -71,56 +68,56 @@ protected static void deleteDirectory(final File directory, boolean deleteDir) { file.delete(); } } - + if (deleteDir) { directory.delete(); } } } - + public void tearDown() { System.out.println("Tearing down graph"); try { - graph.close(); + graph.close(); } catch (Exception e) { - throw new RuntimeException("Got ex", e); - } + throw new RuntimeException("Got ex", e); + } } private Vertex getVertex(Graph graph, Object id) { - Iterator iter = graph.vertices(id); - if (iter.hasNext()) { - return iter.next(); - } else { - return null; - } + Iterator iter = graph.vertices(id); + if (iter.hasNext()) { + return iter.next(); + } else { + return null; + } } private Edge getEdge(Graph graph, Object id) { - Iterator iter = graph.edges(id); - if (iter.hasNext()) { - return iter.next(); - } else { - return null; - } + Iterator iter = graph.edges(id); + if (iter.hasNext()) { + return iter.next(); + } else { + return null; + } } private Edge addEdge(Graph graph, Vertex vOut, Vertex vIn, String label) { - return vOut.addEdge(label, vIn); + return vOut.addEdge(label, vIn); } private void removeEdge(Graph graph, Edge edge) { - edge.remove(); + edge.remove(); } private void removeVertex(Graph graph, Vertex vertex) { - vertex.remove(); + vertex.remove(); } - + public void testLoop() throws IOException { int numRuns = 3; for (int run = 0; run < numRuns; run++) { - //System.out.println("Run #" + run); + // System.out.println("Run #" + run); int numPerCommit = 10; int numCommit = 10; @@ -139,17 +136,18 @@ public void testLoop() throws IOException { } // Make sure the vertex is there in the middle of the Tx - assertEquals(new Integer(i), getVertex(graph, vids[i]).value("count")); + assertEquals(Integer.valueOf(i), getVertex(graph, vids[i]).value("count")); } graph.tx().commit(); double duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); + System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); // Make sure vertices are there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); - assertEquals(i, (int)v.value("count")); + assertEquals(i, (int) v.value("count")); } // if (rand.nextDouble() < 2) { @@ -159,14 +157,14 @@ public void testLoop() throws IOException { // Stop and start if (isPersistent()) { tearDown(); - setUp(false); + doSetUp(false); } // Make sure vertices are still there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); assertNotNull(v); - assertEquals(i, (int)v.value("count")); + assertEquals(i, (int) v.value("count")); } // Now add edges @@ -187,7 +185,7 @@ public void testLoop() throws IOException { // Make sure the edge is there in the middle of the Tx // Using toString() to get the edge Edge qEdge = getEdge(graph, eids[i].toString()); - assertEquals(new Integer(i), (Integer)qEdge.value("count")); + assertEquals(Integer.valueOf(i), (Integer) qEdge.value("count")); assertEquals(vOut, qEdge.outVertex()); assertEquals(vIn, qEdge.inVertex()); } @@ -196,7 +194,7 @@ public void testLoop() throws IOException { // Make sure that the edges are there for (int i = 0; i < numVertices; i++) { Edge e = getEdge(graph, eids[i]); - assertEquals(i, (int)e.value("count")); + assertEquals(i, (int) e.value("count")); } // Now modify the edges. Delete even ones @@ -208,7 +206,7 @@ public void testLoop() throws IOException { if (i % numPerCommit == 0) { graph.tx().commit(); - + try { e.value("foo"); } catch (BitsyException ex) { @@ -218,19 +216,19 @@ public void testLoop() throws IOException { // Make sure the edge is there in the middle of the Tx Edge qEdge = getEdge(graph, eids[i]); - assertEquals(new Integer(i + 1), qEdge.value("count")); - + assertEquals(Integer.valueOf(i + 1), qEdge.value("count")); + // Traverse to the vertices Vertex vOut = qEdge.outVertex(); - assertEquals(new Integer(i), vOut.value("count")); - + assertEquals(Integer.valueOf(i), vOut.value("count")); + Vertex vIn = qEdge.inVertex(); - assertEquals(new Integer((i + 1) % numVertices), vIn.value("count")); - + assertEquals(Integer.valueOf((i + 1) % numVertices), vIn.value("count")); + // Run queries in the middle of the Tx assertEquals(qEdge, vIn.edges(Direction.IN).next()); assertEquals(qEdge, vOut.edges(Direction.OUT).next()); - + if (i % 2 == 0) { removeEdge(graph, qEdge); @@ -244,21 +242,21 @@ public void testLoop() throws IOException { fail("Expecting no element"); } catch (NoSuchElementException e1) { } - + try { vOut.edges(Direction.OUT).next(); fail("Expecting no element"); } catch (NoSuchElementException e2) { } } - - try { + + try { vIn.edges(Direction.IN).next(); fail("Can't access a missing edge"); } catch (NoSuchElementException ex) { // Good } - + try { qEdge.value("count"); fail("Can not access deleted edges"); @@ -272,45 +270,45 @@ public void testLoop() throws IOException { // Stop and start if (isPersistent()) { tearDown(); - //assertTrue(rand.nextDouble() > 5); - setUp(false); + // assertTrue(rand.nextDouble() > 5); + doSetUp(false); } // Make sure vertices are still there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); // System.out.println("Looking for " + vids[i]); - - assertEquals(i, (int)v.value("count")); + + assertEquals(i, (int) v.value("count")); } // Make sure that the edges are there for (int i = 0; i < numVertices; i++) { Edge e = getEdge(graph, eids[i]); - + if (i % 2 == 0) { assertNull(e); } else { // i was changed to i+1 assertNotNull("Could not find edge for UUID " + eids[i], e); - assertEquals(i + 1, (int)e.value("count")); + assertEquals(i + 1, (int) e.value("count")); } } - + // Stop and start if (isPersistent()) { tearDown(); - setUp(false); + doSetUp(false); } - + // Make sure vertices are still there. Modify odd ones and delete even ones graph.tx().onReadWrite(READ_WRITE_BEHAVIOR.MANUAL); if (!graph.tx().isOpen()) graph.tx().open(); for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); - assertEquals(i, (int)v.value("count")); - + assertEquals(i, (int) v.value("count")); + if (i % 2 == 0) { removeVertex(graph, v); } else { @@ -323,114 +321,114 @@ public void testLoop() throws IOException { try { v.value("count"); } catch (IllegalStateException ex) { - // That's expected + // That's expected // TP2 behavior: assertEquals(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, ex.getErrorCode()); } graph.tx().open(); } - + // Check the vertex in the middle of the Tx Vertex qv = getVertex(graph, vids[i]); if (i % 2 == 0) { assertNull(qv); } else { - assertEquals(i + 1, (int)v.value("count")); + assertEquals(i + 1, (int) v.value("count")); } } graph.tx().commit(); graph.tx().onReadWrite(READ_WRITE_BEHAVIOR.AUTO); - - // Make sure that only odd vertices are still there + + // Make sure that only odd vertices are still there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); - + if (i % 2 == 0) { assertNull(v); } else { - assertEquals(i + 1, (int)v.value("count")); + assertEquals(i + 1, (int) v.value("count")); } } - + // Make sure that the edges are gone (even vertices are deleted) for (int i = 0; i < numVertices; i++) { Edge e = getEdge(graph, eids[i]); assertNull(e); } - + // Stop and start if (isPersistent()) { tearDown(); - setUp(false); + doSetUp(false); } - + // Make sure that the edges are gone (even vertices are deleted) for (int i = 0; i < numVertices; i++) { Edge e = getEdge(graph, eids[i]); assertNull(e); } - - // Make sure that only odd vertices are still there + + // Make sure that only odd vertices are still there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); - + if (i % 2 == 0) { assertNull(v); } else { - assertEquals(i + 1, (int)v.value("count")); + assertEquals(i + 1, (int) v.value("count")); } } } } - + public void testClique() throws IOException { // Tests indexes in a clique graph int numPerCommit = 10; int numVertices = 29; int numRuns = 3; - - BitsyGraph kig = (BitsyGraph)graph; + + BitsyGraph kig = (BitsyGraph) graph; if (!kig.getIndexedKeys(Vertex.class).contains("vmod3")) { kig.createKeyIndex("vmod3", Vertex.class); } else { kig.dropKeyIndex("vmod3", Vertex.class); kig.createKeyIndex("vmod3", Vertex.class); } - + if (!kig.getIndexedKeys(Edge.class).contains("emod3")) { kig.createKeyIndex("emod3", Edge.class); } else { kig.dropKeyIndex("emod3", Edge.class); kig.createKeyIndex("emod3", Edge.class); } - + int txc = 0; Object[] vids = new Object[numVertices]; Object[][] eids = new Object[numVertices][numVertices]; long startLong = rand.nextLong(); for (int run = 0; run < numRuns; run++) { - if ((run == numRuns - 1) && ((BitsyGraph)graph).getStore().allowFullGraphScans()) { + if ((run == numRuns - 1) && ((BitsyGraph) graph).getStore().allowFullGraphScans()) { // Last run without index kig.dropKeyIndex("vmod3", Vertex.class); kig.dropKeyIndex("emod3", Edge.class); } - + // Change the starting long to look for index replacement logic long oldStartLong = startLong; startLong = rand.nextLong(); - int[] edgeCount = new int[] {0, 0, 0}; - - for (int i=0; i < numVertices; i++) { + int[] edgeCount = new int[] {0, 0, 0}; + + for (int i = 0; i < numVertices; i++) { if (i == numVertices / 2) { if (isPersistent()) { tearDown(); - - setUp(false); + + doSetUp(false); } } Vertex v; - if (run == 0) { + if (run == 0) { v = graph.addVertex(); vids[i] = v.id(); } else { @@ -439,32 +437,36 @@ public void testClique() throws IOException { } v.property("vmod3", startLong + i % 3); - + // Make sure that the index works on committed and uncommitted data if ((txc++ % numPerCommit == 0) && rand.nextDouble() < 2) { graph.tx().commit(); - + // Add a random vertex without this property Vertex dummyV = graph.addVertex(); if (i % 2 == 0) dummyV.property("notvmod3", 1); } - -// System.out.println("Testing vertex " + i + ". Run #" + run); - + + // System.out.println("Testing vertex " + i + ". Run #" + run); + // Negative test on index value in previous iter if (i > numVertices - 3) { if (rand.nextBoolean()) { - assertFalse(((BitsyGraph)graph).verticesByIndex("vmod3", oldStartLong + i % 3).hasNext()); + assertFalse(((BitsyGraph) graph) + .verticesByIndex("vmod3", oldStartLong + i % 3) + .hasNext()); } else { try { - ((BitsyGraph)graph).verticesByIndex("vmod3", oldStartLong + i % 3).next(); + ((BitsyGraph) graph) + .verticesByIndex("vmod3", oldStartLong + i % 3) + .next(); fail("Expecting no element"); } catch (NoSuchElementException e1) { } } } - - Iterator viter = ((BitsyGraph)graph).verticesByIndex("vmod3", startLong + i % 3); + + Iterator viter = ((BitsyGraph) graph).verticesByIndex("vmod3", startLong + i % 3); int count = 0; while (viter.hasNext()) { Vertex qv = viter.next(); @@ -473,48 +475,51 @@ public void testClique() throws IOException { for (int div3 = i % 3; div3 <= i; div3 += 3) { if (vids[div3].equals(qv.id())) { matchesSomething = true; - //System.out.println("Found match for " + div3); + // System.out.println("Found match for " + div3); } matchesSomething = true; } assertTrue(matchesSomething); count++; - //System.out.println("Count = " + count); + // System.out.println("Count = " + count); } - + assertEquals(1 + i / 3, count); - + // Now add edges - for (int j=0; j < i; j++) { + for (int j = 0; j < i; j++) { Edge e; if (run == 0) { Vertex outV = getVertex(graph, vids[j]); - Vertex inV = getVertex(graph, vids[i]); + Vertex inV = getVertex(graph, vids[i]); e = addEdge(graph, outV, inV, "test"); eids[i][j] = e.id(); } else { e = getEdge(graph, eids[i][j]); } - - e.property("emod3", "E" + (startLong + ((i-j) % 3))); + + e.property("emod3", "E" + (startLong + ((i - j) % 3))); Object eid = e.id(); // Make sure that the index works on committed and uncommitted data if (txc++ % numPerCommit == 0) { graph.tx().commit(); } - + // Negative test on index value in previous iter if ((i == numVertices - 1) && (j >= numVertices - 3)) { - assertFalse(((BitsyGraph)graph).edgesByIndex("emod3", "E" + (oldStartLong + ((i-j) % 3))).hasNext()); + assertFalse(((BitsyGraph) graph) + .edgesByIndex("emod3", "E" + (oldStartLong + ((i - j) % 3))) + .hasNext()); } - //System.out.println("Testing edge from " + j + " to " + i); - Iterator eiter = ((BitsyGraph)graph).edgesByIndex("emod3", "E" + (startLong + ((i-j) % 3))); - edgeCount[(i-j) % 3]++; - + // System.out.println("Testing edge from " + j + " to " + i); + Iterator eiter = + ((BitsyGraph) graph).edgesByIndex("emod3", "E" + (startLong + ((i - j) % 3))); + edgeCount[(i - j) % 3]++; + int ecount = 0; boolean matchesThis = false; while (eiter.hasNext()) { @@ -522,35 +527,35 @@ public void testClique() throws IOException { if (eid.equals(qe.id())) { matchesThis = true; - //System.out.println("Found edge match"); + // System.out.println("Found edge match"); } - + ecount++; } - + assertTrue(matchesThis); - assertEquals(edgeCount[(i-j) % 3], ecount); + assertEquals(edgeCount[(i - j) % 3], ecount); } - + graph.tx().commit(); } } - + // Remove vertex props - for (int i=0; i < numVertices; i++) { + for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); v.property("vmod3").remove(); - + Iterator vOut = v.edges(Direction.OUT); while (vOut.hasNext()) { vOut.next().property("emod3").remove(); } - + // Add a random vertex without this property Vertex dummyV = graph.addVertex(); dummyV.property("notvmod3", 1); Object dummyVId = dummyV.id(); - + // Commit & remove graph.tx().commit(); dummyV = getVertex(graph, dummyVId); @@ -558,42 +563,46 @@ public void testClique() throws IOException { } // Make sure the index is empty - for (int i=0; i < 3; i++) { - assertFalse(((BitsyGraph)graph).verticesByIndex("vmod3", startLong + i % 3).hasNext()); + for (int i = 0; i < 3; i++) { + assertFalse(((BitsyGraph) graph) + .verticesByIndex("vmod3", startLong + i % 3) + .hasNext()); } // Add it back - for (int i=0; i < numVertices; i++) { + for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); assertNull(v.value("vmod3")); v.property("vmod3", startLong); } // Make sure the index is non-empty before commit - assertTrue(((BitsyGraph)graph).verticesByIndex("vmod3", startLong).hasNext()); - + assertTrue(((BitsyGraph) graph).verticesByIndex("vmod3", startLong).hasNext()); + graph.tx().commit(); // ... and after - for (int i=0; i < 3; i++) { - assertTrue(((BitsyGraph)graph).verticesByIndex("vmod3", startLong).hasNext()); + for (int i = 0; i < 3; i++) { + assertTrue(((BitsyGraph) graph).verticesByIndex("vmod3", startLong).hasNext()); } - + // Remove it again - for (int i=0; i < numVertices; i++) { + for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); v.property("vmod3").remove(); } graph.tx().commit(); - - for (int i=0; i < 3; i++) { - assertFalse(((BitsyGraph)graph).verticesByIndex("vmod3", startLong + i % 3).hasNext()); + + for (int i = 0; i < 3; i++) { + assertFalse(((BitsyGraph) graph) + .verticesByIndex("vmod3", startLong + i % 3) + .hasNext()); } graph.tx().commit(); - + // Remove edge props - for (int i=0; i < numVertices; i++) { - for (int j=0; j < i; j++) { + for (int i = 0; i < numVertices; i++) { + for (int j = 0; j < i; j++) { if (eids[i][j] == null) { continue; } @@ -602,56 +611,60 @@ public void testClique() throws IOException { Property prop = e.property("emod3"); if (prop.isPresent()) prop.remove(); } - + // Add a random edge without this property Vertex dummyV1 = graph.addVertex(); dummyV1.property("notvmod3", 1); - + Vertex dummyV2 = graph.addVertex(); dummyV2.property("notvmod3", 1); - + Edge e = addEdge(graph, dummyV1, dummyV2, "test"); e.property("notemod3", "E123"); } - for (int i=0; i < numVertices; i++) { - for (int j=0; j < i; j++) { + for (int i = 0; i < numVertices; i++) { + for (int j = 0; j < i; j++) { if (eids[i][j] == null) { continue; } - assertFalse(((BitsyGraph)graph).edgesByIndex("emod3", "E" + (startLong + ((i-j) % 3))).hasNext()); + assertFalse(((BitsyGraph) graph) + .edgesByIndex("emod3", "E" + (startLong + ((i - j) % 3))) + .hasNext()); } } - + graph.tx().commit(); - - for (int i=0; i < numVertices; i++) { - for (int j=0; j < i; j++) { + + for (int i = 0; i < numVertices; i++) { + for (int j = 0; j < i; j++) { if (eids[i][j] == null) { continue; } - assertFalse(((BitsyGraph)graph).edgesByIndex("emod3", "E" + (startLong + ((i-j) % 3))).hasNext()); + assertFalse(((BitsyGraph) graph) + .edgesByIndex("emod3", "E" + (startLong + ((i - j) % 3))) + .hasNext()); } } // Remove edges - for (int i=0; i < numVertices; i++) { - for (int j=0; j < i; j++) { + for (int i = 0; i < numVertices; i++) { + for (int j = 0; j < i; j++) { if ((i + j) % 10 == 0) { getEdge(graph, eids[i][j]).remove(); } } } graph.tx().commit(); - + // Remove vertices - for (int i=0; i < numVertices; i++) { + for (int i = 0; i < numVertices; i++) { getVertex(graph, vids[i]).remove(); } graph.tx().commit(); } - + public void testTypes() throws IOException { int numPerCommit = 10; int numCommit = 10; @@ -663,21 +676,21 @@ public void testTypes() throws IOException { Vertex v = graph.addVertex(); v.property("int", i); v.property("long", (long) i); - v.property("Integer", new Integer(i)); - v.property("Long", new Long(i)); + v.property("Integer", i); + v.property("Long", (long) i); v.property("double", (double) i + 0.1); - v.property("Double", new Double(i + 0.1)); + v.property("Double", i + 0.1); v.property("float", (float) i + 0.1); - v.property("Float", new Float(i + 0.1)); + v.property("Float", (float) (i + 0.1)); v.property("string", "String"); v.property("date", new Date(ts)); - v.property("stringArr", new String[] { "foo", "bar" }); - v.property("intArr", new int[] { 1, 2 }); - v.property("longArr", new long[] { 1, 2 }); - v.property("doubleArr", new double[] { 1.1, 2.1 }); - v.property("floatArr", new float[] { 1.1f, 2.1f }); - v.property("booleanArr", new boolean[] { false, true }); + v.property("stringArr", new String[] {"foo", "bar"}); + v.property("intArr", new int[] {1, 2}); + v.property("longArr", new long[] {1, 2}); + v.property("doubleArr", new double[] {1.1, 2.1}); + v.property("floatArr", new float[] {1.1f, 2.1f}); + v.property("booleanArr", new boolean[] {false, true}); vids[i] = v.id(); @@ -688,28 +701,30 @@ public void testTypes() throws IOException { graph.tx().commit(); double duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); + System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); // Stop and start if (isPersistent()) { tearDown(); - setUp(false); + doSetUp(false); } - + // Make sure vertices are still there for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); assertNotNull("Could not find " + vids[i], v); - //System.out.println("Index " + v.getId() + ". All props: " + v.getPropertyKeys()); - assertEquals(i, (int)v.value("int")); - assertEquals((long) i, (long)v.value("long")); - assertEquals(new Integer(i), (Integer)v.value("Integer")); - assertEquals(new Long(i), (Long)v.value("Long")); - assertEquals((double) i + 0.1, (double)v.value("double")); - assertEquals(new Double(i + 0.1), (Double)v.value("Double")); -// assertEquals((float) i + 0.1, (float)v.value("float")); TP3 doesn't support raw types property - assertEquals(new Float(i + 0.1), (Float)v.value("Float")); + // System.out.println("Index " + v.getId() + ". All props: " + v.getPropertyKeys()); + assertEquals(i, (int) v.value("int")); + assertEquals((long) i, (long) v.value("long")); + assertEquals(Integer.valueOf(i), (Integer) v.value("Integer")); + assertEquals(Long.valueOf(i), (Long) v.value("Long")); + assertEquals((double) i + 0.1, (double) v.value("double")); + assertEquals((double) i + 0.1, (Double) v.value("Double")); + // assertEquals((float) i + 0.1, (float)v.value("float")); TP3 doesn't support raw types + // property + assertEquals((float) (i + 0.1), (Float) v.value("Float")); assertEquals("String", v.value("string")); assertEquals("foo", ((String[]) v.value("stringArr"))[0]); @@ -735,300 +750,303 @@ public void testTypes() throws IOException { } // TODO: Uncomment after supporting threaded transaction -/* - public void testConcurrency() { - // Create a vertex - Vertex v = graph.addVertex(); - v.property("foo", "bar"); - - Edge e = addEdge(graph, v, v, "self"); - e.property("foo", "bar"); - Object eid = e.id(); - - Object vid = v.id(); - graph.tx().commit(); + /* + public void testConcurrency() { + // Create a vertex + Vertex v = graph.addVertex(); + v.property("foo", "bar"); - // Create a threaded transaction - //TransactionalGraph graph2 = ((ThreadedTransactionalGraph)graph).newTransaction(); // was startTransaction prior to 2.3.0 port - Graph graph2 = graph.tx().createThreadedTx(); // TP 3.0 version - - Vertex v1 = getVertex(graph, vid); - - Edge e2 = getEdge(graph2, eid); - Vertex v2 = e2.outVertex(); - - assertEquals("bar", v1.value("foo")); - v1.property("foo", "baz"); - - assertEquals("bar", v2.value("foo")); - v2.property("foo", "bart"); - - // Should succeed - graph.tx().commit(); - - try { - // Should fail + Edge e = addEdge(graph, v, v, "self"); + e.property("foo", "bar"); + Object eid = e.id(); + + Object vid = v.id(); + graph.tx().commit(); + + // Create a threaded transaction + //TransactionalGraph graph2 = ((ThreadedTransactionalGraph)graph).newTransaction(); // was startTransaction prior to 2.3.0 port + Graph graph2 = graph.tx().createThreadedTx(); // TP 3.0 version + + Vertex v1 = getVertex(graph, vid); + + Edge e2 = getEdge(graph2, eid); + Vertex v2 = e2.outVertex(); + + assertEquals("bar", v1.value("foo")); + v1.property("foo", "baz"); + + assertEquals("bar", v2.value("foo")); + v2.property("foo", "bart"); + + // Should succeed + graph.tx().commit(); + + try { + // Should fail + graph2.tx().commit(); + + fail("Failed optimistic concurrency test"); + } catch (BitsyRetryException ex) { + assertEquals(BitsyErrorCodes.CONCURRENT_MODIFICATION, ex.getErrorCode()); + } + + Vertex v2retry = graph2.vertices(vid).next(); + assertEquals("baz", v2retry.value("foo")); + + v2retry.property("foo", "bart"); graph2.tx().commit(); - - fail("Failed optimistic concurrency test"); - } catch (BitsyRetryException ex) { - assertEquals(BitsyErrorCodes.CONCURRENT_MODIFICATION, ex.getErrorCode()); - } - Vertex v2retry = graph2.vertices(vid).next(); - assertEquals("baz", v2retry.value("foo")); - - v2retry.property("foo", "bart"); - graph2.tx().commit(); - - try { - graph2.close(); - } catch (Exception ex) { - ex.printStackTrace(); - fail("Couldn't close graph2" + ex); + try { + graph2.close(); + } catch (Exception ex) { + ex.printStackTrace(); + fail("Couldn't close graph2" + ex); + } + + // Ensure that the retried transaction came through + Vertex v3 = getVertex(graph, vid); + assertEquals("bart", v3.value("foo")); + + Edge e3 = v3.edges(Direction.OUT).next(); + assertEquals("self", e3.label()); + assertEquals("bar", e3.value("foo")); + + e3.property("foo", "baz"); + assertEquals("self", e3.label()); + assertEquals("baz", e3.value("foo")); + + //TransactionalGraph graph3 = ((ThreadedTransactionalGraph)graph).newTransaction(); // WAS startTransaction prior to 2.3.0 port + Graph graph3 = graph.tx().createThreadedTx(); // TP3 version + Edge e4 = getEdge(graph3, eid); + + assertEquals("self", e4.label()); + assertEquals("bar", e4.value("foo")); + + e4.property("foo", "bart"); + assertEquals("self", e4.label()); + assertEquals("bart", e4.value("foo")); + + assertEquals(e4 + " doesnt' have foo: bart", "bart", e4.value("foo")); + + // Should pass + graph3.tx().commit(); + + // See if the changes from graph3 are seen here + Vertex v51 = graph3.vertices(vid).next(); + Edge e51 = v51.edges(Direction.OUT).next(); + + assertEquals("self", e51.label()); + assertEquals(e51 + " doesnt' have foo: bart", "bart", e51.value("foo")); + + try { + graph.tx().commit(); + fail("Failed optimistic concurrency test"); + } catch (BitsyRetryException ex) { + assertEquals(BitsyErrorCodes.CONCURRENT_MODIFICATION, ex.getErrorCode()); + } + + // See if the changes from graph3 are seen here + Vertex v5 = getVertex(graph, vid); + Edge e5 = v5.edges(Direction.OUT).next(); + + assertEquals("self", e5.label()); + assertEquals(e5 + " doesnt' have foo: bart", "bart", e5.value("foo")); + + // All old vertices should be dead + for (Element eN : new Element[] {v1, v2, v2retry, v3, e, e2, e3, e4}) { + try { + eN.value("foo"); + fail("dead Tx"); + } catch (BitsyException ex) { + assertEquals(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, ex.getErrorCode()); + } + } + + try { + graph.close(); + } catch (Exception ex) { + fail("Couldn't close graph " + ex); + } } - - // Ensure that the retried transaction came through - Vertex v3 = getVertex(graph, vid); - assertEquals("bart", v3.value("foo")); - - Edge e3 = v3.edges(Direction.OUT).next(); - assertEquals("self", e3.label()); - assertEquals("bar", e3.value("foo")); - - e3.property("foo", "baz"); - assertEquals("self", e3.label()); - assertEquals("baz", e3.value("foo")); - - //TransactionalGraph graph3 = ((ThreadedTransactionalGraph)graph).newTransaction(); // WAS startTransaction prior to 2.3.0 port - Graph graph3 = graph.tx().createThreadedTx(); // TP3 version - Edge e4 = getEdge(graph3, eid); - - assertEquals("self", e4.label()); - assertEquals("bar", e4.value("foo")); - - e4.property("foo", "bart"); - assertEquals("self", e4.label()); - assertEquals("bart", e4.value("foo")); - - assertEquals(e4 + " doesnt' have foo: bart", "bart", e4.value("foo")); - - // Should pass - graph3.tx().commit(); - - // See if the changes from graph3 are seen here - Vertex v51 = graph3.vertices(vid).next(); - Edge e51 = v51.edges(Direction.OUT).next(); - - assertEquals("self", e51.label()); - assertEquals(e51 + " doesnt' have foo: bart", "bart", e51.value("foo")); - - try { + */ + // Pun intended + public void testEdgeCases() { + assertEquals(BitsyIsolationLevel.READ_COMMITTED, ((BitsyGraph) graph).getDefaultIsolationLevel()); + for (BitsyIsolationLevel level : + new BitsyIsolationLevel[] {BitsyIsolationLevel.READ_COMMITTED, BitsyIsolationLevel.REPEATABLE_READ}) { + ((BitsyGraph) graph).setDefaultIsolationLevel(level); graph.tx().commit(); - fail("Failed optimistic concurrency test"); - } catch (BitsyRetryException ex) { - assertEquals(BitsyErrorCodes.CONCURRENT_MODIFICATION, ex.getErrorCode()); - } - - // See if the changes from graph3 are seen here - Vertex v5 = getVertex(graph, vid); - Edge e5 = v5.edges(Direction.OUT).next(); - - assertEquals("self", e5.label()); - assertEquals(e5 + " doesnt' have foo: bart", "bart", e5.value("foo")); - - // All old vertices should be dead - for (Element eN : new Element[] {v1, v2, v2retry, v3, e, e2, e3, e4}) { + + int numVertices = 4; + + Object[] vids = new Object[numVertices]; + Vertex[] verts = new Vertex[numVertices]; + + for (int i = 0; i < numVertices; i++) { + Vertex v = graph.addVertex(); + vids[i] = v.id(); + verts[i] = v; + } + + // Add an edge from 0 to 1 + Edge e01 = addEdge(graph, verts[0], verts[1], "one"); + Object e01Id = e01.id(); + + Edge e01Alt = addEdge(graph, verts[0], verts[1], "two"); + Object e01AltId = e01Alt.id(); + + Edge e12 = addEdge(graph, verts[1], verts[2], "empty"); // Empty string no longer allowed in TP3 + Object e12Id = e12.id(); + + Edge e23 = addEdge(graph, verts[2], verts[3], "three"); + Object e23Id = e23.id(); + + // Check if the edges are in + checkIterCount(verts[0].edges(Direction.OUT), 2); + checkIterCount(verts[0].edges(Direction.OUT, "one"), 1); + checkIterCount(verts[0].edges(Direction.OUT, "two"), 1); + + checkIterCount(verts[1].edges(Direction.OUT), 1); + checkIterCount(verts[1].edges(Direction.IN), 2); + + checkIterCount(verts[2].edges(Direction.OUT), 1); + checkIterCount(verts[2].edges(Direction.IN), 1); + + checkIterCount(verts[3].edges(Direction.IN, "three"), 1); + checkIterCount(verts[3].edges(Direction.IN, "threeX"), 0); + + // Transaction returns the same object on every get + for (int i = 0; i < numVertices; i++) { + assertSame(verts[i], getVertex(graph, vids[i])); + } + + assertSame(e01, getEdge(graph, e01.id())); + assertSame(e01Alt, getEdge(graph, e01Alt.id())); + assertSame(e12, getEdge(graph, e12.id())); + assertSame(e23, getEdge(graph, e23.id())); + + // Now commit + graph.tx().commit(); + + // Check to see if the vertices returned for the IDs are the same + for (int i = 0; i < numVertices; i++) { + if (level == BitsyIsolationLevel.REPEATABLE_READ) { + Vertex v = getVertex(graph, vids[i]); + assertNotNull(v); + assertSame(v, getVertex(graph, vids[i])); + } else { + Vertex v = getVertex(graph, vids[i]); + assertNotNull(v); + assertNotSame(getVertex(graph, vids[i]), getVertex(graph, vids[i])); + assertEquals(getVertex(graph, vids[i]), getVertex(graph, vids[i])); + assertEquals( + getVertex(graph, vids[i]).hashCode(), + getVertex(graph, vids[i]).hashCode()); + } + } + + // Check to see if mid-tx deletes work + for (int i = 0; i < numVertices; i++) { + verts[i] = getVertex(graph, vids[i]); + } + + // Check to see if the end points of edges are the same objects as the loaded vertices + e23 = getEdge(graph, e23.id()); + if (level == BitsyIsolationLevel.REPEATABLE_READ) { + assertSame(verts[2], e23.outVertex()); + assertSame(verts[3], e23.inVertex()); + } else { + assertEquals(verts[2].id(), e23.outVertex().id()); + assertEquals(verts[3].id(), e23.inVertex().id()); + } + + // Remove vertex 3 + removeVertex(graph, verts[2]); + + // The vertex should not be accessible try { - eN.value("foo"); - fail("dead Tx"); - } catch (BitsyException ex) { - assertEquals(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, ex.getErrorCode()); + verts[2].value("foo"); + fail("Can't access deleted vertex"); + } catch (BitsyException e) { + assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); } - } - try { - graph.close(); - } catch (Exception ex) { - fail("Couldn't close graph " + ex); + // The edge should not be accessible + try { + e23.value("foo"); + fail("Can't access deleted edge"); + } catch (BitsyException e) { + assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); + } + + // Check to see that e12 and e23 disappeared from the queries as well + checkIterCount(verts[3].edges(Direction.IN), 0); + checkIterCount(verts[1].edges(Direction.OUT), 0); + + // Now try to load an edge that was not previously in the transaction + e12 = getEdge(graph, e12Id); + + // ... but that edge won't be visible because of the deleted vertex + assertNull(e12); + + // Try the same for e23 + e23 = getEdge(graph, e23.id()); + assertNull(e23); + + // No commit and recheck + graph.tx().commit(); + + // Make sure old elements are deleted + assertNull(getVertex(graph, vids[2])); + assertNull(getEdge(graph, e23Id)); + assertNull(getEdge(graph, e12Id)); + + // Get an edge first + e01 = getEdge(graph, e01Id); + + // ... then vertices + for (int i = 0; i < numVertices; i++) { + verts[i] = getVertex(graph, vids[i]); + } + + // ... and make sure the endpoints are the same + if (level == BitsyIsolationLevel.REPEATABLE_READ) { + assertSame(e01.inVertex(), verts[1]); + assertSame(e01.outVertex(), verts[0]); + } else { + assertEquals(e01.inVertex().id(), verts[1].id()); + assertEquals(e01.outVertex().id(), verts[0].id()); + } + + // Now remove the edge + removeEdge(graph, e01); + + checkIterCount(verts[0].edges(Direction.OUT), 1); // only e01Alt lives + checkIterCount(verts[1].edges(Direction.IN), 1); // only e01Alt lives + + // The edge should not be accessible + try { + e01.inVertex(); + System.out.println("Fail!"); + fail("Can't access deleted edge"); + } catch (BitsyException e) { + assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); + } + + // But the vertex should be + e01Alt = getEdge(graph, e01AltId); + if (level == BitsyIsolationLevel.REPEATABLE_READ) { + assertSame(e01Alt.inVertex(), verts[1]); + assertSame(e01Alt.outVertex(), verts[0]); + } else { + assertEquals(e01Alt.inVertex().id(), verts[1].id()); + assertEquals(e01Alt.outVertex().id(), verts[0].id()); + } } - } -*/ - // Pun intended - public void testEdgeCases() { - assertEquals(BitsyIsolationLevel.READ_COMMITTED, ((BitsyGraph)graph).getDefaultIsolationLevel()); - for (BitsyIsolationLevel level : new BitsyIsolationLevel[] {BitsyIsolationLevel.READ_COMMITTED, BitsyIsolationLevel.REPEATABLE_READ}) { - ((BitsyGraph)graph).setDefaultIsolationLevel(level); - graph.tx().commit(); - - int numVertices = 4; - - Object[] vids = new Object[numVertices]; - Vertex[] verts = new Vertex[numVertices]; - - for (int i=0; i < numVertices; i++ ) { - Vertex v = graph.addVertex(); - vids[i] = v.id(); - verts[i] = v; - } - - // Add an edge from 0 to 1 - Edge e01 = addEdge(graph, verts[0], verts[1], "one"); - Object e01Id = e01.id(); - - Edge e01Alt = addEdge(graph, verts[0], verts[1], "two"); - Object e01AltId = e01Alt.id(); - - Edge e12 = addEdge(graph, verts[1], verts[2], "empty"); // Empty string no longer allowed in TP3 - Object e12Id = e12.id(); - - Edge e23 = addEdge(graph, verts[2], verts[3], "three"); - Object e23Id = e23.id(); - - // Check if the edges are in - checkIterCount(verts[0].edges(Direction.OUT), 2); - checkIterCount(verts[0].edges(Direction.OUT, "one"), 1); - checkIterCount(verts[0].edges(Direction.OUT, "two"), 1); - - checkIterCount(verts[1].edges(Direction.OUT), 1); - checkIterCount(verts[1].edges(Direction.IN), 2); - - checkIterCount(verts[2].edges(Direction.OUT), 1); - checkIterCount(verts[2].edges(Direction.IN), 1); - - checkIterCount(verts[3].edges(Direction.IN, "three"), 1); - checkIterCount(verts[3].edges(Direction.IN, "threeX"), 0); - - // Transaction returns the same object on every get - for (int i=0; i < numVertices; i++) { - assertSame(verts[i], getVertex(graph, vids[i])); - } - - assertSame(e01, getEdge(graph, e01.id())); - assertSame(e01Alt, getEdge(graph, e01Alt.id())); - assertSame(e12, getEdge(graph, e12.id())); - assertSame(e23, getEdge(graph, e23.id())); - - // Now commit - graph.tx().commit(); - - // Check to see if the vertices returned for the IDs are the same - for (int i=0; i < numVertices; i++) { - if (level == BitsyIsolationLevel.REPEATABLE_READ) { - Vertex v = getVertex(graph, vids[i]); - assertNotNull(v); - assertSame(v, getVertex(graph, vids[i])); - } else { - Vertex v = getVertex(graph, vids[i]); - assertNotNull(v); - assertNotSame(getVertex(graph, vids[i]), getVertex(graph, vids[i])); - assertEquals(getVertex(graph, vids[i]), getVertex(graph, vids[i])); - assertEquals(getVertex(graph, vids[i]).hashCode(), getVertex(graph, vids[i]).hashCode()); - } - } - - // Check to see if mid-tx deletes work - for (int i=0; i < numVertices; i++ ) { - verts[i] = getVertex(graph, vids[i]); - } - - // Check to see if the end points of edges are the same objects as the loaded vertices - e23 = getEdge(graph, e23.id()); - if (level == BitsyIsolationLevel.REPEATABLE_READ) { - assertSame(verts[2], e23.outVertex()); - assertSame(verts[3], e23.inVertex()); - } else { - assertEquals(verts[2].id(), e23.outVertex().id()); - assertEquals(verts[3].id(), e23.inVertex().id()); - } - - // Remove vertex 3 - removeVertex(graph, verts[2]); - - // The vertex should not be accessible - try { - verts[2].value("foo"); - fail("Can't access deleted vertex"); - } catch (BitsyException e) { - assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); - } - - // The edge should not be accessible - try { - e23.value("foo"); - fail("Can't access deleted edge"); - } catch (BitsyException e) { - assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); - } - - // Check to see that e12 and e23 disappeared from the queries as well - checkIterCount(verts[3].edges(Direction.IN), 0); - checkIterCount(verts[1].edges(Direction.OUT), 0); - - // Now try to load an edge that was not previously in the transaction - e12 = getEdge(graph, e12Id); - - // ... but that edge won't be visible because of the deleted vertex - assertNull(e12); - - // Try the same for e23 - e23 = getEdge(graph, e23.id()); - assertNull(e23); - - // No commit and recheck - graph.tx().commit(); - - // Make sure old elements are deleted - assertNull(getVertex(graph, vids[2])); - assertNull(getEdge(graph, e23Id)); - assertNull(getEdge(graph, e12Id)); - - // Get an edge first - e01 = getEdge(graph, e01Id); - - // ... then vertices - for (int i=0; i < numVertices; i++ ) { - verts[i] = getVertex(graph, vids[i]); - } - - // ... and make sure the endpoints are the same - if (level == BitsyIsolationLevel.REPEATABLE_READ) { - assertSame(e01.inVertex(), verts[1]); - assertSame(e01.outVertex(), verts[0]); - } else { - assertEquals(e01.inVertex().id(), verts[1].id()); - assertEquals(e01.outVertex().id(), verts[0].id()); - } - - // Now remove the edge - removeEdge(graph, e01); - - checkIterCount(verts[0].edges(Direction.OUT), 1); // only e01Alt lives - checkIterCount(verts[1].edges(Direction.IN), 1); // only e01Alt lives - - // The edge should not be accessible - try { - e01.inVertex(); - System.out.println("Fail!"); - fail("Can't access deleted edge"); - } catch (BitsyException e) { - assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); - } - - // But the vertex should be - e01Alt = getEdge(graph, e01AltId); - if (level == BitsyIsolationLevel.REPEATABLE_READ) { - assertSame(e01Alt.inVertex(), verts[1]); - assertSame(e01Alt.outVertex(), verts[0]); - } else { - assertEquals(e01Alt.inVertex().id(), verts[1].id()); - assertEquals(e01Alt.outVertex().id(), verts[0].id()); - } - } - - // Reset default isolation level - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); - graph.tx().commit(); + + // Reset default isolation level + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); + graph.tx().commit(); } public void testMultiThreadedEdgeQueries() throws IOException { @@ -1047,7 +1065,7 @@ public void testMultiThreadedEdgeQueries() throws IOException { final int numThreads = 100; ExecutorService service = Executors.newFixedThreadPool(numThreads + 2); long timeToTest = 10000; // 10 seconds - final long timeToStop = System.currentTimeMillis() + timeToTest; + final long timeToStop = System.currentTimeMillis() + timeToTest; service.submit(new Runnable() { @Override @@ -1055,33 +1073,33 @@ public void run() { try { int counter = 0; while (System.currentTimeMillis() < timeToStop) { - //System.out.println("Read iter"); + // System.out.println("Read iter"); counter++; Vertex v1 = getVertex(graph, v1Id); assertNotNull(v1); - + Vertex v2 = getVertex(graph, v2Id); assertNotNull(v2); - + validate(v1.edges(Direction.OUT), v1, v2); validate(v2.edges(Direction.IN), v1, v2); - + // This is to reload new vertices in REPEATABLE_READ mode (default) - graph.tx().rollback(); - + graph.tx().rollback(); + v1 = getVertex(graph, v1Id); assertNotNull(v1); - + v2 = getVertex(graph, v2Id); assertNotNull(v2); - + validate(v1.edges(Direction.OUT, "label34", "label17"), v1, v2, "label34", "label17"); validate(v2.edges(Direction.IN, "label87", "label39"), v1, v2, "label87", "label39"); - + // This is to reload new vertices in REPEATABLE_READ mode (default) graph.tx().rollback(); - //System.out.println("At " + counter + " read iterations"); + // System.out.println("At " + counter + " read iterations"); } System.out.println("Completed " + counter + " read iterations"); @@ -1089,15 +1107,15 @@ public void run() { setException(e); } } - + public void validate(Iterator edges, Vertex v1, Vertex v2, String... labels) { Map countMap = new HashMap(); List labelsToCheck = ((labels == null) || (labels.length == 0)) ? null : Arrays.asList(labels); while (edges.hasNext()) { - Edge e = edges.next(); - assertEquals(v1, e.outVertex()); + Edge e = edges.next(); + assertEquals(v1, e.outVertex()); assertEquals(v2, e.inVertex()); - + Integer key = e.value("count"); Integer value = countMap.get(key); if (value == null) { @@ -1105,22 +1123,27 @@ public void validate(Iterator edges, Vertex v1, Vertex v2, String... label } else { countMap.put(key, value + 1); } - + if (labelsToCheck != null) { - assertTrue("Could not find " + e.label() + " in " + labelsToCheck, labelsToCheck.contains(e.label())); + assertTrue( + "Could not find " + e.label() + " in " + labelsToCheck, + labelsToCheck.contains(e.label())); } } - + for (Map.Entry entry : countMap.entrySet()) { - //System.out.println("Checking count for " + entry.getKey()); - assertEquals("Transaction boundary not respected for " + entry.getKey() + ", got " + entry.getValue() + " edges", - 0, entry.getValue() % entry.getKey()); + // System.out.println("Checking count for " + entry.getKey()); + assertEquals( + "Transaction boundary not respected for " + entry.getKey() + ", got " + entry.getValue() + + " edges", + 0, + entry.getValue() % entry.getKey()); } } }); final int numEdges = 1; - for (int i=0; i < numThreads; i++) { + for (int i = 0; i < numThreads; i++) { final String label = "label" + i; final int count = i; @@ -1131,21 +1154,21 @@ public void run() { try { Object[] eids = new Object[count * numEdges]; int counter = 0; - + while (System.currentTimeMillis() < timeToStop) { - //System.out.println("Write iter"); + // System.out.println("Write iter"); Vertex v1 = getVertex(graph, v1Id); assertNotNull(v1); - + Vertex v2 = getVertex(graph, v2Id); assertNotNull(v2); - - for (int j=0; j < count; j++) { + + for (int j = 0; j < count; j++) { Edge e = v1.addEdge(label, v2); e.property("count", count); eids[counter++] = e.id(); } - + graph.tx().commit(); writeIters++; @@ -1164,7 +1187,7 @@ public void run() { } catch (InterruptedException e1) { e1.printStackTrace(); } - + // Clear and restart int pauseCounter = 0; for (Object eid : eids) { @@ -1183,15 +1206,15 @@ public void run() { } } } - + System.out.println("Completed " + writeIters + " write iterations"); } catch (Throwable e) { setException(e); } } - }); + }); } - + try { Thread.sleep(timeToTest + 1000); } catch (InterruptedException e) { @@ -1209,7 +1232,7 @@ public void run() { private void setException(Throwable t) { this.toThrow = t; } - + private Throwable getException() { return toThrow; } @@ -1229,21 +1252,21 @@ public void testMultiThreadedTreeCreation() throws IOException { setException(null); // Added for TP3 because the default is now READ_COMMITTED - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); Vertex rootV = graph.addVertex(); - final Object rootVid = rootV.id(); + final Object rootVid = rootV.id(); graph.tx().commit(); - final int rootDegree = 5; // 5! = 120 nodes -- keeping it low to increase chances of BitsyRetryException + final int rootDegree = 5; // 5! = 120 nodes -- keeping it low to increase chances of BitsyRetryException final int numThreads = 10; ExecutorService service = Executors.newFixedThreadPool(numThreads + 1); long timeToTest = 20000; // 20 seconds final String labelId = "child"; - final long timeToStop = System.currentTimeMillis() + timeToTest; + final long timeToStop = System.currentTimeMillis() + timeToTest; - for (int i=0; i < numThreads; i++) { + for (int i = 0; i < numThreads; i++) { service.submit(new Runnable() { @Override public void run() { @@ -1251,7 +1274,7 @@ public void run() { int createIters = 0; while (System.currentTimeMillis() < timeToStop) { Object vid = rootVid; - + int expectedDegree = rootDegree; while (expectedDegree > 0) { Thread.sleep(rand.nextInt(5)); // Sleep between 0 and 5ms; @@ -1263,13 +1286,13 @@ public void run() { int idx = rand.nextInt(expectedDegree); Iterator edgeIter = v.edges(Direction.OUT, labelId); while (edgeIter.hasNext()) { - Edge e = edgeIter.next(); + Edge e = edgeIter.next(); if (count == idx) { vid = e.inVertex().id(); } count++; } - + if (count > 0) { assertEquals(expectedDegree, count); expectedDegree--; @@ -1279,29 +1302,30 @@ public void run() { // Someone else removed the edges System.out.println("Got a concurrent mod exception -- expected behavior"); graph.tx().rollback(); - + break; } - + // This is the end because count is 0 if (expectedDegree == 0) { - // Leaf is OK. Creator is happy. + // Leaf is OK. Creator is happy. assertEquals("no", v.value("haschildren")); break; - } else { + } else { // Probability of 1/3 to create children if (rand.nextInt() % 3 == 0) { try { - //System.out.println("Adding nodes with expected degree " + expectedDegree); + // System.out.println("Adding nodes with expected degree " + + // expectedDegree); // Not at leaf v.property("haschildren", "yes"); - for (int i=0; i < expectedDegree; i++) { + for (int i = 0; i < expectedDegree; i++) { Vertex child = graph.addVertex(); child.property("haschildren", "no"); v.addEdge(labelId, child); } - + createIters++; graph.tx().commit(); } catch (BitsyRetryException e) { @@ -1310,12 +1334,12 @@ public void run() { graph.tx().rollback(); } } - + break; } } } - + System.out.println("Completed " + createIters + " create iterations"); } catch (Throwable e) { setException(e); @@ -1323,17 +1347,17 @@ public void run() { } }); } - + // Create the destructor service.submit(new Runnable() { @Override public void run() { try { int deleteIters = 0; - + while (System.currentTimeMillis() < timeToStop) { Object vid = rootVid; - + int expectedDegree = rootDegree; while (expectedDegree > 0) { Thread.sleep(rand.nextInt(5)); // Sleep between 0 and 5ms; @@ -1343,7 +1367,7 @@ public void run() { int idx = rand.nextInt(expectedDegree); Iterator edgeIter = v.edges(Direction.OUT, labelId); while (edgeIter.hasNext()) { - Edge e = edgeIter.next(); + Edge e = edgeIter.next(); if (count == idx) { vid = e.inVertex().id(); } @@ -1358,7 +1382,7 @@ public void run() { // There are children under this node -- toss a coin if (rand.nextInt(factorial(expectedDegree)) == 0) { try { - //System.out.println("Removing node with expected degree " + expectedDegree); + // System.out.println("Removing node with expected degree " + expectedDegree); // Remove this node and its children removeDesc(v); @@ -1370,7 +1394,7 @@ public void run() { System.out.println("Got a concurrent mod exception -- expected behavior"); graph.tx().rollback(); } - + break; } @@ -1378,7 +1402,7 @@ public void run() { expectedDegree--; } } - + System.out.println("Completed " + deleteIters + " delete iters"); } catch (Throwable e) { setException(e); @@ -1386,9 +1410,9 @@ public void run() { } private void removeDesc(Vertex v) { - Iterator vertIter = v.vertices(Direction.OUT); + Iterator vertIter = v.vertices(Direction.OUT); while (vertIter.hasNext()) { - Vertex childV = vertIter.next(); + Vertex childV = vertIter.next(); removeDesc(childV); childV.remove(); } @@ -1396,14 +1420,14 @@ private void removeDesc(Vertex v) { private int factorial(int count) { int ans = 1; - for (int i=1; i <= count; i++) { + for (int i = 1; i <= count; i++) { ans *= count; } return ans; } }); - + try { Thread.sleep(timeToTest + 1000); } catch (InterruptedException e) { @@ -1424,35 +1448,35 @@ private void checkIterCount(Iterator iter, int expectedCount) { iter.next(); count++; } - + assertEquals(expectedCount, count); } - + public void testPersistence() throws Exception { - BitsyGraph bGraph = (BitsyGraph)graph; - FileBackedMemoryGraphStore store = (FileBackedMemoryGraphStore)(bGraph.getStore()); - + BitsyGraph bGraph = (BitsyGraph) graph; + FileBackedMemoryGraphStore store = (FileBackedMemoryGraphStore) (bGraph.getStore()); + // Check defaults assertEquals(1000, bGraph.getMinLinesPerReorg()); assertEquals(4 * 1024 * 1024, bGraph.getTxLogThreshold()); assertEquals(1d, bGraph.getReorgFactor()); assertTrue(store.allowFullGraphScans()); - + // Add a little -- shouldn't flush int numVertices = 100; Object[] vids = new Object[numVertices]; Vertex[] verts = new Vertex[numVertices]; - - for (int i=0; i < numVertices; i++ ) { + + for (int i = 0; i < numVertices; i++) { Vertex v = graph.addVertex(); v.property("foo", "something \n multi-line"); vids[i] = v.id(); verts[i] = v; } - + // Commit graph.tx().commit(); - + // Make sure the number of lines are correct -- 100 + 1 header + 1 tx, 1 header in the other int txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); int txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1460,23 +1484,23 @@ public void testPersistence() throws Exception { int vB = lineCount(dbPath.resolve(Paths.get("vB.txt"))); int eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); int eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - - assertPair(102, 1, txA, txB); // 1 header + 100 V + 1 tx, 1 header + + assertPair(102, 1, txA, txB); // 1 header + 100 V + 1 tx, 1 header assertPair(0, 2, vA, eB); // An empty log is flushed in the beginning, hence 1, 2 assertPair(0, 2, eA, eB); - + // Add some edges -- shouldn't flush - for (int i=0; i < numVertices; i++ ) { + for (int i = 0; i < numVertices; i++) { verts[i] = getVertex(graph, vids[i]); } - - for (int i=1; i < numVertices; i++ ) { - addEdge(graph, verts[i-1], verts[i], "label\n with multi-lines"); + + for (int i = 1; i < numVertices; i++) { + addEdge(graph, verts[i - 1], verts[i], "label\n with multi-lines"); } // Commit graph.tx().commit(); - + // Make sure the number of lines are correct -- 100 + 1 header + 1 tx, 1 header in the other txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1484,22 +1508,22 @@ public void testPersistence() throws Exception { vB = lineCount(dbPath.resolve(Paths.get("vB.txt"))); eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - - assertPair(202, 1, txA, txB); // 1 header + 100 V + 1 tx + 99 E + 1tx, 1 header + + assertPair(202, 1, txA, txB); // 1 header + 100 V + 1 tx + 99 E + 1tx, 1 header assertPair(0, 2, vA, vB); // An empty log is flushed in the beginning, hence 2 assertPair(0, 2, eA, eB); - + // Trigger a flush bGraph.setTxLogThreshold(10); // 10 bytes -- definitely will trigger flush on next add - + // Add dummy vertex with no props #101 graph.addVertex(); graph.tx().commit(); - + // Wait for flush Thread.sleep(1000); - + // Make sure the number of lines are correct txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1507,26 +1531,27 @@ public void testPersistence() throws Exception { vB = lineCount(dbPath.resolve(Paths.get("vB.txt"))); eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - - assertPair(1, 1, txA, txB); // 1 header, 1 header + + assertPair(1, 1, txA, txB); // 1 header, 1 header assertPair(0, 104, vA, vB); // 1 header + 1 log (on load) + 101 V + 1 log (on copy) - assertPair(0, 102, eA, eB); // 1 header + 1 log (on load) + 99 E + 1 log (on copy) + assertPair(0, 102, eA, eB); // 1 header + 1 log (on load) + 99 E + 1 log (on copy) Path stage1 = tempDir("stage1"); bGraph.backup(stage1); - - // Set the min lines to a small value to trigger reorg -- more than 200 lines have been added, so the factor will kick in + + // Set the min lines to a small value to trigger reorg -- more than 200 lines have been added, so the factor + // will kick in bGraph.setMinLinesPerReorg(1); assertEquals(bGraph.getMinLinesPerReorg(), 1); - + // Add a dummy vertex #102 graph.addVertex(); graph.tx().commit(); - + // Wait for the flush followed by reorg Thread.sleep(2000); - + // Make sure the number of lines are correct txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1534,36 +1559,36 @@ public void testPersistence() throws Exception { vB = lineCount(dbPath.resolve(Paths.get("vB.txt"))); eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - - assertPair(1, 1, txA, txB); // 1 header, 1 header + + assertPair(1, 1, txA, txB); // 1 header, 1 header assertPair(0, 104, vA, vB); // 1 header + 102 V + 1 L - assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L - + assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L + Path stage2 = tempDir("stage2"); bGraph.backup(stage2); - + // Modify the vertices to see if that takes effect - for (int i=0; i < numVertices; i++ ) { + for (int i = 0; i < numVertices; i++) { // Using the string representation verts[i] = getVertex(graph, vids[i].toString()); verts[i].property("baz", new Date()); } graph.tx().commit(); - + // Lower reorg factor bGraph.setReorgFactor(0.0001d); bGraph.setMinLinesPerReorg(0); // Wait for the flush followed by reorg Thread.sleep(1000); - + // Add a dummy vertex #103 graph.addVertex(); graph.tx().commit(); - + // Wait for the flush followed by reorg Thread.sleep(2000); - + // Increase the min lines and the factor to still trigger the reorg bGraph.setMinLinesPerReorg(99); bGraph.setReorgFactor(0.3d); @@ -1577,25 +1602,25 @@ public void testPersistence() throws Exception { eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - assertPair(1, 1, txA, txB); // 1 header, 1 header + assertPair(1, 1, txA, txB); // 1 header, 1 header assertPair(0, 105, vA, vB); // 1 header + 103 V + 1 L - assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L - + assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L + Path stage3 = tempDir("stage3"); bGraph.backup(stage3); - + // Remove the vertices - for (int i=0; i < numVertices; i++ ) { + for (int i = 0; i < numVertices; i++) { verts[i] = getVertex(graph, vids[i].toString()); - + // This will remove both the vertex and edge removeVertex(graph, verts[i]); } graph.tx().commit(); - + // Wait for the flush followed by reorg Thread.sleep(1000); - + // Make sure the number of lines are correct txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1604,19 +1629,19 @@ public void testPersistence() throws Exception { eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - assertPair(1, 102, txA, txB); // 1 header, 1 H + 100V header + 1 T - //assertPair(0, 105, vA, vB); // 1 header + 103 V + 1 L + assertPair(1, 102, txA, txB); // 1 header, 1 H + 100V header + 1 T + // assertPair(0, 105, vA, vB); // 1 header + 103 V + 1 L assertPair(0, 106, vA, vB); // 1 header + 103 V + 1 L - //assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L - assertPair(0, 102, eA, eB); // 1 header + 99 E + 1 L + // assertPair(0, 101, eA, eB); // 1 header + 99 E + 1 L + assertPair(0, 102, eA, eB); // 1 header + 99 E + 1 L // Backup will flush the buffers explicitly. Reorg will follow after backup Path stage4 = tempDir("stage4"); bGraph.backup(stage4); - + // Wait for the flush followed by reorg Thread.sleep(2000); - + // Make sure the number of lines are correct txA = lineCount(dbPath.resolve(Paths.get("txA.txt"))); txB = lineCount(dbPath.resolve(Paths.get("txB.txt"))); @@ -1624,10 +1649,10 @@ public void testPersistence() throws Exception { vB = lineCount(dbPath.resolve(Paths.get("vB.txt"))); eA = lineCount(dbPath.resolve(Paths.get("eA.txt"))); eB = lineCount(dbPath.resolve(Paths.get("eB.txt"))); - - assertPair(1, 1, txA, txB); // 1 header, 1 header + + assertPair(1, 1, txA, txB); // 1 header, 1 header assertPair(0, 5, vA, vB); // 1 header + 3 dummy V + 1 L - assertPair(0, 2, eA, eB); // 1 header + 0 E + 1 L + assertPair(0, 2, eA, eB); // 1 header + 0 E + 1 L } private void assertPair(int a, int b, int c, int d) { @@ -1638,108 +1663,114 @@ private void assertPair(int a, int b, int c, int d) { assertEquals(b, c); } } - + private int lineCount(Path file) throws Exception { - InputStream is = new FileInputStream(file.toFile()); + InputStream is = Files.newInputStream(file); assertNotNull(is); BufferedReader br = new BufferedReader(new InputStreamReader(is, FileBackedMemoryGraphStore.utf8)); - + int ans = 0; String line = null; while ((line = br.readLine()) != null) { ans++; } - + br.close(); is.close(); - + return ans; } - + public void testLargeFileSaveLoad() throws Exception { - BitsyGraph bGraph = (BitsyGraph)graph; - + BitsyGraph bGraph = (BitsyGraph) graph; + if (!(bGraph.getStore() instanceof FileBackedMemoryGraphStore)) { return; } - - FileBackedMemoryGraphStore store = (FileBackedMemoryGraphStore)(bGraph.getStore()); - + + FileBackedMemoryGraphStore store = (FileBackedMemoryGraphStore) (bGraph.getStore()); + // Check defaults assertEquals(1000, bGraph.getMinLinesPerReorg()); assertEquals(4 * 1024 * 1024, bGraph.getTxLogThreshold()); assertEquals(1d, bGraph.getReorgFactor()); assertTrue(store.allowFullGraphScans()); - + // Add a little -- shouldn't flush int numCommit = 1000; // 5000 int numPerCommit = 100; // 1000 int numVertices = numCommit * numPerCommit; - - //Object[] vids = new Object[numVertices]; - //Vertex[] verts = new Vertex[numVertices]; + + // Object[] vids = new Object[numVertices]; + // Vertex[] verts = new Vertex[numVertices]; long ts = System.currentTimeMillis(); Vertex prevV = null; - for (int i=0; i < numVertices; i++ ) { + for (int i = 0; i < numVertices; i++) { Vertex v = graph.addVertex(); v.property("foo", "bar"); v.property("count", i); - //vids[i] = v.getId(); - //verts[i] = v; - + // vids[i] = v.getId(); + // verts[i] = v; + if (prevV != null) { addEdge(graph, prevV, v, "test"); } - + if (i % numPerCommit == 0) { prevV = null; - //System.out.println("Commit"); - graph.tx().commit(); + // System.out.println("Commit"); + graph.tx().commit(); } else { prevV = v; } } - + // Commit graph.tx().commit(); double duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); + System.out.println("Took " + duration + "ms to insert " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); bGraph.flushTxLog(); - + duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to insert and flush " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); - + System.out.println("Took " + duration + "ms to insert and flush " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); + // Restart a few times - for (int j=0; j<3; j++) { + for (int j = 0; j < 3; j++) { ts = System.currentTimeMillis(); tearDown(); - + duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to shut down graph with " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); + System.out.println("Took " + duration + "ms to shut down graph with " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); ts = System.currentTimeMillis(); - setUp(false); + doSetUp(false); duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to load " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); - + System.out.println("Took " + duration + "ms to load " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); + ts = System.currentTimeMillis(); checkIterCount(graph.vertices(), numVertices); duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to query " + numVertices + " vertices. Rate = " + (duration / numVertices) + "ms per vertex"); - } + System.out.println("Took " + duration + "ms to query " + numVertices + " vertices. Rate = " + + (duration / numVertices) + "ms per vertex"); + } } public void XtestMultiThreadedCommits() throws Exception { for (int numThreads : new int[] {1, 2, 3, 4, 5, 10, 25, 50, 100, 150, 250, 500, 750, 1000}) { - final int numVerticesPerThread = (numThreads <= 10 ? 10000 : (numThreads <= 100 ? 100000 : 100000)) / numThreads; + final int numVerticesPerThread = + (numThreads <= 10 ? 10000 : (numThreads <= 100 ? 100000 : 100000)) / numThreads; int numElements = 2 * numVerticesPerThread * numThreads; - + ExecutorService service = Executors.newFixedThreadPool(numThreads); final Object[] startVertex = new Object[numThreads]; @@ -1763,25 +1794,26 @@ public void run() { addEdge(graph, prevV, v, TEST_LABEL); } graph.tx().commit(); - + prevId = v.id(); } - - System.out.println("Thread " + tid + " is done"); + + System.out.println("Thread " + tid + " is done"); cdl.countDown(); } }); } - + cdl.await(); double duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to save " + numElements + " vertices+edges. Rate = " + (duration / numElements) + "ms per vertex. TPS = " + ((double)numElements * 1000 / duration)); - + System.out.println("Took " + duration + "ms to save " + numElements + " vertices+edges. Rate = " + + (duration / numElements) + "ms per vertex. TPS = " + ((double) numElements * 1000 / duration)); + // Wait 10 seconds between tests Thread.sleep(10000); - - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); + + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); final CountDownLatch cdl2 = new CountDownLatch(numThreads); ts = System.currentTimeMillis(); for (int i = 0; i < numThreads; i++) { @@ -1790,7 +1822,7 @@ public void run() { service.submit(new Runnable() { @Override public void run() { - for (int k=0; k < 100; k++) { + for (int k = 0; k < 100; k++) { int count = 0; Vertex v = getVertex(graph, startVertex[tid]); @@ -1808,11 +1840,11 @@ public void run() { if (numVerticesPerThread != count + 1) { System.out.println("Mistmatch between " + numVerticesPerThread + " and " + count); } - + graph.tx().commit(); } - - System.out.println("Thread " + tid + " is done"); + + System.out.println("Thread " + tid + " is done"); cdl2.countDown(); } }); @@ -1821,19 +1853,20 @@ public void run() { cdl2.await(); duration = System.currentTimeMillis() - ts; - System.out.println("Took " + duration + "ms to query " + numElements + " vertices+edge 100 times. Rate = " + (duration / numElements) + "ms per vertex. TPS = " + ((double)numElements * 100000 / duration)); - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); + System.out.println("Took " + duration + "ms to query " + numElements + " vertices+edge 100 times. Rate = " + + (duration / numElements) + "ms per vertex. TPS = " + ((double) numElements * 100000 / duration)); + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); service.shutdown(); // Uncomment to look at memory usage -// Thread.sleep(1000); -// System.gc(); -// Thread.sleep(30000); + // Thread.sleep(1000); + // System.gc(); + // Thread.sleep(30000); // Clear graph tearDown(); - setUp(true); + doSetUp(true); } } @@ -1847,19 +1880,19 @@ public void XtestMultiThreadedReadsOnBipartiteGraph() throws Exception { final String label = "test"; final Object[] outVertices = new Object[partSize]; final Object[] inVertices = new Object[partSize]; - + // Vertices - for (int i=0; i < partSize; i++) { + for (int i = 0; i < partSize; i++) { outVertices[i] = graph.addVertex().id(); inVertices[i] = graph.addVertex().id(); - + if (i % numPerCommit == 0) { graph.tx().commit(); } } - + // Edges - for (int i=0; i < partSize; i++) { + for (int i = 0; i < partSize; i++) { Vertex outVertex = getVertex(graph, outVertices[i]); outVertex.addEdge(label, getVertex(graph, inVertices[(5 * i + 1) % partSize])); outVertex.addEdge(label, getVertex(graph, inVertices[(5 * i + 4) % partSize])); @@ -1872,41 +1905,41 @@ public void XtestMultiThreadedReadsOnBipartiteGraph() throws Exception { graph.tx().commit(); final int numRuns = 3; - Map calcStrMap = new HashMap(); - - for (int run=0; run < numRuns; run++) { - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); + Map calcStrMap = new HashMap<>(); + + for (int run = 0; run < numRuns; run++) { + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); for (final int numThreads : new int[] {1, 2, 3, 4, 5, 10, 25, 50, 100, 150, 250, 500, 750, 1000}) { ExecutorService service = Executors.newFixedThreadPool(numThreads); - + final CountDownLatch cdl = new CountDownLatch(numThreads); long ts = System.currentTimeMillis(); - - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); + + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.READ_COMMITTED); System.out.println("Running bi-partite read test with " + numThreads + " threads"); for (int i = 0; i < numThreads; i++) { final int tid = i; - //System.out.println("Scheduling read work for thread " + tid); + // System.out.println("Scheduling read work for thread " + tid); service.submit(new Runnable() { @Override public void run() { try { Vertex v = getVertex(graph, outVertices[0]); - for (int k=0; k < 100 * numIters / numThreads; k++) { + for (int k = 0; k < 100 * numIters / numThreads; k++) { assertNotNull(v); - + Vertex nextV = randomVertex(v.vertices(Direction.OUT, label)); - + assertNotNull(nextV); - + // Take a random edge back - Vertex backV = randomVertex(nextV.vertices(Direction.IN)); + Vertex backV = randomVertex(nextV.vertices(Direction.IN)); if (backV != null) { v = backV; } } - - //System.out.println("Thread " + tid + " is done"); + + // System.out.println("Thread " + tid + " is done"); } catch (Throwable t) { setException(t); } finally { @@ -1917,10 +1950,10 @@ public void run() { private Vertex randomVertex(Iterator vertices) { List options = new ArrayList(); while (vertices.hasNext()) { - Vertex option = vertices.next(); + Vertex option = vertices.next(); options.add(option); } - + if (options.isEmpty()) { return null; } else { @@ -1929,18 +1962,20 @@ private Vertex randomVertex(Iterator vertices) { } }); } - + cdl.await(); - + if (getException() != null) { throw new RuntimeException("Error in testMultiThreadedReadsOnBipartiteGraph", getException()); } - + service.shutdown(); - + long duration = System.currentTimeMillis() - ts; - double tps = ((double)numElements * 100000 / duration); - System.out.println("Took " + duration + "ms to query " + numElements + " vertices+edge 100 times. Rate = " + (duration / numElements) + "ms per vertex. TPS = " + tps); + double tps = ((double) numElements * 100000 / duration); + System.out.println( + "Took " + duration + "ms to query " + numElements + " vertices+edge 100 times. Rate = " + + (duration / numElements) + "ms per vertex. TPS = " + tps); String calcStr = calcStrMap.get(numThreads); if (calcStr == null) { @@ -1954,109 +1989,109 @@ private Vertex randomVertex(Iterator vertices) { for (Map.Entry entry : calcStrMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue() + ")/3"); } - - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); + + ((BitsyGraph) graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); } // TODO: Uncomment after supporting threaded transactions -/* - public void testConcurrentAccessForIndexes() { - // Create an index - ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); - ((BitsyGraph)graph).createKeyIndex("testKey", Vertex.class); - - for (BitsyIsolationLevel level : new BitsyIsolationLevel[] {BitsyIsolationLevel.REPEATABLE_READ, BitsyIsolationLevel.READ_COMMITTED}) { - ((BitsyGraph)graph).setDefaultIsolationLevel(level); - graph.tx().commit(); - - Vertex v = graph.addVertex(); - v.property("testKey", "foo"); - - graph.tx().commit(); - - Vertex v1 = graph.addVertex(); - v1.property("testKey", "foo"); - - // Don't commit yet - //TransactionalGraph anotherGraph = ((ThreadedTransactionalGraph)graph).newTransaction(); - Graph anotherGraph = graph.tx().createThreadedTx(); // TP3 version - Iterator indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); - - checkIterCount(indexResult, 1); // Queried before the commit - - // Now commit the new vertex - graph.tx().commit(); - - indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); - checkIterCount(indexResult, 2); // Queried after the commit -- the iterator refreshes itself - anotherGraph.tx().commit(); - - //anotherGraph = ((ThreadedTransactionalGraph)graph).newTransaction(); - anotherGraph = graph.tx().createThreadedTx(); - indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); - checkIterCount(indexResult, 2); // Queried after the commit - anotherGraph.tx().commit(); - - getVertex(graph, v.id()).remove(); - getVertex(graph, v1.id()).remove(); - graph.tx().commit(); - } - - ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); - // Drop the index - ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); - } -*/ - + /* + public void testConcurrentAccessForIndexes() { + // Create an index + ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); + ((BitsyGraph)graph).createKeyIndex("testKey", Vertex.class); + + for (BitsyIsolationLevel level : new BitsyIsolationLevel[] {BitsyIsolationLevel.REPEATABLE_READ, BitsyIsolationLevel.READ_COMMITTED}) { + ((BitsyGraph)graph).setDefaultIsolationLevel(level); + graph.tx().commit(); + + Vertex v = graph.addVertex(); + v.property("testKey", "foo"); + + graph.tx().commit(); + + Vertex v1 = graph.addVertex(); + v1.property("testKey", "foo"); + + // Don't commit yet + //TransactionalGraph anotherGraph = ((ThreadedTransactionalGraph)graph).newTransaction(); + Graph anotherGraph = graph.tx().createThreadedTx(); // TP3 version + Iterator indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); + + checkIterCount(indexResult, 1); // Queried before the commit + + // Now commit the new vertex + graph.tx().commit(); + + indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); + checkIterCount(indexResult, 2); // Queried after the commit -- the iterator refreshes itself + anotherGraph.tx().commit(); + + //anotherGraph = ((ThreadedTransactionalGraph)graph).newTransaction(); + anotherGraph = graph.tx().createThreadedTx(); + indexResult = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo"); + checkIterCount(indexResult, 2); // Queried after the commit + anotherGraph.tx().commit(); + + getVertex(graph, v.id()).remove(); + getVertex(graph, v1.id()).remove(); + graph.tx().commit(); + } + + ((BitsyGraph)graph).setDefaultIsolationLevel(BitsyIsolationLevel.REPEATABLE_READ); + // Drop the index + ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); + } + */ + // TODO: Uncomment after supporting threaded transaction -/* - public void testConcurrentAccessForIndexes2() { - // Create an index - ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); - ((BitsyGraph)graph).createKeyIndex("testKey", Vertex.class); - - for (BitsyIsolationLevel level : new BitsyIsolationLevel[] {BitsyIsolationLevel.READ_COMMITTED, BitsyIsolationLevel.REPEATABLE_READ}) { - System.out.println("Testing for " + level); - Vertex v = graph.addVertex(); - v.property("testKey", "foo"); - - graph.tx().commit(); - - // Now read the vertex - ((BitsyGraph)graph).setTxIsolationLevel(level); - Vertex vBak = getVertex(graph, v.id()); - - // ... and update it in a different thread - //TransactionalGraph anotherGraph = graph.newTransaction(); - Graph anotherGraph = graph.tx().createThreadedTx(); - Vertex v2 = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo").next(); - v2.property("testKey", "bar"); - anotherGraph.tx().commit(); - Vertex vBak2 = getVertex(anotherGraph, v2.id()); - - // Re-query the old version with the new value - if (level == BitsyIsolationLevel.READ_COMMITTED) { - Vertex vQuery = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "bar").next(); - vQuery.property("testKey", "baz"); - // Now commit the new vertex -- should succeed - graph.tx().commit(); - } else { - // TODO: Identify why this fails with TP3... - //assertFalse(((BitsyGraph)anotherGraph).verticesByIndex("testKey", "bar").hasNext()); - } - } - - // Drop the index - ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); - } -*/ - + /* + public void testConcurrentAccessForIndexes2() { + // Create an index + ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); + ((BitsyGraph)graph).createKeyIndex("testKey", Vertex.class); + + for (BitsyIsolationLevel level : new BitsyIsolationLevel[] {BitsyIsolationLevel.READ_COMMITTED, BitsyIsolationLevel.REPEATABLE_READ}) { + System.out.println("Testing for " + level); + Vertex v = graph.addVertex(); + v.property("testKey", "foo"); + + graph.tx().commit(); + + // Now read the vertex + ((BitsyGraph)graph).setTxIsolationLevel(level); + Vertex vBak = getVertex(graph, v.id()); + + // ... and update it in a different thread + //TransactionalGraph anotherGraph = graph.newTransaction(); + Graph anotherGraph = graph.tx().createThreadedTx(); + Vertex v2 = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "foo").next(); + v2.property("testKey", "bar"); + anotherGraph.tx().commit(); + Vertex vBak2 = getVertex(anotherGraph, v2.id()); + + // Re-query the old version with the new value + if (level == BitsyIsolationLevel.READ_COMMITTED) { + Vertex vQuery = ((BitsyGraph)anotherGraph).verticesByIndex("testKey", "bar").next(); + vQuery.property("testKey", "baz"); + // Now commit the new vertex -- should succeed + graph.tx().commit(); + } else { + // TODO: Identify why this fails with TP3... + //assertFalse(((BitsyGraph)anotherGraph).verticesByIndex("testKey", "bar").hasNext()); + } + } + + // Drop the index + ((BitsyGraph)graph).dropKeyIndex("testKey", Vertex.class); + } + */ + public void testConcurrentAccessForVersions() throws InterruptedException { Vertex v = graph.addVertex(); - final Object vid = v.id(); + final Object vid = v.id(); v.property("testKey", "foo"); graph.tx().commit(); - + v = getVertex(graph, vid); assertEquals("foo", v.value("testKey")); @@ -2067,58 +2102,58 @@ public void run() { graph.tx().commit(); } }; - + t.start(); t.join(); - + assertEquals("foo", v.value("testKey")); try { v.property("testKey", "baz"); graph.tx().commit(); - + fail("Should throw concurrent mod exception"); } catch (BitsyRetryException e) { // Ignore } - + v = getVertex(graph, vid); assertEquals("bar", v.value("testKey")); v.property("testKey", "baz"); assertEquals("baz", v.value("testKey")); graph.tx().commit(); - + v = getVertex(graph, vid); Vertex v2 = graph.addVertex(); - + Edge e12 = v.addEdge("foo", v2); - + v.remove(); removeVertex(graph, v2); - + try { v.remove(); fail("Should throw exception"); } catch (BitsyException e) { assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); } - + try { e12.remove(); } catch (BitsyException e) { assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); - } - + } + try { v2.remove(); fail("Should throw exception"); } catch (BitsyException e) { assertEquals(BitsyErrorCodes.ELEMENT_ALREADY_DELETED, e.getErrorCode()); } - + graph.tx().commit(); } - + public void testLargeDegreePerformance() { long ts = System.currentTimeMillis(); @@ -2142,8 +2177,8 @@ public void testLargeDegreePerformance() { one = graph.vertices(oneId).next(); } } - - for (int i=0; i < numVertices; i++) { + + for (int i = 0; i < numVertices; i++) { Vertex v = getVertex(graph, vids[i]); Iterator iter = v.edges(Direction.BOTH); @@ -2155,16 +2190,16 @@ public void testLargeDegreePerformance() { if (i % 1000 == 0) { System.out.println(i + " 1000 in " + (System.currentTimeMillis() - ts)); - + if (i % 5000 == 0) { Iterator iter2 = getVertex(graph, one.id()).edges(Direction.BOTH); - for (int j=0; j < numVertices - i - 1; j++) { + for (int j = 0; j < numVertices - i - 1; j++) { assertTrue(iter2.hasNext()); iter2.next(); } assertFalse(iter.hasNext()); } - + ts = System.currentTimeMillis(); graph.tx().commit(); diff --git a/src/test/java/com/lambdazen/bitsy/BitsyMemGraphIT.java b/src/test/java/com/lambdazen/bitsy/BitsyMemGraphIT.java index 1435e91..ca37e99 100644 --- a/src/test/java/com/lambdazen/bitsy/BitsyMemGraphIT.java +++ b/src/test/java/com/lambdazen/bitsy/BitsyMemGraphIT.java @@ -1,55 +1,56 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.store.Record; +import com.lambdazen.bitsy.store.Record.RecordType; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; -import com.lambdazen.bitsy.store.Record; -import com.lambdazen.bitsy.store.Record.RecordType; - -public class BitsyMemGraphIT extends BitsyGraphIT -{ +public class BitsyMemGraphIT extends BitsyGraphIT { public boolean isPersistent() { return false; } - + public void setUp() { System.out.println("Setting up memory-only graph"); graph = new BitsyGraph(false); } - + public void tearDown() { System.out.println("Tearing down graph"); try { - graph.close(); + graph.close(); } catch (Exception e) { - throw new RuntimeException("Couldn't close", e); + throw new RuntimeException("Couldn't close", e); } } public void testPersistence() { // Disable } - + public void testObsolescence() { - IGraphStore store = ((BitsyGraph)graph).getStore(); - + IGraphStore store = ((BitsyGraph) graph).getStore(); + // Create a vertex Vertex v = graph.addVertex(); Object vid = v.id(); v.property("foo", "bar"); - + // Self edge Edge e = v.addEdge("self", v); Object eid = e.id(); - + graph.tx().commit(); Record v1MRec = new Record(RecordType.V, "{\"id\":\"" + vid + "\",\"v\":1,\"s\":\"M\"}"); assertFalse(v1MRec.checkObsolete(store, false, 1, null)); assertFalse(v1MRec.checkObsolete(store, true, 1, null)); - Record e1MRec = new Record(RecordType.E, "{\"id\":\"" + eid + "\",\"v\":1,\"s\":\"M\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + "\"}"); + Record e1MRec = new Record( + RecordType.E, + "{\"id\":\"" + eid + "\",\"v\":1,\"s\":\"M\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + + "\"}"); assertFalse(e1MRec.checkObsolete(store, false, 1, null)); assertFalse(e1MRec.checkObsolete(store, true, 1, null)); @@ -64,7 +65,7 @@ public void testObsolescence() { Record v2MRec = new Record(RecordType.V, "{\"id\":\"" + vid + "\",\"v\":2,\"s\":\"M\"}"); Record v1DRec = new Record(RecordType.V, "{\"id\":\"" + vid + "\",\"v\":1,\"s\":\"D\"}"); - + assertTrue(v1MRec.checkObsolete(store, false, 1, null)); assertTrue(v1MRec.checkObsolete(store, true, 1, null)); @@ -74,9 +75,15 @@ public void testObsolescence() { assertFalse(v2MRec.checkObsolete(store, false, 1, null)); assertFalse(v2MRec.checkObsolete(store, true, 1, null)); - Record e2MRec = new Record(RecordType.E, "{\"id\":\"" + eid + "\",\"v\":2,\"s\":\"M\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + "\"}"); - Record e1DRec = new Record(RecordType.E, "{\"id\":\"" + eid + "\",\"v\":1,\"s\":\"D\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + "\"}"); - + Record e2MRec = new Record( + RecordType.E, + "{\"id\":\"" + eid + "\",\"v\":2,\"s\":\"M\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + + "\"}"); + Record e1DRec = new Record( + RecordType.E, + "{\"id\":\"" + eid + "\",\"v\":1,\"s\":\"D\",\"o\":\"" + vid + "\",\"l\":\"" + vid + "\",\"i\":\"" + vid + + "\"}"); + assertTrue(e1MRec.checkObsolete(store, false, 1, null)); assertTrue(e1MRec.checkObsolete(store, true, 1, null)); @@ -91,12 +98,11 @@ public void testObsolescence() { v.remove(); // Edge will get deleted automatically! - + graph.tx().commit(); - + Record v2DRec = new Record(RecordType.V, "{\"id\":\"" + vid + "\",\"v\":1,\"s\":\"D\"}"); assertFalse(v2DRec.checkObsolete(store, false, 1, null)); assertTrue(v2DRec.checkObsolete(store, true, 1, null)); } - } diff --git a/src/test/java/com/lambdazen/bitsy/FileBasedTestCase.java b/src/test/java/com/lambdazen/bitsy/FileBasedTestCase.java index 2cfc0e8..0ba827e 100644 --- a/src/test/java/com/lambdazen/bitsy/FileBasedTestCase.java +++ b/src/test/java/com/lambdazen/bitsy/FileBasedTestCase.java @@ -6,16 +6,15 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - import junit.framework.TestCase; public class FileBasedTestCase extends TestCase { public Path tempDir(String dirName) throws IOException { return tempDir(dirName, true); } - + public Path tempDir(String dirName, boolean delete) throws IOException { - String clsUri = this.getClass().getName().replace('.','/') + ".class"; + String clsUri = this.getClass().getName().replace('.', '/') + ".class"; URL url = this.getClass().getClassLoader().getResource(clsUri); String clsPath = url.getPath(); System.out.println(clsPath); @@ -23,15 +22,15 @@ public Path tempDir(String dirName, boolean delete) throws IOException { System.out.println(dir); Path root = Paths.get(dir).resolve("../" + dirName).normalize(); System.out.println(root); - + if (!Files.exists(root)) { Files.createDirectory(root); } - + if (delete) { deleteDirectory(root.toFile(), false); } - + return root; } @@ -44,13 +43,13 @@ protected static void deleteDirectory(final File directory, boolean deleteDir) { file.delete(); } } - + if (deleteDir) { directory.delete(); } } } - + public void testDummy() throws IOException { tempDir("temp-dir"); } diff --git a/src/test/java/com/lambdazen/bitsy/RecoveryTest.java b/src/test/java/com/lambdazen/bitsy/RecoveryTest.java index a74ce89..51b4bb8 100644 --- a/src/test/java/com/lambdazen/bitsy/RecoveryTest.java +++ b/src/test/java/com/lambdazen/bitsy/RecoveryTest.java @@ -1,5 +1,6 @@ package com.lambdazen.bitsy; +import com.lambdazen.bitsy.store.LoadTask; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -7,13 +8,9 @@ import java.nio.file.StandardCopyOption; import java.util.Iterator; -import com.lambdazen.bitsy.store.LoadTask; - public class RecoveryTest extends FileBasedTestCase { - public RecoveryTest() { - - } - + public RecoveryTest() {} + public void testPartialTx() throws Exception { for (long minSizeForParallelLoader : new long[] {10, 1024 * 1024}) { // Try with both the parallel and serial loaders @@ -23,29 +20,27 @@ public void testPartialTx() throws Exception { Path rootPath = Paths.get(url.toURI()); System.out.println("Path = " + rootPath); - String[] fileNames = new String[] {"txA.txt", "txB.txt", "vA.txt", "vB.txt", "eA.txt", "eB.txt", "metaA.txt", "metaB.txt"}; + String[] fileNames = + new String[] {"txA.txt", "txB.txt", "vA.txt", "vB.txt", "eA.txt", "eB.txt", "metaA.txt", "metaB.txt" + }; Path targetDir = tempDir("recoverytest"); - String[] paths = { - "stage1", - "stage2", - "stage3", - "stage4", - "stage5", - "stage6", - "stage7"}; + String[] paths = {"stage1", "stage2", "stage3", "stage4", "stage5", "stage6", "stage7"}; int[] vCounts = new int[] {50, 50, 100, 75, 75, 101, 101}; int[] eCounts = new int[] {0, 0, 0, 0, 0, 99, 99}; - for (int i=0; i < paths.length; i++) { + for (int i = 0; i < paths.length; i++) { System.out.println("Deleting " + targetDir); deleteDirectory(targetDir.toFile(), false); Path sourceDir = rootPath.resolve("./" + paths[i]).normalize(); System.out.println("Copying from " + sourceDir); for (String fileName : fileNames) { - Files.copy(sourceDir.resolve(fileName), targetDir.resolve(fileName), StandardCopyOption.REPLACE_EXISTING); + Files.copy( + sourceDir.resolve(fileName), + targetDir.resolve(fileName), + StandardCopyOption.REPLACE_EXISTING); } BitsyGraph graph = new BitsyGraph(targetDir); @@ -56,16 +51,14 @@ public void testPartialTx() throws Exception { } } } - + private void checkIterCount(Iterator iter, int expectedCount) { int count = 0; while (iter.hasNext()) { iter.next(); count++; } - + assertEquals(expectedCount, count); } - - } diff --git a/src/test/java/com/lambdazen/bitsy/ads/dict/DictionaryTest.java b/src/test/java/com/lambdazen/bitsy/ads/dict/DictionaryTest.java index 6d59f75..344c130 100644 --- a/src/test/java/com/lambdazen/bitsy/ads/dict/DictionaryTest.java +++ b/src/test/java/com/lambdazen/bitsy/ads/dict/DictionaryTest.java @@ -3,19 +3,18 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; - import junit.framework.TestCase; public class DictionaryTest extends TestCase { private Random rand = new Random(); - + public void testBasicExpandContract() { Dictionary dict = new Dictionary1("foo", "bar"); - + assertEquals(1, dict.getPropertyKeys().length); assertEquals("foo", dict.getPropertyKeys()[0]); assertEquals("bar", dict.getProperty("foo")); - + dict = dict.setProperty("foo", "baz"); assertEquals(Dictionary1.class, dict.getClass()); @@ -25,12 +24,12 @@ public void testBasicExpandContract() { // Move up dict = dict.setProperty("foo1", "bar1"); - + assertEquals(Dictionary2.class, dict.getClass()); assertEquals(2, dict.getPropertyKeys().length); assertEquals("baz", dict.getProperty("foo")); assertEquals("bar1", dict.getProperty("foo1")); - + // Move down dict = dict.removeProperty("foo"); assertEquals(Dictionary1.class, dict.getClass()); @@ -39,32 +38,32 @@ public void testBasicExpandContract() { // Move up dict = dict.setProperty("foo2", "bar2"); - + assertEquals(Dictionary2.class, dict.getClass()); assertEquals(2, dict.getPropertyKeys().length); assertEquals("bar1", dict.getProperty("foo1")); assertEquals("bar2", dict.getProperty("foo2")); - + // Overwrite foo2 dict = dict.setProperty("foo2", "baz2"); - + assertEquals(Dictionary2.class, dict.getClass()); assertEquals(2, dict.getPropertyKeys().length); assertEquals("bar1", dict.getProperty("foo1")); assertEquals("baz2", dict.getProperty("foo2")); - + // Move up to 3 dict = dict.setProperty("foo3", "bar3"); - + assertEquals(Dictionary3.class, dict.getClass()); assertEquals(3, dict.getPropertyKeys().length); assertEquals("bar1", dict.getProperty("foo1")); assertEquals("baz2", dict.getProperty("foo2")); assertEquals("bar3", dict.getProperty("foo3")); - + // Overwrite foo1 dict = dict.setProperty("foo1", "baz1"); - + assertEquals(Dictionary3.class, dict.getClass()); assertEquals(3, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); @@ -73,7 +72,7 @@ public void testBasicExpandContract() { // Move up to 4 dict = dict.setProperty("foo4", "bar4"); - + assertEquals(Dictionary4.class, dict.getClass()); assertEquals(4, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); @@ -83,7 +82,7 @@ public void testBasicExpandContract() { // Move up to 5 dict = dict.setProperty("foo5", "bar5"); - + assertEquals(Dictionary6.class, dict.getClass()); assertEquals(5, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); @@ -94,7 +93,7 @@ public void testBasicExpandContract() { // Move up to 6 dict = dict.setProperty("foo6", "bar6"); - + assertEquals(Dictionary6.class, dict.getClass()); assertEquals(6, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); @@ -107,7 +106,7 @@ public void testBasicExpandContract() { // Move down to 5 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo3"); - + assertEquals(Dictionary6.class, dict.getClass()); assertEquals(5, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); @@ -119,37 +118,37 @@ public void testBasicExpandContract() { // Move down to 4 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo6"); - + assertEquals(Dictionary4.class, dict.getClass()); assertEquals(4, dict.getPropertyKeys().length); assertEquals("baz1", dict.getProperty("foo1")); assertEquals("baz2", dict.getProperty("foo2")); assertEquals("bar4", dict.getProperty("foo4")); assertEquals("bar5", dict.getProperty("foo5")); - + // Move down to 3 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo1"); - + assertEquals(Dictionary3.class, dict.getClass()); assertEquals(3, dict.getPropertyKeys().length); assertEquals("baz2", dict.getProperty("foo2")); assertEquals("bar4", dict.getProperty("foo4")); assertEquals("bar5", dict.getProperty("foo5")); - + // Move down to 2 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo4"); - + assertEquals(Dictionary2.class, dict.getClass()); assertEquals(2, dict.getPropertyKeys().length); assertEquals("baz2", dict.getProperty("foo2")); assertEquals("bar5", dict.getProperty("foo5")); - + // Move down to 1 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo5"); - + assertEquals(Dictionary1.class, dict.getClass()); assertEquals(1, dict.getPropertyKeys().length); assertEquals("baz2", dict.getProperty("foo2")); @@ -157,24 +156,24 @@ public void testBasicExpandContract() { // Move down to 0 dict = dict.removeProperty("invalidKey"); // invalid key dict = dict.removeProperty("foo2"); - + assertNull(dict); } - + public void testRandomExpandContract() { randomTestIter(5000, 171); randomTestIter(100000, 17); } - + public void randomTestIter(int numIters, int numKeys) { Map reference = new HashMap(); - + Dictionary dict = null; - for (int i=0; i < numIters; i++) { + for (int i = 0; i < numIters; i++) { String key = "key " + (i % numKeys); Object value = getRandomObject(); - + if (rand.nextBoolean() || rand.nextBoolean()) { // Prob 0.75 to set if (dict == null) { @@ -189,43 +188,43 @@ public void randomTestIter(int numIters, int numKeys) { if (dict != null) { dict = dict.removeProperty(key); } - + reference.remove(key); } - + if ((rand.nextInt() % 2 == 0) && dict != null) { dict = dict.copyOf(); } - + compareAgainstMap(dict, reference); } } - + public void compareAgainstMap(Dictionary dict, Map reference) { String[] keys = (dict == null) ? new String[0] : dict.getPropertyKeys(); assertEquals(reference.size(), keys.length); - for (int i=0; i < keys.length; i++) { + for (int i = 0; i < keys.length; i++) { assertEquals(reference.get(keys[i]), dict.getProperty(keys[i])); } - + if (rand.nextInt() % 2 == 0) { dict = DictionaryFactory.fromMap(reference); } } - + public Object getRandomObject() { long time = System.currentTimeMillis(); - + if (rand.nextBoolean()) { if (rand.nextBoolean()) { - return new Long(time); + return time; } else { return "" + time; } } else { if (rand.nextBoolean()) { - return new StringBuffer("" + time); + return new StringBuilder("" + time); } else { return null; } diff --git a/src/test/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMaxTest.java b/src/test/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMaxTest.java index 11c0d55..15e08db 100644 --- a/src/test/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMaxTest.java +++ b/src/test/java/com/lambdazen/bitsy/ads/set/CompactMultiSetMaxTest.java @@ -1,17 +1,14 @@ package com.lambdazen.bitsy.ads.set; import java.util.Arrays; - import junit.framework.TestCase; public class CompactMultiSetMaxTest extends TestCase { - public CompactMultiSetMaxTest() { - - } - + public CompactMultiSetMaxTest() {} + public void testSimpleUse() { CompactMultiSetMax test = new CompactMultiSetMax(4, false); - + ClassifierGetter c = new ClassifierGetter() { @Override public String getClassifier(String obj) { @@ -21,10 +18,10 @@ public String getClassifier(String obj) { test = test.add("fooBar", c); // classifier is foo test = test.add("fooBaz", c); // classifier is foo - + test = test.add("barBar", c); // classifier is bar test = test.add("barBaz", c); // classifier is bar - + Object[] fooStuff = test.getSuperSetWithClassifier("foo"); Arrays.sort(fooStuff); assertEquals(2, fooStuff.length); @@ -36,33 +33,33 @@ public String getClassifier(String obj) { assertEquals(2, barStuff.length); assertEquals("barBar", barStuff[0]); assertEquals("barBaz", barStuff[1]); - + test = test.remove("fooBar", c); test = test.remove("fooBaz", c); test = test.remove("barBaz", c); - + fooStuff = test.getSuperSetWithClassifier("foo"); assertEquals(0, fooStuff.length); barStuff = test.getSuperSetWithClassifier("bar"); assertEquals(1, barStuff.length); assertEquals("barBar", barStuff[0]); - + test = test.remove("barBar", c); for (Object elem : test.elements) { assertNull(elem); } - + assertEquals(0, test.getOccupiedCells()); } - + public void testResize() { CompactMultiSetMax test; - + // Repeat the test 100 times final int numEntries = 10000; - for (int numRun=0; numRun < 10; numRun++) { + for (int numRun = 0; numRun < 10; numRun++) { for (int factor : new int[] {10, 100, 1000}) { final int factorFinal = factor; ClassifierGetter c = new ClassifierGetter() { @@ -74,60 +71,63 @@ public Integer getClassifier(Integer obj) { test = new CompactMultiSetMax(4, false); - for (int i=0; i < numEntries; i++) { + for (int i = 0; i < numEntries; i++) { test = test.add(i, c); - + assertTrue(test.getOccupiedCells() > 0); } - - for (int key=0; key < numEntries / factor; key++) { + + for (int key = 0; key < numEntries / factor; key++) { Object[] matches = test.getSuperSetWithClassifier(key); - + int count = 0; for (Object match : matches) { - if (((Integer)match) % (numEntries / factor) == key) { + if (((Integer) match) % (numEntries / factor) == key) { count++; } } - + assertEquals(factor, count); } - - for (int i=0; i < numEntries/2; i++) { + + for (int i = 0; i < numEntries / 2; i++) { test = test.remove(i, c); - + // Also remove some random things that can't be there if (i % 13 == 0) { - //test = test.remove(-i, c); + // test = test.remove(-i, c); } } - - for (int key=0; key < numEntries / factor; key++) { + + for (int key = 0; key < numEntries / factor; key++) { Object[] matches = test.getSuperSetWithClassifier(key); - + int count = 0; for (Object match : matches) { - if (((Integer)match) % (numEntries / factor) == key) { + if (((Integer) match) % (numEntries / factor) == key) { count++; } } - + assertEquals(factor / 2, count); } - - for (int i=numEntries/2; i < numEntries; i++) { + + for (int i = numEntries / 2; i < numEntries; i++) { test = test.remove(i, c); } assertEquals(0, test.getOccupiedCells()); for (Object elem : test.elements) { - assertNull("For factor " + factor + " and numEntries " + numEntries + " with elements " + Arrays.asList(CompactSet.getElements(elem)) + " as " + elem, elem); + assertNull( + "For factor " + factor + " and numEntries " + numEntries + " with elements " + + Arrays.asList(CompactSet.getElements(elem)) + " as " + elem, + elem); } - for (int key=0; key < numEntries; key++) { + for (int key = 0; key < numEntries; key++) { Object[] matches = test.getSuperSetWithClassifier(key); - + assertEquals(0, matches.length); } } diff --git a/src/test/java/com/lambdazen/bitsy/ads/set/SetTest.java b/src/test/java/com/lambdazen/bitsy/ads/set/SetTest.java index 5bfcf56..8106071 100644 --- a/src/test/java/com/lambdazen/bitsy/ads/set/SetTest.java +++ b/src/test/java/com/lambdazen/bitsy/ads/set/SetTest.java @@ -5,35 +5,33 @@ import java.util.HashSet; import java.util.List; import java.util.Random; - import junit.framework.TestCase; public class SetTest extends TestCase { private Random rand = new Random(); - + public void testBasicExpandContract() { Object set = null; // empty set - + // Test remove on null set = CompactSet.remove(set, "foo"); - + // Add foo - set = CompactSet.add(set, "foo"); + set = CompactSet.add(set, "foo"); assertEquals(1, CompactSet.size(set)); Object[] elements = CompactSet.getElements(set); assertEquals("foo", elements[0]); - + // Add foo again set = CompactSet.add(set, "foo"); assertEquals(1, CompactSet.size(set)); elements = CompactSet.getElements(set); assertEquals("foo", elements[0]); - + set = CompactSet.add(set, "bar"); assertEquals(2, CompactSet.size(set)); assertEquals("foo", CompactSet.getElements(set)[0]); assertEquals("bar", CompactSet.getElements(set)[1]); - // Move down to 0 set = CompactSet.remove(set, "foo"); // invalid key @@ -43,19 +41,19 @@ public void testBasicExpandContract() { set = CompactSet.remove(set, "foo"); // invalid key assertEquals(1, CompactSet.size(set)); assertEquals("bar", CompactSet.getElements(set)[0]); - + set = CompactSet.remove(set, "bar"); assertNull(set); } - + public void testRandomExpandContract() { randomTestIter(5000, 171); randomTestIter(100000, 17); } - + public void testClassTypes() { Object set = null; // empty set - + set = CompactSet.add(set, 1); assertEquals(1, CompactSet.size(set)); assertEquals(Integer.class, set.getClass()); @@ -112,38 +110,38 @@ public void testClassTypes() { assertEquals(12, CompactSet.size(set)); assertEquals(Set12.class, set.getClass()); - for (int i=13; i <= 24; i++) { + for (int i = 13; i <= 24; i++) { set = CompactSet.add(set, i); assertEquals(i, CompactSet.size(set)); assertEquals(Set24.class, set.getClass()); } - + set = CompactSet.add(set, 25); assertEquals(25, CompactSet.size(set)); assertEquals(SetMax.class, set.getClass()); - + // Remove - for (int i=25; i > 9; i--) { + for (int i = 25; i > 9; i--) { set = CompactSet.remove(set, i); - assertEquals(i-1, CompactSet.size(set)); - + assertEquals(i - 1, CompactSet.size(set)); + if (i > 17) { assertEquals(SetMax.class, set.getClass()); } else if (i > 13) { - assertTrue((set instanceof Set24) || (set instanceof SetMax)); // Depends on hashcode + assertTrue((set instanceof Set24) || (set instanceof SetMax)); // Depends on hashcode } else { assertEquals(Set12.class, set.getClass()); } } - + set = CompactSet.remove(set, 9); assertEquals(8, CompactSet.size(set)); assertEquals(Set8.class, set.getClass()); - + set = CompactSet.remove(set, 8); assertEquals(7, CompactSet.size(set)); assertEquals(Set8.class, set.getClass()); - + set = CompactSet.remove(set, 7); assertEquals(6, CompactSet.size(set)); assertEquals(Set6.class, set.getClass()); @@ -171,18 +169,18 @@ public void testClassTypes() { set = CompactSet.remove(set, 1); assertNull(set); } - + public void randomTestIter(int numIters, int numKeys) { - for (boolean safe: new boolean[] {true, false}) { + for (boolean safe : new boolean[] {true, false}) { System.out.println("randomTestIter: " + numIters + ", " + numKeys + ", " + safe); - + java.util.Set reference = new HashSet(); - + Object set = null; - - for (int i=0; i < numIters; i++) { + + for (int i = 0; i < numIters; i++) { String key = "key " + (i % numKeys); - + if (rand.nextBoolean() || rand.nextBoolean()) { // Prob 0.75 to set if (safe) { @@ -190,46 +188,46 @@ public void randomTestIter(int numIters, int numKeys) { } else { set = CompactSet.add(set, key); } - + reference.add(key); } else { // Prob 0.25 to remove set = CompactSet.remove(set, key); - + reference.remove(key); } - + compareAgainstSet(set, reference); } } } - + public void compareAgainstSet(Object set, java.util.Set reference) { Object[] keys = CompactSet.getElements(set); - + List myKeys = Arrays.asList(keys); List refKeys = Arrays.asList(reference.toArray()); - + Collections.sort(myKeys); Collections.sort(refKeys); - + assertEquals(reference.size(), keys.length); assertEquals(reference.size(), CompactSet.size(set)); assertEquals(refKeys, myKeys); } - + public Object getRandomObject() { long time = System.currentTimeMillis(); - + if (rand.nextBoolean()) { if (rand.nextBoolean()) { - return new Long(time); + return time; } else { return "" + time; } } else { if (rand.nextBoolean()) { - return new StringBuffer("" + time); + return new StringBuilder("" + time); } else { return null; } diff --git a/src/test/java/com/lambdazen/bitsy/store/EndpointTest.java b/src/test/java/com/lambdazen/bitsy/store/EndpointTest.java index e8d85d5..cbf84c6 100644 --- a/src/test/java/com/lambdazen/bitsy/store/EndpointTest.java +++ b/src/test/java/com/lambdazen/bitsy/store/EndpointTest.java @@ -4,91 +4,90 @@ import junit.framework.TestCase; public class EndpointTest extends TestCase { - public EndpointTest() { - } - + public EndpointTest() {} + public void testCompare() throws Exception { UUID vid = UUID.randomUUID(); UUID eid = UUID.randomUUID(); Endpoint e1; Endpoint e2; - + e1 = new Endpoint(null, null); e1.setMarker(); e2 = new Endpoint(null, eid); - + assertTrue(e1.isMatch(e2)); assertEquals(-1, e1.compareTo(e2)); assertEquals(1, e2.compareTo(e1)); - + e2 = new Endpoint("something", eid); assertTrue(e1.isMatch(e2)); assertEquals(-1, e1.compareTo(e2)); assertEquals(1, e2.compareTo(e1)); assertFalse(e1.equals(e2)); -// e2 = new Endpoint(eid, null, eid); -// assertFalse(e1.isMatch(e2)); -// assertEquals(vid.compareTo(eid), e1.compareTo(e2)); -// assertEquals(-vid.compareTo(eid), e2.compareTo(e1)); -// assertFalse(e1.equals(e2)); - + // e2 = new Endpoint(eid, null, eid); + // assertFalse(e1.isMatch(e2)); + // assertEquals(vid.compareTo(eid), e1.compareTo(e2)); + // assertEquals(-vid.compareTo(eid), e2.compareTo(e1)); + // assertFalse(e1.equals(e2)); + e1 = new Endpoint("foo", null); e1.setMarker(); - + e2 = new Endpoint("foo", eid); - + assertTrue(e1.isMatch(e2)); assertEquals(-1, e1.compareTo(e2)); assertEquals(1, e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e2 = new Endpoint("bar", eid); assertFalse(e1.isMatch(e2)); assertEquals("foo".compareTo("bar"), e1.compareTo(e2)); assertEquals("bar".compareTo("foo"), e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e1 = new Endpoint("foo", eid); e1.setMarker(); - + e2 = new Endpoint("foo", eid); assertTrue(e1.isMatch(e2)); assertEquals(-1, e1.compareTo(e2)); assertEquals(1, e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e2 = new Endpoint("bar", eid); assertFalse(e1.isMatch(e2)); assertEquals("foo".compareTo("bar"), e1.compareTo(e2)); assertEquals("bar".compareTo("foo"), e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e2 = new Endpoint("foo", vid); assertFalse(e1.isMatch(e2)); assertEquals(eid.compareTo(vid), e1.compareTo(e2)); assertEquals(-eid.compareTo(vid), e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e1 = new Endpoint("foo", eid); - + e2 = new Endpoint("foo", eid); assertEquals(0, e1.compareTo(e2)); assertEquals(e1, e2); - + e2 = new Endpoint("bar", eid); assertEquals("foo".compareTo("bar"), e1.compareTo(e2)); assertEquals("bar".compareTo("foo"), e2.compareTo(e1)); assertFalse(e1.equals(e2)); - + e2 = new Endpoint("foo", vid); assertEquals(eid.compareTo(vid), e1.compareTo(e2)); assertEquals(vid.compareTo(eid), e2.compareTo(e1)); assertFalse(e1.equals(e2)); - -// e2 = new Endpoint(eid, "foo", vid); -// assertEquals(vid.compareTo(eid), e1.compareTo(e2)); -// assertEquals(eid.compareTo(vid), e2.compareTo(e1)); -// assertFalse(e1.equals(e2)); + + // e2 = new Endpoint(eid, "foo", vid); + // assertEquals(vid.compareTo(eid), e1.compareTo(e2)); + // assertEquals(eid.compareTo(vid), e2.compareTo(e1)); + // assertFalse(e1.equals(e2)); } } diff --git a/src/test/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStoreTest.java b/src/test/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStoreTest.java index 2ca9617..3cf141f 100644 --- a/src/test/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStoreTest.java +++ b/src/test/java/com/lambdazen/bitsy/store/FileBackedMemoryGraphStoreTest.java @@ -1,5 +1,12 @@ package com.lambdazen.bitsy.store; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyState; +import com.lambdazen.bitsy.BitsyVertex; +import com.lambdazen.bitsy.FileBasedTestCase; +import com.lambdazen.bitsy.ICommitChanges; +import com.lambdazen.bitsy.UUID; +import com.lambdazen.bitsy.ads.dict.DictionaryFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -7,26 +14,17 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; - import org.apache.tinkerpop.gremlin.structure.Direction; -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyState; -import com.lambdazen.bitsy.BitsyVertex; -import com.lambdazen.bitsy.FileBasedTestCase; -import com.lambdazen.bitsy.ICommitChanges; -import com.lambdazen.bitsy.UUID; -import com.lambdazen.bitsy.ads.dict.DictionaryFactory; - public class FileBackedMemoryGraphStoreTest extends FileBasedTestCase { FileBackedMemoryGraphStore store; - - public FileBackedMemoryGraphStoreTest() { - } - + + public FileBackedMemoryGraphStoreTest() {} + protected void setUp() throws Exception { System.out.println("Making DB"); - this.store = new FileBackedMemoryGraphStore(new MemoryGraphStore(true), tempDir("test-fbmgst"), 2*1024, 1); // 2K buffer to test rollover + this.store = new FileBackedMemoryGraphStore( + new MemoryGraphStore(true), tempDir("test-fbmgst"), 2 * 1024, 1); // 2K buffer to test rollover System.out.println("Made DB"); } @@ -34,78 +32,80 @@ protected void tearDown() throws Exception { store.shutdown(); System.out.println("Close"); } - -// public void testOpenClose() { -// System.out.println("Opened DB"); -// } - + + // public void testOpenClose() { + // System.out.println("Opened DB"); + // } + public void testSomething() { Map foo = new TreeMap(); foo.put(1, 2); foo.put(2, 3); - - assert(foo.values().size() == 2); - assert(foo.values().size() == 2); + + assert (foo.values().size() == 2); + assert (foo.values().size() == 2); } - + public void testVertexInserts() { int numCommits = 10; int numPerCommit = 10; - + List uuids = new ArrayList(); long ts = System.currentTimeMillis(); - for (int i=0; i < numCommits * numPerCommit; i += numPerCommit) { - if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i+numPerCommit)); - + for (int i = 0; i < numCommits * numPerCommit; i += numPerCommit) { + if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i + numPerCommit)); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit); store.commit(changes); - + uuids.addAll(changes.getVertexIDs()); } - System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to commit " + (numPerCommit * numCommits) + " vertices"); - + System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to commit " + (numPerCommit * numCommits) + + " vertices"); + ts = System.currentTimeMillis(); // Check to see if the stuff made it in int counter = 0; for (UUID uuid : uuids) { - //System.out.println("Found " + uuid); + // System.out.println("Found " + uuid); VertexBean bean = store.getVertex(uuid); assertNotNull(bean); assertEquals(1, bean.getVersion()); assertEquals(counter++, bean.getProperties().get("Vertex")); } - System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to query " + uuids.size() + " vertices"); + System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to query " + uuids.size() + " vertices"); } - + public void testBipartiteGraph() { for (boolean reverse : new boolean[] {false, true}) { for (boolean useEdgeLabels : new boolean[] {true, false}) { - System.out.println("Entering iteration with reverse " + reverse + ", and useEdgeLabels " + useEdgeLabels); - + System.out.println( + "Entering iteration with reverse " + reverse + ", and useEdgeLabels " + useEdgeLabels); + int numCommits = 10; int numPerCommit = 10; int partSize = numCommits * numPerCommit; UUID[] outVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); - UUID[] inVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); + UUID[] inVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); EdgeCommitChanges ecc = new EdgeCommitChanges(); // Now add edges from one to the other long ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - UUID[] ins = new UUID[] { - inVertices[(5 * i + 1) % partSize], - inVertices[(5 * i + 4) % partSize], - inVertices[(5 * i + 7) % partSize] + for (int i = 0; i < outVertices.length; i++) { + UUID[] ins = new UUID[] { + inVertices[(5 * i + 1) % partSize], + inVertices[(5 * i + 4) % partSize], + inVertices[(5 * i + 7) % partSize] }; - for (int j=0; j < ins.length; j++) { + for (int j = 0; j < ins.length; j++) { String label = ""; // null labels are not supported after 2.3.0 - + if (useEdgeLabels) { label = "Label " + j; } - + if (!reverse) { ecc.addEdge(outVertices[i], label, ins[j]); } else { @@ -119,10 +119,11 @@ public void testBipartiteGraph() { store.commit(ecc); ecc = new EdgeCommitChanges(); - //double duration = (System.currentTimeMillis() - ts); - //System.out.println("Took " + duration + " ms to save " + size + " edges. Rate = " + (duration / size) + " ms per edge"); + // double duration = (System.currentTimeMillis() - ts); + // System.out.println("Took " + duration + " ms to save " + size + " edges. Rate = " + (duration + // / size) + " ms per edge"); - //ts = System.currentTimeMillis(); + // ts = System.currentTimeMillis(); } } // Commit before the next stage @@ -130,41 +131,44 @@ public void testBipartiteGraph() { // Now check to see if the edges go to the right places ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - UUID[] ins = new UUID[] { - inVertices[(5 * i + 1) % partSize], - inVertices[(5 * i + 4) % partSize], - inVertices[(5 * i + 7) % partSize] + for (int i = 0; i < outVertices.length; i++) { + UUID[] ins = new UUID[] { + inVertices[(5 * i + 1) % partSize], + inVertices[(5 * i + 4) % partSize], + inVertices[(5 * i + 7) % partSize] }; List edgeList; if (useEdgeLabels && Math.random() < 0.2) { - //System.out.println("Explicit label query"); - edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] {"Label 0", "Label 1", "Label 2"}); + // System.out.println("Explicit label query"); + edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] { + "Label 0", "Label 1", "Label 2" + }); } else { - //System.out.println("Null label query"); + // System.out.println("Null label query"); edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); } - + if (edgeList.size() < 3) { // Something is wrong System.out.println("Edges retrieved " + edgeList); System.out.println("Vertices expected: "); - for (int k=0; k < 3; k++) { + for (int k = 0; k < 3; k++) { System.out.print(ins[k] + " "); } fail("WRONG edgeList size"); } - - for (int j=0; j < 3; j++) { + + for (int j = 0; j < 3; j++) { EdgeBean edge = edgeList.get(j); assertEquals(outVertices[i], reverse ? edge.getInVertexId() : edge.getOutVertexId()); - // Either foo is missing, or it is bar -- poor man's validation - assertTrue(edge.getProperties() == null || edge.getProperties().get("foo").equals("bar")); + // Either foo is missing, or it is bar -- poor man's validation + assertTrue(edge.getProperties() == null + || edge.getProperties().get("foo").equals("bar")); boolean match = false; - for (int k=0; k < 3; k++) { - UUID otherVertexId = reverse ? edge.getOutVertexId() : edge.getInVertexId(); + for (int k = 0; k < 3; k++) { + UUID otherVertexId = reverse ? edge.getOutVertexId() : edge.getInVertexId(); if (otherVertexId.equals(ins[k])) { // Match match = true; @@ -172,12 +176,17 @@ public void testBipartiteGraph() { if (useEdgeLabels) { String label = "Label " + k; assertEquals(label, edge.getLabel()); - + // Additional check to make sure that the edge can be retrieved by label if (Math.random() < 0.2) { - List edgeByLabelList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] {label}); + List edgeByLabelList = store.getEdges( + outVertices[i], + reverse ? Direction.IN : Direction.OUT, + new String[] {label}); assertEquals(1, edgeByLabelList.size()); - assertEquals(edge.getId(), edgeByLabelList.get(0).getId()); + assertEquals( + edge.getId(), + edgeByLabelList.get(0).getId()); } } else { assertEquals("", edge.getLabel()); @@ -190,65 +199,68 @@ public void testBipartiteGraph() { } double duration = (System.currentTimeMillis() - ts); - System.out.println("Took " + duration + " ms to save " + (numCommits * numPerCommit * 3) + " edges. Rate = " + (duration / (numCommits * numPerCommit * 3)) + " ms per edge"); - + System.out.println("Took " + duration + " ms to save " + (numCommits * numPerCommit * 3) + + " edges. Rate = " + (duration / (numCommits * numPerCommit * 3)) + " ms per edge"); + // Now, remove all the vertices to make sure that the edges are also gone ts = System.currentTimeMillis(); deleteVertices(inVertices, numPerCommit); duration = (System.currentTimeMillis() - ts); - System.out.println("Took " + duration + " ms to delete " + inVertices.length + " vertices with 3 incident edges. Rate = " + (duration / inVertices.length) + " ms per vertex"); + System.out.println("Took " + duration + " ms to delete " + inVertices.length + + " vertices with 3 incident edges. Rate = " + (duration / inVertices.length) + + " ms per vertex"); // Check if there are no edges into inVertices ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - List edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); + for (int i = 0; i < outVertices.length; i++) { + List edgeList = + store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); assertEquals(0, edgeList.size()); } } } } - + private List createVertices(int numPerCommit, int partSize) { List ans = new ArrayList(); - - for (int i=0; i < partSize; i += numPerCommit) { - if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i+numPerCommit)); - + + for (int i = 0; i < partSize; i += numPerCommit) { + if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i + numPerCommit)); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit); store.commit(changes); ans.addAll(changes.getVertexIDs()); } - + return ans; } private void deleteVertices(UUID[] toDelete, int numPerCommit) { int partSize = toDelete.length; - for (int i=0; i < partSize; i += numPerCommit) { - //System.out.println("Deleting vertex from #" + i); - + for (int i = 0; i < partSize; i += numPerCommit) { + // System.out.println("Deleting vertex from #" + i); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit, toDelete, 1); store.commit(changes); } } - public class VertexCommitChanges implements ICommitChanges { List vertices; - + int start, num; List uuids; UUID[] toDelete; int version; - + public VertexCommitChanges(int start, int num) { this(start, num, null); } - + public VertexCommitChanges(int start, int num, UUID[] toDelete) { this(start, num, toDelete, 0); } - + public VertexCommitChanges(int start, int num, UUID[] toDelete, int version) { this.start = start; this.num = num; @@ -256,17 +268,17 @@ public VertexCommitChanges(int start, int num, UUID[] toDelete, int version) { this.uuids = new ArrayList(); this.version = version; } - + public List getVertexIDs() { return uuids; } - + @Override public Collection getVertexChanges() { if (vertices == null) { vertices = new ArrayList(); - for (int i=start; i < start+num; i++) { + for (int i = start; i < start + num; i++) { Map propMap = new TreeMap(); propMap.put("Vertex", i); @@ -286,7 +298,7 @@ public Collection getVertexChanges() { uuids.add(uuid); if (i % 97 == 0) { - // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. + // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. vertices.add(new BitsyVertex(uuid, null, null, null, BitsyState.U, 23)); } } @@ -300,20 +312,20 @@ public Collection getEdgeChanges() { return Collections.emptyList(); } } - + public class EdgeCommitChanges implements ICommitChanges { List outUUIDs; List inUUIDs; List edgeLabels; List edgeUUIDs; List edges; - + public EdgeCommitChanges() { this.outUUIDs = new ArrayList(); this.inUUIDs = new ArrayList(); this.edgeLabels = new ArrayList(); } - + public int size() { return outUUIDs.size(); } @@ -352,15 +364,23 @@ public Collection getEdgeChanges() { UUID edgeUUID = UUID.randomUUID(); edgeUUIDs.add(edgeUUID); - BitsyEdge edge = new BitsyEdge(edgeUUID, DictionaryFactory.fromMap(edgeProps), null, BitsyState.M, Integer.MIN_VALUE, label, outV, inV); + BitsyEdge edge = new BitsyEdge( + edgeUUID, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.M, + Integer.MIN_VALUE, + label, + outV, + inV); edges.add(edge); - if (Math.random() < 0.01) { // Place some random unmodified nodes with the same UUID. // These should be ignored in the commit. Keeping - // probability at 5% to not affect ms/edge too much - edges.add(new BitsyEdge(edgeUUID, null, null, BitsyState.U, Integer.MIN_VALUE, label, outV, inV)); + // probability at 5% to not affect ms/edge too much + edges.add( + new BitsyEdge(edgeUUID, null, null, BitsyState.U, Integer.MIN_VALUE, label, outV, inV)); } // Once in a while, create an edge called "Invalid" and remove @@ -370,15 +390,30 @@ public Collection getEdgeChanges() { // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. UUID deleteEdgeId = UUID.randomUUID(); - edges.add(new BitsyEdge(deleteEdgeId, DictionaryFactory.fromMap(edgeProps), null, BitsyState.M, 1, "To be removed", outV, inV)); + edges.add(new BitsyEdge( + deleteEdgeId, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.M, + 1, + "To be removed", + outV, + inV)); // Now remove it - edges.add(new BitsyEdge(deleteEdgeId, DictionaryFactory.fromMap(edgeProps), null, BitsyState.D, 2, "To be removed", outV, inV)); + edges.add(new BitsyEdge( + deleteEdgeId, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.D, + 2, + "To be removed", + outV, + inV)); } } - } - + return edges; } } diff --git a/src/test/java/com/lambdazen/bitsy/store/MemoryGraphStoreTest.java b/src/test/java/com/lambdazen/bitsy/store/MemoryGraphStoreTest.java index dbd217d..6a1fd58 100644 --- a/src/test/java/com/lambdazen/bitsy/store/MemoryGraphStoreTest.java +++ b/src/test/java/com/lambdazen/bitsy/store/MemoryGraphStoreTest.java @@ -1,5 +1,11 @@ package com.lambdazen.bitsy.store; +import com.lambdazen.bitsy.BitsyEdge; +import com.lambdazen.bitsy.BitsyState; +import com.lambdazen.bitsy.BitsyVertex; +import com.lambdazen.bitsy.ICommitChanges; +import com.lambdazen.bitsy.UUID; +import com.lambdazen.bitsy.ads.dict.DictionaryFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -7,105 +13,97 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; - -import org.apache.tinkerpop.gremlin.structure.Direction; - -import com.lambdazen.bitsy.BitsyEdge; -import com.lambdazen.bitsy.BitsyState; -import com.lambdazen.bitsy.BitsyVertex; -import com.lambdazen.bitsy.ICommitChanges; -import com.lambdazen.bitsy.UUID; -import com.lambdazen.bitsy.ads.dict.DictionaryFactory; - import junit.framework.TestCase; +import org.apache.tinkerpop.gremlin.structure.Direction; public class MemoryGraphStoreTest extends TestCase { MemoryGraphStore store; - - public MemoryGraphStoreTest() { - } - + + public MemoryGraphStoreTest() {} + protected void setUp() { System.out.println("Making DB"); this.store = new MemoryGraphStore(true); System.out.println("Made DB"); } - + protected void tearDown() { System.out.println("Close"); } - -// public void testOpenClose() { -// System.out.println("Opened DB"); -// } - + + // public void testOpenClose() { + // System.out.println("Opened DB"); + // } + public void testSomething() { Map foo = new TreeMap(); foo.put(1, 2); foo.put(2, 3); - - assert(foo.values().size() == 2); - assert(foo.values().size() == 2); + + assert (foo.values().size() == 2); + assert (foo.values().size() == 2); } - + public void testVertexInserts() { int numCommits = 100; int numPerCommit = 100; - + List uuids = new ArrayList(); long ts = System.currentTimeMillis(); - for (int i=0; i < numCommits * numPerCommit; i += numPerCommit) { - if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i+numPerCommit)); - + for (int i = 0; i < numCommits * numPerCommit; i += numPerCommit) { + if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i + numPerCommit)); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit); store.commit(changes); - + uuids.addAll(changes.getVertexIDs()); } - System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to commit " + (numPerCommit * numCommits) + " vertices"); - + System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to commit " + (numPerCommit * numCommits) + + " vertices"); + ts = System.currentTimeMillis(); // Check to see if the stuff made it in int counter = 0; for (UUID uuid : uuids) { - //System.out.println("Found " + uuid); + // System.out.println("Found " + uuid); VertexBean bean = store.getVertex(uuid); assertNotNull(bean); assertEquals(1, bean.getVersion()); assertEquals(counter++, bean.getProperties().get("Vertex")); } - System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to query " + uuids.size() + " vertices"); + System.out.println("Took " + (System.currentTimeMillis() - ts) + " ms to query " + uuids.size() + " vertices"); } - + public void testBipartiteGraph() { for (boolean reverse : new boolean[] {false, true}) { for (boolean useEdgeLabels : new boolean[] {true, false}) { - System.out.println("Entering iteration with reverse " + reverse + ", and useEdgeLabels " + useEdgeLabels); - + System.out.println( + "Entering iteration with reverse " + reverse + ", and useEdgeLabels " + useEdgeLabels); + int numCommits = 100; int numPerCommit = 10; int partSize = numCommits * numPerCommit; UUID[] outVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); - UUID[] inVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); + UUID[] inVertices = createVertices(numPerCommit, partSize).toArray(new UUID[0]); EdgeCommitChanges ecc = new EdgeCommitChanges(); // Now add edges from one to the other long ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - UUID[] ins = new UUID[] { - inVertices[(5 * i + 1) % partSize], - inVertices[(5 * i + 4) % partSize], - inVertices[(5 * i + 7) % partSize] + for (int i = 0; i < outVertices.length; i++) { + UUID[] ins = new UUID[] { + inVertices[(5 * i + 1) % partSize], + inVertices[(5 * i + 4) % partSize], + inVertices[(5 * i + 7) % partSize] }; - for (int j=0; j < ins.length; j++) { + for (int j = 0; j < ins.length; j++) { String label = ""; - + if (useEdgeLabels) { label = "Label " + j; } - + if (!reverse) { ecc.addEdge(outVertices[i], label, ins[j]); } else { @@ -119,10 +117,11 @@ public void testBipartiteGraph() { store.commit(ecc); ecc = new EdgeCommitChanges(); - //double duration = (System.currentTimeMillis() - ts); - //System.out.println("Took " + duration + " ms to save " + size + " edges. Rate = " + (duration / size) + " ms per edge"); + // double duration = (System.currentTimeMillis() - ts); + // System.out.println("Took " + duration + " ms to save " + size + " edges. Rate = " + (duration + // / size) + " ms per edge"); - //ts = System.currentTimeMillis(); + // ts = System.currentTimeMillis(); } } // Commit before the next stage @@ -130,41 +129,44 @@ public void testBipartiteGraph() { // Now check to see if the edges go to the right places ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - UUID[] ins = new UUID[] { - inVertices[(5 * i + 1) % partSize], - inVertices[(5 * i + 4) % partSize], - inVertices[(5 * i + 7) % partSize] + for (int i = 0; i < outVertices.length; i++) { + UUID[] ins = new UUID[] { + inVertices[(5 * i + 1) % partSize], + inVertices[(5 * i + 4) % partSize], + inVertices[(5 * i + 7) % partSize] }; List edgeList; if (useEdgeLabels && Math.random() < 0.2) { - //System.out.println("Explicit label query"); - edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] {"Label 0", "Label 1", "Label 2"}); + // System.out.println("Explicit label query"); + edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] { + "Label 0", "Label 1", "Label 2" + }); } else { - //System.out.println("Null label query"); + // System.out.println("Null label query"); edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); } - + if (edgeList.size() < 3) { // Something is wrong System.out.println("Edges retrieved " + edgeList); System.out.println("Vertices expected: "); - for (int k=0; k < 3; k++) { + for (int k = 0; k < 3; k++) { System.out.print(ins[k] + " "); } fail("WRONG edgeList size"); } - - for (int j=0; j < 3; j++) { + + for (int j = 0; j < 3; j++) { EdgeBean edge = edgeList.get(j); assertEquals(outVertices[i], reverse ? edge.getInVertexId() : edge.getOutVertexId()); - // Either foo is missing, or it is bar -- poor man's validation - assertTrue(edge.getProperties() == null || "bar".equals(edge.getProperties().get("foo"))); + // Either foo is missing, or it is bar -- poor man's validation + assertTrue(edge.getProperties() == null + || "bar".equals(edge.getProperties().get("foo"))); boolean match = false; - for (int k=0; k < 3; k++) { - UUID otherVertexId = reverse ? edge.getOutVertexId() : edge.getInVertexId(); + for (int k = 0; k < 3; k++) { + UUID otherVertexId = reverse ? edge.getOutVertexId() : edge.getInVertexId(); if (otherVertexId.equals(ins[k])) { // Match match = true; @@ -172,12 +174,17 @@ public void testBipartiteGraph() { if (useEdgeLabels) { String label = "Label " + k; assertEquals(label, edge.getLabel()); - + // Additional check to make sure that the edge can be retrieved by label if (Math.random() < 0.2) { - List edgeByLabelList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, new String[] {label}); + List edgeByLabelList = store.getEdges( + outVertices[i], + reverse ? Direction.IN : Direction.OUT, + new String[] {label}); assertEquals(1, edgeByLabelList.size()); - assertEquals(edge.getId(), edgeByLabelList.get(0).getId()); + assertEquals( + edge.getId(), + edgeByLabelList.get(0).getId()); } } else { assertEquals("", edge.getLabel()); @@ -190,70 +197,73 @@ public void testBipartiteGraph() { } double duration = (System.currentTimeMillis() - ts); - System.out.println("Took " + duration + " ms to save " + (numCommits * numPerCommit * 3) + " edges. Rate = " + (duration / (numCommits * numPerCommit * 3)) + " ms per edge"); - + System.out.println("Took " + duration + " ms to save " + (numCommits * numPerCommit * 3) + + " edges. Rate = " + (duration / (numCommits * numPerCommit * 3)) + " ms per edge"); + // Now, remove all the vertices to make sure that the edges are also gone ts = System.currentTimeMillis(); deleteVertices(inVertices, numPerCommit); duration = (System.currentTimeMillis() - ts); - System.out.println("Took " + duration + " ms to delete " + inVertices.length + " vertices with 3 incident edges. Rate = " + (duration / inVertices.length) + " ms per vertex"); + System.out.println("Took " + duration + " ms to delete " + inVertices.length + + " vertices with 3 incident edges. Rate = " + (duration / inVertices.length) + + " ms per vertex"); for (VertexBean vBean : store.getAllVertices()) { assertNull(vBean.outEdges); assertNull(vBean.inEdges); } - + // Check if there are no edges into inVertices ts = System.currentTimeMillis(); - for (int i=0; i < outVertices.length; i++) { - List edgeList = store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); + for (int i = 0; i < outVertices.length; i++) { + List edgeList = + store.getEdges(outVertices[i], reverse ? Direction.IN : Direction.OUT, null); assertEquals(0, edgeList.size()); } } } } - + private List createVertices(int numPerCommit, int partSize) { List ans = new ArrayList(); - - for (int i=0; i < partSize; i += numPerCommit) { - if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i+numPerCommit)); - + + for (int i = 0; i < partSize; i += numPerCommit) { + if (i % 1000 == 0) System.out.println("Inserting vertex " + i + " to " + (i + numPerCommit)); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit); store.commit(changes); ans.addAll(changes.getVertexIDs()); } - + return ans; } private void deleteVertices(UUID[] toDelete, int numPerCommit) { int partSize = toDelete.length; - for (int i=0; i < partSize; i += numPerCommit) { - //System.out.println("Deleting vertex from #" + i); - + for (int i = 0; i < partSize; i += numPerCommit) { + // System.out.println("Deleting vertex from #" + i); + VertexCommitChanges changes = new VertexCommitChanges(i, numPerCommit, toDelete, 1); store.commit(changes); } } - public class VertexCommitChanges implements ICommitChanges { List vertices; - + int start, num; List uuids; UUID[] toDelete; int version; - + public VertexCommitChanges(int start, int num) { this(start, num, null); } - + public VertexCommitChanges(int start, int num, UUID[] toDelete) { this(start, num, toDelete, 0); } - + public VertexCommitChanges(int start, int num, UUID[] toDelete, int version) { this.start = start; this.num = num; @@ -261,17 +271,17 @@ public VertexCommitChanges(int start, int num, UUID[] toDelete, int version) { this.uuids = new ArrayList(); this.version = version; } - + public List getVertexIDs() { return uuids; } - + @Override public Collection getVertexChanges() { if (vertices == null) { vertices = new ArrayList(); - for (int i=start; i < start+num; i++) { + for (int i = start; i < start + num; i++) { Map propMap = new TreeMap(); propMap.put("Vertex", i); @@ -286,13 +296,13 @@ public Collection getVertexChanges() { } // Insert or delete a vertex - //vertices.add(new BitsyVertex(uuid, DictionaryFactory.fromMap(propMap), null, state, version)); + // vertices.add(new BitsyVertex(uuid, DictionaryFactory.fromMap(propMap), null, state, version)); vertices.add(new BitsyVertex(uuid, null, DictionaryFactory.fromMap(propMap), null, state, version)); uuids.add(uuid); if (i % 97 == 0) { - // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. + // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. vertices.add(new BitsyVertex(uuid, null, null, null, BitsyState.U, 23)); } } @@ -306,20 +316,20 @@ public Collection getEdgeChanges() { return Collections.emptyList(); } } - + public class EdgeCommitChanges implements ICommitChanges { List outUUIDs; List inUUIDs; List edgeLabels; List edgeUUIDs; List edges; - + public EdgeCommitChanges() { this.outUUIDs = new ArrayList(); this.inUUIDs = new ArrayList(); this.edgeLabels = new ArrayList(); } - + public int size() { return outUUIDs.size(); } @@ -358,15 +368,23 @@ public Collection getEdgeChanges() { UUID edgeUUID = UUID.randomUUID(); edgeUUIDs.add(edgeUUID); - BitsyEdge edge = new BitsyEdge(edgeUUID, DictionaryFactory.fromMap(edgeProps), null, BitsyState.M, Integer.MIN_VALUE, label, outV, inV); + BitsyEdge edge = new BitsyEdge( + edgeUUID, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.M, + Integer.MIN_VALUE, + label, + outV, + inV); edges.add(edge); - if (Math.random() < 0.01) { // Place some random unmodified nodes with the same UUID. // These should be ignored in the commit. Keeping - // probability at 5% to not affect ms/edge too much - edges.add(new BitsyEdge(edgeUUID, null, null, BitsyState.U, Integer.MIN_VALUE, label, outV, inV)); + // probability at 5% to not affect ms/edge too much + edges.add( + new BitsyEdge(edgeUUID, null, null, BitsyState.U, Integer.MIN_VALUE, label, outV, inV)); } // Once in a while, create an edge called "Invalid" and remove @@ -376,15 +394,30 @@ public Collection getEdgeChanges() { // Place some random unmodified nodes with the same UUID. These should be ignored in the commit. UUID deleteEdgeId = UUID.randomUUID(); - edges.add(new BitsyEdge(deleteEdgeId, DictionaryFactory.fromMap(edgeProps), null, BitsyState.M, 1, "To be removed", outV, inV)); + edges.add(new BitsyEdge( + deleteEdgeId, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.M, + 1, + "To be removed", + outV, + inV)); // Now remove it - edges.add(new BitsyEdge(deleteEdgeId, DictionaryFactory.fromMap(edgeProps), null, BitsyState.D, 2, "To be removed", outV, inV)); + edges.add(new BitsyEdge( + deleteEdgeId, + DictionaryFactory.fromMap(edgeProps), + null, + BitsyState.D, + 2, + "To be removed", + outV, + inV)); } } - } - + return edges; } } diff --git a/src/test/java/com/lambdazen/bitsy/store/RecordTest.java b/src/test/java/com/lambdazen/bitsy/store/RecordTest.java index 4067ffa..591354d 100644 --- a/src/test/java/com/lambdazen/bitsy/store/RecordTest.java +++ b/src/test/java/com/lambdazen/bitsy/store/RecordTest.java @@ -7,20 +7,18 @@ import com.lambdazen.bitsy.UUID; import com.lambdazen.bitsy.ads.dict.DictionaryFactory; import com.lambdazen.bitsy.store.Record.RecordType; -import junit.framework.TestCase; - import java.util.ArrayList; import java.util.List; import java.util.TreeMap; +import junit.framework.TestCase; public class RecordTest extends TestCase { - public RecordTest() { - } - + public RecordTest() {} + public void testRecord() throws Exception { ObjectMapper mapper = new ObjectMapper(); TreeMap props = new TreeMap(); - + UUID edgeId = UUID.fromString("9d09e705-fac4-409b-a0bb-74883fa21313"); UUID outVId = UUID.fromString("25f1b840-c521-4398-ac84-9d1a0e305f4c"); UUID inVId = UUID.fromString("2c390534-5f50-4924-8792-a06293db4241"); @@ -32,41 +30,46 @@ public void testRecord() throws Exception { bar.add("colon:{}+!#&*(!@#="); props.put("foo", bar); String str = Record.generateDBLine(RecordType.V, mapper.writeValueAsString(vBean)); - assertEquals("V={\"id\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"v\":1,\"s\":\"D\",\"p\":null,\"l\":null}#42fe79ab\n", - str); + assertEquals( + "V={\"id\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"v\":1,\"s\":\"D\",\"p\":null,\"l\":null}#42fe79ab\n", + str); VertexBean vBean2 = new VertexBeanJson(inVId, "foo", null, 1, BitsyState.D); props.put("test \"with\" quotes", null); props.put("foo", bar); str = Record.generateDBLine(RecordType.V, mapper.writeValueAsString(vBean2)); - assertEquals("V={\"id\":\"2c390534-5f50-4924-8792-a06293db4241\",\"v\":1,\"s\":\"D\",\"p\":null,\"l\":\"foo\"}#3656bf28\n", - str); - - EdgeBean edgeBean = new EdgeBean(edgeId, DictionaryFactory.fromMap(props), Integer.MIN_VALUE, null, vBean, vBean2); - - EdgeBean edgeBeanJson = new EdgeBeanJson("" + edgeId, props, Integer.MIN_VALUE, null, vBean.getIdStr(), vBean2.getIdStr(), BitsyState.M); + assertEquals( + "V={\"id\":\"2c390534-5f50-4924-8792-a06293db4241\",\"v\":1,\"s\":\"D\",\"p\":null,\"l\":\"foo\"}#3656bf28\n", + str); + + EdgeBean edgeBean = + new EdgeBean(edgeId, DictionaryFactory.fromMap(props), Integer.MIN_VALUE, null, vBean, vBean2); + + EdgeBean edgeBeanJson = new EdgeBeanJson( + "" + edgeId, props, Integer.MIN_VALUE, null, vBean.getIdStr(), vBean2.getIdStr(), BitsyState.M); str = Record.generateDBLine(RecordType.E, mapper.writeValueAsString(edgeBeanJson)); - + System.out.println("str: " + str.replaceAll("[\\\\]", "\\\\\\\\").replaceAll("[\"]", "\\\\\"")); - assertEquals("E={\"id\":\"9d09e705-fac4-409b-a0bb-74883fa21313\",\"v\":-2147483648,\"s\":\"M\",\"o\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"l\":null,\"i\":\"2c390534-5f50-4924-8792-a06293db4241\",\"p\":{\"foo\":[\"another''\\\"one\\\"\",\"colon:{}+!#&*(!@#=\"],\"test \\\"with\\\" quotes\":null}}#4cf814b7\n", + assertEquals( + "E={\"id\":\"9d09e705-fac4-409b-a0bb-74883fa21313\",\"v\":-2147483648,\"s\":\"M\",\"o\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"l\":null,\"i\":\"2c390534-5f50-4924-8792-a06293db4241\",\"p\":{\"foo\":[\"another''\\\"one\\\"\",\"colon:{}+!#&*(!@#=\"],\"test \\\"with\\\" quotes\":null}}#4cf814b7\n", str); - //assertEquals("E={\"class\":\"com.lambdazen.bitsy.store.EdgeBean\",\"id\":\"9d09e705-fac4-409b-a0bb-74883fa21313\",\"v\":-2147483648,\"s\":\"M\",\"o\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"l\":null,\"i\":\"2c390534-5f50-4924-8792-a06293db4241\",\"p\":{\"foo\":[\"another''\\\"one\\\"\",\"colon:{}+!#&*(!@#=\"],\"test \\\"with\\\" quotes\":null}}#98e95483", + // assertEquals("E={\"class\":\"com.lambdazen.bitsy.store.EdgeBean\",\"id\":\"9d09e705-fac4-409b-a0bb-74883fa21313\",\"v\":-2147483648,\"s\":\"M\",\"o\":\"25f1b840-c521-4398-ac84-9d1a0e305f4c\",\"l\":null,\"i\":\"2c390534-5f50-4924-8792-a06293db4241\",\"p\":{\"foo\":[\"another''\\\"one\\\"\",\"colon:{}+!#&*(!@#=\"],\"test \\\"with\\\" quotes\":null}}#98e95483", // str); - + str = str.trim(); Record edgeR = Record.parseRecord(str, 12, null); assertEquals(RecordType.E, edgeR.getType()); assertEquals(str.substring(2, str.lastIndexOf("#")), edgeR.getJson()); - + try { // Wrong hashcode - Record.parseRecord(str.substring(0, str.length()-1), 13, null); + Record.parseRecord(str.substring(0, str.length() - 1), 13, null); fail("wrong hashcode"); } catch (BitsyException e) { // all ok } - - EdgeBeanJson edgeBean2 = (EdgeBeanJson)mapper.readValue(edgeR.getJson(), EdgeBeanJson.class); + + EdgeBeanJson edgeBean2 = (EdgeBeanJson) mapper.readValue(edgeR.getJson(), EdgeBeanJson.class); assertEquals(edgeBean.getId(), edgeBean2.getId()); assertEquals(edgeBean.getLabel(), edgeBean2.getLabel()); assertEquals(edgeBean.getVersion(), edgeBean2.getVersion()); @@ -77,13 +80,12 @@ public void testRecord() throws Exception { assertEquals(BitsyState.M, edgeBean2.getState()); } - - public void testDictionaryMaxProperties() throws Exception { ObjectMapper mapper = new ObjectMapper(); ObjectReader reader = mapper.readerFor(VertexBeanJson.class); - String json = "{\"id\":\"40026fee-498a-4cd9-afad-1ae31363c13e\",\"v\":1,\"s\":\"M\",\"p\":{\"a00\":\"00\",\"a01\":\"01\",\"a02\":\"02\",\"a03\":\"03\",\"a04\":\"04\",\"a05\":\"05\",\"a06\":\"06\",\"a07\":\"07\",\"a08\":\"08\",\"a09\":\"09\",\"a10\":\"10\",\"a11\":\"11\",\"a12\":\"12\",\"a13\":\"13\",\"a14\":\"14\",\"a15\":\"15\",\"a16\":\"16\",\"a17\":\"17\",\"a18\":\"18\",\"a19\":\"19\",\"a20\":\"20\",\"a21\":\"21\",\"a22\":\"22\",\"a23\":\"23\",\"a24\":\"24\",\"a25\":\"25\",\"a26\":\"26\",\"a27\":\"27\",\"a28\":\"28\",\"a29\":\"29\",\"a30\":\"30\",\"a31\":\"31\",\"a32\":\"32\",\"a33\":\"33\",\"a34\":\"34\",\"a35\":\"35\",\"a36\":\"36\",\"a37\":\"37\",\"a38\":\"38\",\"a39\":\"39\",\"a40\":\"40\",\"a41\":\"41\",\"a42\":\"42\",\"a43\":\"43\",\"a44\":\"44\",\"a45\":\"45\",\"a46\":\"46\",\"a47\":\"47\",\"a48\":\"48\",\"a49\":\"49\",\"a50\":\"50\"}}"; + String json = + "{\"id\":\"40026fee-498a-4cd9-afad-1ae31363c13e\",\"v\":1,\"s\":\"M\",\"p\":{\"a00\":\"00\",\"a01\":\"01\",\"a02\":\"02\",\"a03\":\"03\",\"a04\":\"04\",\"a05\":\"05\",\"a06\":\"06\",\"a07\":\"07\",\"a08\":\"08\",\"a09\":\"09\",\"a10\":\"10\",\"a11\":\"11\",\"a12\":\"12\",\"a13\":\"13\",\"a14\":\"14\",\"a15\":\"15\",\"a16\":\"16\",\"a17\":\"17\",\"a18\":\"18\",\"a19\":\"19\",\"a20\":\"20\",\"a21\":\"21\",\"a22\":\"22\",\"a23\":\"23\",\"a24\":\"24\",\"a25\":\"25\",\"a26\":\"26\",\"a27\":\"27\",\"a28\":\"28\",\"a29\":\"29\",\"a30\":\"30\",\"a31\":\"31\",\"a32\":\"32\",\"a33\":\"33\",\"a34\":\"34\",\"a35\":\"35\",\"a36\":\"36\",\"a37\":\"37\",\"a38\":\"38\",\"a39\":\"39\",\"a40\":\"40\",\"a41\":\"41\",\"a42\":\"42\",\"a43\":\"43\",\"a44\":\"44\",\"a45\":\"45\",\"a46\":\"46\",\"a47\":\"47\",\"a48\":\"48\",\"a49\":\"49\",\"a50\":\"50\"}}"; VertexBeanJson vBean = reader.readValue(json); diff --git a/src/test/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizerTest.java b/src/test/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizerTest.java index 472bf0b..5a103c2 100644 --- a/src/test/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizerTest.java +++ b/src/test/java/com/lambdazen/bitsy/store/SingleThreadedStringCanonicalizerTest.java @@ -5,16 +5,16 @@ public class SingleThreadedStringCanonicalizerTest extends TestCase { public void testCanonicalize() { IStringCanonicalizer canon = new SingleThreadedStringCanonicalizer(); - + String abc1 = "a".concat("bc"); String abc2 = "abc"; - + assertEquals(abc1, abc2); assertNotSame(abc1, abc2); - + String c1 = canon.canonicalize(abc1); String c2 = canon.canonicalize(abc2); - + assertSame(c1, c2); assertSame(c1, canon.canonicalize("ab".concat("c"))); } diff --git a/src/test/java/com/lambdazen/bitsy/structure/BitsyGraphStructureTestSuite.java b/src/test/java/com/lambdazen/bitsy/structure/BitsyGraphStructureTestSuite.java index 6b453cf..d8ad04d 100644 --- a/src/test/java/com/lambdazen/bitsy/structure/BitsyGraphStructureTestSuite.java +++ b/src/test/java/com/lambdazen/bitsy/structure/BitsyGraphStructureTestSuite.java @@ -18,48 +18,19 @@ */ package com.lambdazen.bitsy.structure; +import com.lambdazen.bitsy.BitsyGraph; import org.apache.tinkerpop.gremlin.AbstractGremlinSuite; import org.apache.tinkerpop.gremlin.GraphProviderClass; -import org.apache.tinkerpop.gremlin.algorithm.generator.CommunityGeneratorTest; -import org.apache.tinkerpop.gremlin.algorithm.generator.DistributionGeneratorTest; import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine; import org.apache.tinkerpop.gremlin.structure.EdgeTest; -import org.apache.tinkerpop.gremlin.structure.FeatureSupportTest; -import org.apache.tinkerpop.gremlin.structure.GraphConstructionTest; -import org.apache.tinkerpop.gremlin.structure.GraphTest; -import org.apache.tinkerpop.gremlin.structure.PropertyTest; -import org.apache.tinkerpop.gremlin.structure.SerializationTest; -import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite; -import org.apache.tinkerpop.gremlin.structure.TransactionTest; -import org.apache.tinkerpop.gremlin.structure.VariablesTest; -import org.apache.tinkerpop.gremlin.structure.VertexPropertyTest; import org.apache.tinkerpop.gremlin.structure.VertexTest; -import org.apache.tinkerpop.gremlin.structure.io.IoCustomTest; -import org.apache.tinkerpop.gremlin.structure.io.IoEdgeTest; -import org.apache.tinkerpop.gremlin.structure.io.IoGraphTest; -import org.apache.tinkerpop.gremlin.structure.io.IoPropertyTest; -import org.apache.tinkerpop.gremlin.structure.io.IoTest; -import org.apache.tinkerpop.gremlin.structure.io.IoVertexTest; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdgeTest; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedGraphTest; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedPropertyTest; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexPropertyTest; -import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexTest; -import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceEdgeTest; -import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceGraphTest; -import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexPropertyTest; -import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexTest; -import org.apache.tinkerpop.gremlin.structure.util.star.StarGraphTest; import org.junit.runner.RunWith; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerBuilder; -import com.lambdazen.bitsy.BitsyGraph; - /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ - @RunWith(BitsyGraphStructureTestSuite.class) @GraphProviderClass(provider = BitsyTestGraphProvider.class, graph = BitsyGraph.class) public class BitsyGraphStructureTestSuite extends AbstractGremlinSuite { @@ -67,43 +38,42 @@ public class BitsyGraphStructureTestSuite extends AbstractGremlinSuite { * This list of tests in the suite that will be executed. Gremlin developers should add to this list * as needed to enforce tests upon implementations. */ - private static final Class[] allTests = new Class[]{ - VertexTest.class, - EdgeTest.class, -// VertexPropertyTest.class, -// GraphTest.class, -// FeatureSupportTest.class, -// PropertyTest.class, -// VariablesTest.class, + private static final Class[] allTests = new Class[] { + VertexTest.class, EdgeTest.class, + // VertexPropertyTest.class, + // GraphTest.class, + // FeatureSupportTest.class, + // PropertyTest.class, + // VariablesTest.class, -// DetachedGraphTest.class, -// DetachedVertexPropertyTest.class, -// DetachedPropertyTest.class -// DetachedVertexTest.class, -// DetachedEdgeTest.class, + // DetachedGraphTest.class, + // DetachedVertexPropertyTest.class, + // DetachedPropertyTest.class + // DetachedVertexTest.class, + // DetachedEdgeTest.class, -// ReferenceGraphTest.class, -// ReferenceEdgeTest.class, -// ReferenceVertexPropertyTest.class, -// ReferenceVertexTest.class, + // ReferenceGraphTest.class, + // ReferenceEdgeTest.class, + // ReferenceVertexPropertyTest.class, + // ReferenceVertexTest.class, -// CommunityGeneratorTest.class, -// DistributionGeneratorTest.class, -// GraphConstructionTest.class, + // CommunityGeneratorTest.class, + // DistributionGeneratorTest.class, + // GraphConstructionTest.class, -// TransactionTest.class, + // TransactionTest.class, - /* SERIALIZATION TESTS WON'T WORK -- + /* SERIALIZATION TESTS WON'T WORK -- IoPropertyTest.class, IoTest.class, IoVertexTest.class, IoCustomTest.class, IoEdgeTest.class, IoGraphTest.class, - SerializationTest.class, + SerializationTest.class, StarGraphTest.class // has failure related to UUID and kryo */ - + }; public BitsyGraphStructureTestSuite(final Class klass, final RunnerBuilder builder) throws InitializationError { diff --git a/src/test/java/com/lambdazen/bitsy/structure/BitsyProcessStandardTestSuite.java b/src/test/java/com/lambdazen/bitsy/structure/BitsyProcessStandardTestSuite.java index a1afa4e..f615ef0 100644 --- a/src/test/java/com/lambdazen/bitsy/structure/BitsyProcessStandardTestSuite.java +++ b/src/test/java/com/lambdazen/bitsy/structure/BitsyProcessStandardTestSuite.java @@ -67,158 +67,157 @@ public class BitsyProcessStandardTestSuite extends AbstractGremlinSuite { /** * This list of tests in the suite that will be executed as part of this suite. */ - private static final Class[] allTests = new Class[]{ + private static final Class[] allTests = new Class[] { - // branch -// BranchTest.Traversals.class, -// ChooseTest.Traversals.class, -// OptionalTest.Traversals.class, -// LocalTest.Traversals.class, -// RepeatTest.Traversals.class, -// UnionTest.Traversals.class, + // branch + // BranchTest.Traversals.class, + // ChooseTest.Traversals.class, + // OptionalTest.Traversals.class, + // LocalTest.Traversals.class, + // RepeatTest.Traversals.class, + // UnionTest.Traversals.class, - // filter -// AndTest.Traversals.class, -// CoinTest.Traversals.class, -// CyclicPathTest.Traversals.class, -// DedupTest.Traversals.class, -// DropTest.Traversals.class, -// FilterTest.Traversals.class, - HasTest.Traversals.class, - IsTest.Traversals.class, -// OrTest.Traversals.class, -// RangeTest.Traversals.class, -// SampleTest.Traversals.class, -// SimplePathTest.Traversals.class, -// TailTest.Traversals.class, -// WhereTest.Traversals.class, + // filter + // AndTest.Traversals.class, + // CoinTest.Traversals.class, + // CyclicPathTest.Traversals.class, + // DedupTest.Traversals.class, + // DropTest.Traversals.class, + // FilterTest.Traversals.class, + HasTest.Traversals.class, IsTest.Traversals.class, + // OrTest.Traversals.class, + // RangeTest.Traversals.class, + // SampleTest.Traversals.class, + // SimplePathTest.Traversals.class, + // TailTest.Traversals.class, + // WhereTest.Traversals.class, - // map -// AddEdgeTest.Traversals.class, -// AddVertexTest.Traversals.class, -// CoalesceTest.Traversals.class, -// ConstantTest.Traversals.class, -// CountTest.Traversals.class, -// FlatMapTest.Traversals.class, -// FoldTest.Traversals.class, -// GraphTest.Traversals.class, -// LoopsTest.Traversals.class, -// MapTest.Traversals.class, -// MapKeysTest.Traversals.class, -// MapValuesTest.Traversals.class, -// MatchTest.CountMatchTraversals.class, -// MatchTest.GreedyMatchTraversals.class, -// MaxTest.Traversals.class, -// MeanTest.Traversals.class, -// MinTest.Traversals.class, -// SumTest.Traversals.class, -// OrderTest.Traversals.class, -// PathTest.Traversals.class, -// ProfileTest.Traversals.class, // NOT SURE WHY THIS IS FAILING?! -// ProjectTest.Traversals.class, + // map + // AddEdgeTest.Traversals.class, + // AddVertexTest.Traversals.class, + // CoalesceTest.Traversals.class, + // ConstantTest.Traversals.class, + // CountTest.Traversals.class, + // FlatMapTest.Traversals.class, + // FoldTest.Traversals.class, + // GraphTest.Traversals.class, + // LoopsTest.Traversals.class, + // MapTest.Traversals.class, + // MapKeysTest.Traversals.class, + // MapValuesTest.Traversals.class, + // MatchTest.CountMatchTraversals.class, + // MatchTest.GreedyMatchTraversals.class, + // MaxTest.Traversals.class, + // MeanTest.Traversals.class, + // MinTest.Traversals.class, + // SumTest.Traversals.class, + // OrderTest.Traversals.class, + // PathTest.Traversals.class, + // ProfileTest.Traversals.class, // NOT SURE WHY THIS IS FAILING?! + // ProjectTest.Traversals.class, -// PropertiesTest.Traversals.class, -// SelectTest.Traversals.class, -// VertexTest.Traversals.class, -// UnfoldTest.Traversals.class, -// ValueMapTest.Traversals.class, + // PropertiesTest.Traversals.class, + // SelectTest.Traversals.class, + // VertexTest.Traversals.class, + // UnfoldTest.Traversals.class, + // ValueMapTest.Traversals.class, - // sideEffect -// AggregateTest.Traversals.class, -// ExplainTest.Traversals.class, -// GroupTest.Traversals.class, -// GroupTestV3d0.Traversals.class, -// GroupCountTest.Traversals.class, -// InjectTest.Traversals.class, -// SackTest.Traversals.class, -// SideEffectCapTest.Traversals.class, -// SideEffectTest.Traversals.class, -// StoreTest.Traversals.class, -// SubgraphTest.Traversals.class, -// TreeTest.Traversals.class, + // sideEffect + // AggregateTest.Traversals.class, + // ExplainTest.Traversals.class, + // GroupTest.Traversals.class, + // GroupTestV3d0.Traversals.class, + // GroupCountTest.Traversals.class, + // InjectTest.Traversals.class, + // SackTest.Traversals.class, + // SideEffectCapTest.Traversals.class, + // SideEffectTest.Traversals.class, + // StoreTest.Traversals.class, + // SubgraphTest.Traversals.class, + // TreeTest.Traversals.class, - // compliance -// ComplexTest.Traversals.class, -// CoreTraversalTest.class, -// TraversalInterruptionTest.class, + // compliance + // ComplexTest.Traversals.class, + // CoreTraversalTest.class, + // TraversalInterruptionTest.class, - // creations -// TranslationStrategyProcessTest.class, + // creations + // TranslationStrategyProcessTest.class, - // decorations -// ElementIdStrategyProcessTest.class, -// EventStrategyProcessTest.class, -// ReadOnlyStrategyProcessTest.class, -// PartitionStrategyProcessTest.class, -// SubgraphStrategyProcessTest.class + // decorations + // ElementIdStrategyProcessTest.class, + // EventStrategyProcessTest.class, + // ReadOnlyStrategyProcessTest.class, + // PartitionStrategyProcessTest.class, + // SubgraphStrategyProcessTest.class }; - + /** * A list of the minimum set of base tests that Gremlin flavors should implement to be compliant with Gremlin. */ - private static final Class[] testsToEnforce = new Class[]{ - // branch - BranchTest.class, - ChooseTest.class, - OptionalTest.class, - LocalTest.class, - RepeatTest.class, - UnionTest.class, + private static final Class[] testsToEnforce = new Class[] { + // branch + BranchTest.class, + ChooseTest.class, + OptionalTest.class, + LocalTest.class, + RepeatTest.class, + UnionTest.class, - // filter - AndTest.class, - CoinTest.class, - CyclicPathTest.class, - DedupTest.class, - DropTest.class, - FilterTest.class, - HasTest.class, - IsTest.class, - OrTest.class, - RangeTest.class, - SampleTest.class, - SimplePathTest.class, - TailTest.class, - WhereTest.class, + // filter + AndTest.class, + CoinTest.class, + CyclicPathTest.class, + DedupTest.class, + DropTest.class, + FilterTest.class, + HasTest.class, + IsTest.class, + OrTest.class, + RangeTest.class, + SampleTest.class, + SimplePathTest.class, + TailTest.class, + WhereTest.class, - // map - AddEdgeTest.class, - AddVertexTest.class, - CoalesceTest.class, - ConstantTest.class, - CountTest.class, - FlatMapTest.class, - FoldTest.class, - LoopsTest.class, - MapTest.class, - //MapKeysTest.class, - //MapValuesTest.class, - MatchTest.class, - MaxTest.class, - MeanTest.class, - MinTest.class, - SumTest.class, - OrderTest.class, - PathTest.class, - PropertiesTest.class, - ProfileTest.class, - ProjectTest.class, - SelectTest.class, - VertexTest.class, - UnfoldTest.class, - ValueMapTest.class, + // map + AddEdgeTest.class, + AddVertexTest.class, + CoalesceTest.class, + ConstantTest.class, + CountTest.class, + FlatMapTest.class, + FoldTest.class, + LoopsTest.class, + MapTest.class, + // MapKeysTest.class, + // MapValuesTest.class, + MatchTest.class, + MaxTest.class, + MeanTest.class, + MinTest.class, + SumTest.class, + OrderTest.class, + PathTest.class, + PropertiesTest.class, + ProfileTest.class, + ProjectTest.class, + SelectTest.class, + VertexTest.class, + UnfoldTest.class, + ValueMapTest.class, - // sideEffect - AggregateTest.class, - GroupTest.class, - GroupCountTest.class, - InjectTest.class, - SackTest.class, - SideEffectCapTest.class, - SideEffectTest.class, - StoreTest.class, - SubgraphTest.class, - TreeTest.class, + // sideEffect + AggregateTest.class, + GroupTest.class, + GroupCountTest.class, + InjectTest.class, + SackTest.class, + SideEffectCapTest.class, + SideEffectTest.class, + StoreTest.class, + SubgraphTest.class, + TreeTest.class, }; /** diff --git a/src/test/java/com/lambdazen/bitsy/structure/BitsyTestGraphProvider.java b/src/test/java/com/lambdazen/bitsy/structure/BitsyTestGraphProvider.java index 6812995..aeceaa5 100644 --- a/src/test/java/com/lambdazen/bitsy/structure/BitsyTestGraphProvider.java +++ b/src/test/java/com/lambdazen/bitsy/structure/BitsyTestGraphProvider.java @@ -1,25 +1,26 @@ package com.lambdazen.bitsy.structure; +import com.lambdazen.bitsy.BitsyGraph; +import com.lambdazen.bitsy.BitsyIsolationLevel; +import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; import java.io.File; +import java.nio.file.Paths; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.apache.commons.configuration2.Configuration; import org.apache.tinkerpop.gremlin.AbstractGraphProvider; import org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR; -import com.lambdazen.bitsy.BitsyGraph; -import com.lambdazen.bitsy.BitsyIsolationLevel; -import com.lambdazen.bitsy.wrapper.BitsyAutoReloadingGraph; - public class BitsyTestGraphProvider extends AbstractGraphProvider { - private static final Set IMPLEMENTATION = new HashSet() {{ + private static final Set IMPLEMENTATION = new HashSet() { + { add(BitsyAutoReloadingGraph.class); - }}; + } + }; @Override public void clear(Graph graph, Configuration configuration) throws Exception { @@ -48,27 +49,27 @@ protected static void deleteDirectory(final File directory, boolean deleteDir) { if (directory.exists()) { for (File file : directory.listFiles()) { if (file.isDirectory()) { - //System.out.println("Deleting dir: " + file.toString()); + // System.out.println("Deleting dir: " + file.toString()); deleteDirectory(file, true); } else { - //System.out.println("Deleting file: " + file.toString()); + // System.out.println("Deleting file: " + file.toString()); file.delete(); } } if (deleteDir) { - //System.out.println("Deleting dir: " + directory); + // System.out.println("Deleting dir: " + directory); directory.delete(); } } - //System.out.println("Exiting delete dir"); + // System.out.println("Exiting delete dir"); } @Override - public Map getBaseConfiguration(String graphName, Class test, String testMethodName, - GraphData loadGraphWith) { + public Map getBaseConfiguration( + String graphName, Class test, String testMethodName, GraphData loadGraphWith) { final String directory = makeTestDirectory(graphName, test, testMethodName); - File testDataRootFile = new File(directory); + File testDataRootFile = Paths.get(directory).toFile(); testDataRootFile.mkdirs(); try { @@ -82,12 +83,14 @@ public Map getBaseConfiguration(String graphName, Class test, String testDataRoot = testDataRootFile.getPath(); - return new HashMap() {{ - put(Graph.GRAPH, BitsyAutoReloadingGraph.class.getName()); - put(BitsyGraph.DB_PATH_KEY, testDataRoot); - put(BitsyGraph.CREATE_DIR_IF_MISSING_KEY, true); - put(BitsyGraph.DEFAULT_ISOLATION_LEVEL_KEY, BitsyIsolationLevel.READ_COMMITTED.toString()); - put(BitsyGraph.VERTEX_INDICES_KEY, "name, foo"); - }}; + return new HashMap() { + { + put(Graph.GRAPH, BitsyAutoReloadingGraph.class.getName()); + put(BitsyGraph.DB_PATH_KEY, testDataRoot); + put(BitsyGraph.CREATE_DIR_IF_MISSING_KEY, true); + put(BitsyGraph.DEFAULT_ISOLATION_LEVEL_KEY, BitsyIsolationLevel.READ_COMMITTED.toString()); + put(BitsyGraph.VERTEX_INDICES_KEY, "name, foo"); + } + }; } } diff --git a/src/test/java/com/lambdazen/bitsy/structure/HasLabelTest.java b/src/test/java/com/lambdazen/bitsy/structure/HasLabelTest.java index 54fce06..be5f821 100644 --- a/src/test/java/com/lambdazen/bitsy/structure/HasLabelTest.java +++ b/src/test/java/com/lambdazen/bitsy/structure/HasLabelTest.java @@ -1,14 +1,14 @@ package com.lambdazen.bitsy.structure; +import static org.junit.Assert.assertTrue; + import com.lambdazen.bitsy.BitsyGraph; +import java.util.ArrayList; +import java.util.List; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.T; import org.junit.Test; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; public class HasLabelTest { @Test diff --git a/src/test/java/com/lambdazen/bitsy/util/CommittableFileLogTest.java b/src/test/java/com/lambdazen/bitsy/util/CommittableFileLogTest.java index ba33870..91a81b0 100644 --- a/src/test/java/com/lambdazen/bitsy/util/CommittableFileLogTest.java +++ b/src/test/java/com/lambdazen/bitsy/util/CommittableFileLogTest.java @@ -1,36 +1,32 @@ package com.lambdazen.bitsy.util; +import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.Random; - -import com.lambdazen.bitsy.store.FileBackedMemoryGraphStore; - import junit.framework.TestCase; public class CommittableFileLogTest extends TestCase { - public CommittableFileLogTest() { - - } - + public CommittableFileLogTest() {} + public void testRead() throws Exception { - File tempFile = File.createTempFile("mobydick", ".txt"); - + File tempFile = File.createTempFile("mobydick", ".txt"); + InputStream is = getClass().getResourceAsStream("mobydick.txt"); assertNotNull(is); BufferedReader br = new BufferedReader(new InputStreamReader(is, FileBackedMemoryGraphStore.utf8)); - + CommittableFileLog cflWrite = new CommittableFileLog(tempFile.toPath(), false); cflWrite.openForOverwrite(1L); - + Random rand = new Random(); int expectedLines = -1; - for (int run=0; run < 10; run++) { + for (int run = 0; run < 10; run++) { List lines = new ArrayList(); String line = null; while ((line = br.readLine()) != null) { @@ -42,15 +38,15 @@ public void testRead() throws Exception { br.close(); is.close(); - + if (run == 0) { cflWrite.close(); } - + if (expectedLines != -1) { assertEquals(expectedLines, lines.size()); } - + System.out.println("Finished writing to " + tempFile); List nioLines = new ArrayList(); @@ -61,7 +57,7 @@ public void testRead() throws Exception { int byteCounter = 13; // Start with header int linesDeleted = 0; while ((line = cfl.readLine()) != null) { - //System.out.println("Line: " + line); + // System.out.println("Line: " + line); nioLines.add(line); int lineBytes = 1 + line.getBytes(FileBackedMemoryGraphStore.utf8).length; byteCounter += lineBytes; @@ -69,10 +65,10 @@ public void testRead() throws Exception { if (rand.nextDouble() < 0.1) { cfl.mark(); assertEquals(byteCounter, cfl.getMarkPosition()); - linesDeleted = 0; + linesDeleted = 0; } else if (rand.nextDouble() < 0.15) { cfl.mark(lineBytes); - //System.out.println("Line bytes: " + lineBytes); + // System.out.println("Line bytes: " + lineBytes); assertEquals(byteCounter - lineBytes, cfl.getMarkPosition()); linesDeleted = 1; } else { @@ -82,18 +78,18 @@ public void testRead() throws Exception { assertEquals(lines.size(), nioLines.size()); expectedLines = lines.size() - linesDeleted; - - for (int i=0; i < lines.size(); i++) { + + for (int i = 0; i < lines.size(); i++) { assertEquals(lines.get(i), nioLines.get(i)); } - + cfl.truncateAtMark(); cfl.close(); - + // For the next run -- use the temp file for reading - is = new FileInputStream(tempFile); + is = Files.newInputStream(tempFile.toPath()); br = new BufferedReader(new InputStreamReader(is, FileBackedMemoryGraphStore.utf8)); - + // Skip the first line with the header br.readLine(); } diff --git a/src/test/java/com/lambdazen/bitsy/util/DoubleBufferIT.java b/src/test/java/com/lambdazen/bitsy/util/DoubleBufferIT.java index 4934c1d..db4cbb5 100644 --- a/src/test/java/com/lambdazen/bitsy/util/DoubleBufferIT.java +++ b/src/test/java/com/lambdazen/bitsy/util/DoubleBufferIT.java @@ -1,20 +1,18 @@ package com.lambdazen.bitsy.util; -import java.util.List; -import junit.framework.TestCase; import com.lambdazen.bitsy.BitsyErrorCodes; import com.lambdazen.bitsy.BitsyException; import com.lambdazen.bitsy.util.DoubleBuffer.BufferName; +import java.util.List; +import junit.framework.TestCase; public class DoubleBufferIT extends TestCase { // Temp vars used in inner classes int count; int potFn; - - public DoubleBufferIT() { - - } - + + public DoubleBufferIT() {} + public void testFixedCtBuf() throws Exception { Thread.sleep(1000); int initThreadCount = Thread.activeCount(); @@ -28,51 +26,54 @@ public void testFixedCtBuf() throws Exception { potFn = 0; count = 0; - DoubleBuffer buf = new DoubleBuffer(new BufferPotential() { - @Override - public boolean addWork(Integer newWork) { - potFn += newWork.intValue(); - return (potFn >= finalThreshold); - } - - @Override - public void reset() { - potFn = 0; - } - - }, new BufferFlusher() { - BufferName oldBufName = BufferName.B; - - @Override - public void flushBuffer(BufferName bufName, List workList) throws BitsyException, InterruptedException { - if (bufName == oldBufName) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Buffer doesn't swap"); - } - - for (Integer work : workList) { - assertEquals(1, work.intValue()); - } + DoubleBuffer buf = new DoubleBuffer<>( + new BufferPotential() { + @Override + public boolean addWork(Integer newWork) { + potFn += newWork; + return (potFn >= finalThreshold); + } - oldBufName = bufName; - count++; - - if (slow) { - try { - Thread.sleep(flushSlowSleep); - } catch (InterruptedException e) { - System.out.println("Interrupted the flusher"); - throw e; + @Override + public void reset() { + potFn = 0; } - } - } - }, "TestThread"); + }, + new BufferFlusher() { + BufferName oldBufName = BufferName.B; + + @Override + public void flushBuffer(BufferName bufName, List workList) + throws BitsyException, InterruptedException { + if (bufName == oldBufName) { + throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Buffer doesn't swap"); + } + + for (Integer work : workList) { + assertEquals(1, work.intValue()); + } + + oldBufName = bufName; + count++; + + if (slow) { + try { + Thread.sleep(flushSlowSleep); + } catch (InterruptedException e) { + System.out.println("Interrupted the flusher"); + throw e; + } + } + } + }, + "TestThread"); - for (int i=0; i < 100; i++) { - buf.addWork(new Integer(1)); + for (int i = 0; i < 100; i++) { + buf.addWork(1); Thread.sleep(50); if (slow && (i % threshold == 0)) { // Sleep a little for the flusher to catch up - Thread.sleep(flushSlowSleep + 100); + Thread.sleep(flushSlowSleep + 100); } } @@ -86,7 +87,7 @@ public void flushBuffer(BufferName bufName, List workList) throws Bitsy } } } - + public void testException() throws Exception { int initThreadCount = Thread.activeCount(); @@ -95,42 +96,44 @@ public void testException() throws Exception { for (boolean syncMode : new boolean[] {false, true}) { System.out.println("Sync mode " + syncMode); - DoubleBuffer buf = new DoubleBuffer(new BufferPotential() { - @Override - public boolean addWork(Integer newWork) { - return true; - } + DoubleBuffer buf = new DoubleBuffer<>( + new BufferPotential() { + @Override + public boolean addWork(Integer newWork) { + return true; + } - @Override - public void reset() { - } + @Override + public void reset() {} + }, + new BufferFlusher() { + BufferName oldBufName = BufferName.B; - }, new BufferFlusher() { - BufferName oldBufName = BufferName.B; + @Override + public void flushBuffer(BufferName bufName, List workList) + throws BitsyException, InterruptedException { + assertNull(workList); - @Override - public void flushBuffer(BufferName bufName, List workList) throws BitsyException, InterruptedException { - assertNull(workList); + if (bufName == oldBufName) { + throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Buffer doesn't swap"); + } - if (bufName == oldBufName) { - throw new BitsyException(BitsyErrorCodes.INTERNAL_ERROR, "Buffer doesn't swap"); - } + Thread.sleep(2000); // wait 2 seconds - Thread.sleep(2000); // wait 2 seconds + if (bufName == BufferName.A) { + throw new BitsyException(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, "test"); + } - if (bufName == BufferName.A) { - throw new BitsyException(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, "test"); - } + oldBufName = bufName; + count++; + } + }, + "TestThread", + false, + true); // sync mode is true - oldBufName = bufName; - count++; - } - }, "TestThread", - false, - true); // sync mode is true + buf.addWork(1); - buf.addWork(new Integer(1)); - if (syncMode) { Thread.sleep(500); // wait 0.5 seconds... because of sync mode addMode will have to wait } else { @@ -140,32 +143,35 @@ public void flushBuffer(BufferName bufName, List workList) throws Bitsy try { // If sync mode weren't set, add work would have gone through long ts = System.currentTimeMillis(); - buf.addWork(new Integer(2)); - + buf.addWork(2); + if (syncMode) { // Sync mode may require another addwork for the exception to register Thread.sleep(100); - buf.addWork(new Integer(3)); + buf.addWork(3); } - - assertEquals(syncMode, System.currentTimeMillis() - ts > 1000); // with sync mode at least 1 second must pass before, addWork gets through. + + assertEquals( + syncMode, + System.currentTimeMillis() - ts + > 1000); // with sync mode at least 1 second must pass before, addWork gets through. fail("Needs to throw an exception"); } catch (BitsyException e) { assertEquals(BitsyErrorCodes.EXCEPTION_IN_FLUSH, e.getErrorCode()); - BitsyException cause = (BitsyException)e.getCause(); + BitsyException cause = (BitsyException) e.getCause(); assertEquals(BitsyErrorCodes.ACCESS_OUTSIDE_TX_SCOPE, cause.getErrorCode()); assertTrue(cause.getMessage().contains("test")); } // Flush thread must have died already Thread.sleep(100); - //assertEquals(initThreadCount, Thread.activeCount()); + // assertEquals(initThreadCount, Thread.activeCount()); buf.stop(1000); Thread.sleep(100); - //assertEquals(initThreadCount, Thread.activeCount()); + // assertEquals(initThreadCount, Thread.activeCount()); } } } From 8078838695884ebc4b29318db17b9481afa629b4 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 2 Jun 2025 14:35:49 +0200 Subject: [PATCH 2/4] Typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd306e1..c8a406f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: name: Verify uses: maveniverse/parent/.github/workflows/ci.yml@release-39 with: - maven-single-run: 'false' + maven-single-run: false jdk-matrix: '[ "8", "11", "17", "21", "24" ]' maven-matrix: '[ "3.9.9", "4.0.0-rc-3" ]' maven-test: './mvnw clean verify -e -B -V -P run-its' \ No newline at end of file From 9bef75c8bd432d0e0009acbba07098ff2c90365a Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 2 Jun 2025 14:37:04 +0200 Subject: [PATCH 3/4] Fix CI --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8a406f..2278815 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,6 @@ jobs: name: Verify uses: maveniverse/parent/.github/workflows/ci.yml@release-39 with: - maven-single-run: false - jdk-matrix: '[ "8", "11", "17", "21", "24" ]' - maven-matrix: '[ "3.9.9", "4.0.0-rc-3" ]' + jdk-matrix: '[ "8", "17", "21", "24" ]' + maven-matrix: '[ "3.9.9" ]' maven-test: './mvnw clean verify -e -B -V -P run-its' \ No newline at end of file From a70dd2e9c8ed08ab8d223e268a91bb9f78e1c109 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 2 Jun 2025 14:46:01 +0200 Subject: [PATCH 4/4] Do not run ITs --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2278815..17b00dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: name: Verify uses: maveniverse/parent/.github/workflows/ci.yml@release-39 with: + maven-test-run: false # ITs are currently busted and needs to go to separate module jdk-matrix: '[ "8", "17", "21", "24" ]' maven-matrix: '[ "3.9.9" ]' maven-test: './mvnw clean verify -e -B -V -P run-its' \ No newline at end of file