├── .classpath
├── .git-blame-ignore-revs
├── .github
├── dependabot.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── LICENSE
├── NOTICE
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── lambdazen
│ │ └── bitsy
│ │ ├── BitsyEdge.java
│ │ ├── BitsyElement.java
│ │ ├── BitsyErrorCodes.java
│ │ ├── BitsyException.java
│ │ ├── BitsyFeatures.java
│ │ ├── BitsyGraph.java
│ │ ├── BitsyGraphMBean.java
│ │ ├── BitsyGraphSONModule.java
│ │ ├── BitsyIoRegistryV3d0.java
│ │ ├── BitsyIsolationLevel.java
│ │ ├── BitsyProperty.java
│ │ ├── BitsyRetryException.java
│ │ ├── BitsyState.java
│ │ ├── BitsyVertex.java
│ │ ├── BitsyVertexProperty.java
│ │ ├── ICommitChanges.java
│ │ ├── IEdge.java
│ │ ├── IGraphStore.java
│ │ ├── ITransaction.java
│ │ ├── PortDatabase.java
│ │ ├── ThreadedBitsyGraph.java
│ │ ├── UUID.java
│ │ ├── UUIDGraphBinarySerializer.java
│ │ ├── ads
│ │ ├── dict
│ │ │ ├── Dictionary.java
│ │ │ ├── Dictionary1.java
│ │ │ ├── Dictionary11.java
│ │ │ ├── Dictionary16.java
│ │ │ ├── Dictionary2.java
│ │ │ ├── Dictionary3.java
│ │ │ ├── Dictionary4.java
│ │ │ ├── Dictionary6.java
│ │ │ ├── Dictionary8.java
│ │ │ ├── DictionaryFactory.java
│ │ │ ├── DictionaryMax.java
│ │ │ └── PrimitiveDictionary.java
│ │ └── set
│ │ │ ├── ArraySet.java
│ │ │ ├── ClassifierGetter.java
│ │ │ ├── CompactMultiSetMax.java
│ │ │ ├── CompactSet.java
│ │ │ ├── PrimitiveSet.java
│ │ │ ├── Set.java
│ │ │ ├── Set12.java
│ │ │ ├── Set2.java
│ │ │ ├── Set24.java
│ │ │ ├── Set3.java
│ │ │ ├── Set4.java
│ │ │ ├── Set6.java
│ │ │ ├── Set8.java
│ │ │ └── SetMax.java
│ │ ├── gremlin
│ │ ├── BitsyGraphStep.java
│ │ └── BitsyTraversalStrategy.java
│ │ ├── index
│ │ ├── BitsyIndex.java
│ │ ├── BitsyIndexMap.java
│ │ ├── EdgeIndex.java
│ │ ├── EdgeIndexMap.java
│ │ ├── IndexHelper.java
│ │ ├── VertexIndex.java
│ │ └── VertexIndexMap.java
│ │ ├── jsr223
│ │ └── BitsyGremlinPlugin.java
│ │ ├── store
│ │ ├── AdjacencyMap.java
│ │ ├── AdjacencyMapForBeans.java
│ │ ├── BackupJob.java
│ │ ├── CompactAndCopyTask.java
│ │ ├── EdgeBean.java
│ │ ├── EdgeBeanJson.java
│ │ ├── Endpoint.java
│ │ ├── FileBackedMemoryGraphStore.java
│ │ ├── IEdgeRemover.java
│ │ ├── IStringCanonicalizer.java
│ │ ├── ITxBatchJob.java
│ │ ├── IVeReorgJob.java
│ │ ├── IndexBean.java
│ │ ├── JobWithCountDownLatch.java
│ │ ├── LoadTask.java
│ │ ├── MemoryGraphStore.java
│ │ ├── ParallelRecordReader.java
│ │ ├── Record.java
│ │ ├── RecordReader.java
│ │ ├── SingleThreadedStringCanonicalizer.java
│ │ ├── TxBatch.java
│ │ ├── TxLog.java
│ │ ├── TxLogFlushPotential.java
│ │ ├── TxUnit.java
│ │ ├── VEObsolescencePotential.java
│ │ ├── VertexBean.java
│ │ └── VertexBeanJson.java
│ │ ├── tx
│ │ ├── BitsyTransaction.java
│ │ └── BitsyTransactionContext.java
│ │ ├── util
│ │ ├── BitsyElementIterator.java
│ │ ├── BufferFlusher.java
│ │ ├── BufferPotential.java
│ │ ├── BufferQueuer.java
│ │ ├── CommittableFileLog.java
│ │ ├── DefaultCommitChanges.java
│ │ ├── DoubleBuffer.java
│ │ ├── DoubleBufferThread.java
│ │ ├── DoubleBufferWithExecWork.java
│ │ ├── EdgeIterator.java
│ │ └── VertexIterator.java
│ │ └── wrapper
│ │ ├── BitsyAutoReloadingEdge.java
│ │ ├── BitsyAutoReloadingGraph.java
│ │ └── BitsyAutoReloadingVertex.java
└── resources
│ └── META-INF
│ └── services
│ └── org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin
└── test
├── java
└── com
│ └── lambdazen
│ └── bitsy
│ ├── BitsyGraphIT.java
│ ├── BitsyMemGraphIT.java
│ ├── FileBasedTestCase.java
│ ├── RecoveryTest.java
│ ├── ads
│ ├── dict
│ │ └── DictionaryTest.java
│ └── set
│ │ ├── CompactMultiSetMaxTest.java
│ │ └── SetTest.java
│ ├── store
│ ├── EndpointTest.java
│ ├── FileBackedMemoryGraphStoreTest.java
│ ├── MemoryGraphStoreTest.java
│ ├── RecordTest.java
│ └── SingleThreadedStringCanonicalizerTest.java
│ ├── structure
│ ├── BitsyGraphStructureTestSuite.java
│ ├── BitsyProcessStandardTestSuite.java
│ ├── BitsyTestGraphProvider.java
│ └── HasLabelTest.java
│ └── util
│ ├── CommittableFileLogTest.java
│ └── DoubleBufferIT.java
└── resources
├── com
└── lambdazen
│ └── bitsy
│ └── util
│ └── mobydick.txt
├── gremlin-server
├── bitsy.properties
└── gremlin-server-bitsy.yaml
└── recovery
├── stage1
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
├── stage2
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
├── stage3
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
├── stage4
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
├── stage5
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
├── stage6
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
└── stage7
├── eA.txt
├── eB.txt
├── metaA.txt
├── metaB.txt
├── txA.txt
├── txB.txt
├── vA.txt
└── vB.txt
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # reformat with Maveniverse parent 39
2 | 641fdf861487e91b277fda8f06cc852842d14f60
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |
4 | - package-ecosystem: "maven"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 |
9 | - package-ecosystem: "github-actions"
10 | directory: "/"
11 | schedule:
12 | interval: "daily"
13 |
14 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 |
9 | jobs:
10 | build:
11 | name: Verify
12 | uses: maveniverse/parent/.github/workflows/ci.yml@release-39
13 | with:
14 | maven-test-run: false # ITs are currently busted and needs to go to separate module
15 | jdk-matrix: '[ "8", "17", "21", "24" ]'
16 | maven-matrix: '[ "3.9.9" ]'
17 | maven-test: './mvnw clean verify -e -B -V -P run-its'
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | *.iml
3 | .idea
4 | *~
5 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=only-script
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
20 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 | bitsy
3 | Bitsy v3 is a small, fast, embeddable, durable in-memory graph database that is compatible with Tinkerpop3. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.
4 |
5 |
6 |
7 | org.eclipse.jdt.core.javabuilder
8 |
9 |
10 |
11 | org.eclipse.jdt.core.javanature
12 |
13 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Thu Nov 02 18:34:43 EDT 2017
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
3 | eclipse.preferences.version=1
4 | org.eclipse.jdt.core.compiler.source=1.8
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | This product depends on the following components:
2 |
3 | - Tinkerpop Gremlin (gremlin-core, gremlin-test)
4 | http://tinkerpop.apache.org/
5 | Apache 2.0 license
6 | Copyright (c) 2015- The Apache Software Foundation.
7 |
8 | - Jackson JSON processor (jackson-core, jackson-databind)
9 | https://github.com/FasterXML/
10 | Apache 2.0 license
11 | Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
12 |
13 | - Ness Computing Core Component (components-ness-core)
14 | https://github.com/NessComputing/components-ness-core
15 | Apache 2.0 license
16 | Copyright (C) 2012- Ness Computing, Inc.
17 |
18 | - SLF4J API (slf4j-api)
19 | http://www.slf4j.org/
20 | MIT license
21 | Copyright (c) 2004- QOS.ch
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://search.maven.org/artifact/com.lambdazen.bitsy/bitsy)
2 |
3 | Bitsy is a small, fast, embeddable, durable in-memory graph database that is compatible with Tinkerpop3.
4 |
5 | [The project Wiki](https://github.com/lambdazen/bitsy/wiki) is the official source of documentation. The original version of the database compatible with Tinkerpop2 is available at https://bitbucket.org/lambdazen/bitsy.
6 |
7 | ### Git branching strategy
8 |
9 | Tags are named release-[version]. Versions start with 3.0. For e.g., release-3.0
10 |
11 | Development happens on `master` branch.
12 |
13 | ## Building it
14 |
15 | The project **build time requirement** is [Apache Maven](https://maven.apache.org/), at least version 3.9 and Java 21.
16 | The project **run time requirement is Java 8**.
17 |
18 | For quick build (runs no tests nor any other plugin like javadoc)
19 |
20 | ```
21 | mvn clean install -Dtest=void
22 | ```
23 |
24 | For UT-only build (will run UTs too)
25 |
26 | ```
27 | mvn clean install
28 | ```
29 |
30 | For full build (will run UTs and ITs)
31 |
32 | ```
33 | mvn clean install -P run-its
34 | ```
35 |
36 | For publishing setup, see [parent POM](https://github.com/maveniverse/parent).
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyEdge.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import com.lambdazen.bitsy.ads.dict.Dictionary;
4 | import com.lambdazen.bitsy.store.EdgeBean;
5 | import com.lambdazen.bitsy.store.EdgeBeanJson;
6 | import com.lambdazen.bitsy.tx.BitsyTransaction;
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.Collections;
10 | import java.util.Iterator;
11 | import org.apache.tinkerpop.gremlin.structure.Direction;
12 | import org.apache.tinkerpop.gremlin.structure.Edge;
13 | import org.apache.tinkerpop.gremlin.structure.Property;
14 | import org.apache.tinkerpop.gremlin.structure.Vertex;
15 | import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
16 |
17 | public class BitsyEdge extends BitsyElement implements Edge, IEdge {
18 | UUID outVertexId;
19 | UUID inVertexId;
20 |
21 | public BitsyEdge(
22 | UUID id,
23 | Dictionary properties,
24 | BitsyTransaction tx,
25 | BitsyState state,
26 | int version,
27 | String label,
28 | UUID outVertexId,
29 | UUID inVertexId) {
30 | super(id, label, properties, tx, state, version);
31 |
32 | if (label == null) {
33 | throw new IllegalArgumentException("Edge label can not be null"); // Enforced by 2.3.0 test case
34 | }
35 |
36 | this.outVertexId = outVertexId;
37 | this.inVertexId = inVertexId;
38 | }
39 |
40 | public BitsyEdge(EdgeBean bean, BitsyTransaction tx, BitsyState state) {
41 | this(
42 | bean.getId(),
43 | bean.getPropertiesDict(),
44 | tx,
45 | state,
46 | bean.getVersion(),
47 | bean.getLabel(),
48 | bean.getOutVertexId(),
49 | bean.getInVertexId());
50 | }
51 |
52 | public EdgeBeanJson asJsonBean() {
53 | // The TX is usually not active at this point. So no checks.
54 | return new EdgeBeanJson((UUID) id, properties, version, label, outVertexId, inVertexId, state);
55 | }
56 |
57 | @Override
58 | public Iterator vertices(Direction dir) {
59 | tx.validateForQuery(this);
60 |
61 | if (dir != Direction.BOTH) {
62 | Vertex ans = inOrOutVertex(dir);
63 |
64 | return Collections.singleton(ans).iterator();
65 | } else {
66 | return bothVertices();
67 | }
68 | }
69 |
70 | @Override
71 | public Vertex inVertex() {
72 | tx.validateForQuery(this);
73 |
74 | return inOrOutVertex(Direction.IN);
75 | }
76 |
77 | @Override
78 | public Vertex outVertex() {
79 | tx.validateForQuery(this);
80 |
81 | return inOrOutVertex(Direction.OUT);
82 | }
83 |
84 | @Override
85 | public Iterator bothVertices() {
86 | tx.validateForQuery(this);
87 |
88 | Vertex inV = inVertex();
89 | Vertex outV = outVertex();
90 | return Arrays.asList(new Vertex[] {outV, inV}).iterator();
91 | }
92 |
93 | private Vertex inOrOutVertex(Direction dir) {
94 | Vertex ans = tx.getVertex(getVertexId(dir));
95 |
96 | // Vertex may disappear in READ_COMMITTED MODE
97 | if (ans == null) {
98 | throw new BitsyRetryException(
99 | BitsyErrorCodes.CONCURRENT_MODIFICATION,
100 | "The vertex in direction " + dir + " of the edge " + this.id()
101 | + " was removed by another transaction");
102 | }
103 |
104 | return ans;
105 | }
106 |
107 | public UUID getInVertexId() {
108 | return inVertexId;
109 | }
110 |
111 | public UUID getOutVertexId() {
112 | return outVertexId;
113 | }
114 |
115 | public UUID getVertexId(Direction dir) {
116 | if (dir == Direction.IN) {
117 | return inVertexId;
118 | } else if (dir == Direction.OUT) {
119 | return outVertexId;
120 | } else {
121 | throw new IllegalArgumentException("Unsupported direction " + dir);
122 | }
123 | }
124 |
125 | public void incrementVersion() {
126 | this.version++;
127 | }
128 |
129 | public void remove() {
130 | tx.removeEdge(this);
131 | }
132 |
133 | public String toString() {
134 | return StringFactory.edgeString(this);
135 | }
136 |
137 | @Override
138 | // THERE ARE TWO MORE COPIES OF THIS CODE IN ELEMENT AND VERTEX
139 | public Iterator> properties(String... propertyKeys) {
140 | ArrayList> ans = new ArrayList>();
141 |
142 | if (propertyKeys.length == 0) {
143 | if (this.properties == null) return Collections.emptyIterator();
144 | propertyKeys = this.properties.getPropertyKeys();
145 | }
146 |
147 | for (String key : propertyKeys) {
148 | Property prop = property(key);
149 | if (prop.isPresent()) ans.add(prop);
150 | }
151 | return ans.iterator();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyException.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public class BitsyException extends RuntimeException {
4 | private static final long serialVersionUID = -5310572247323732287L;
5 | BitsyErrorCodes code;
6 |
7 | public BitsyException(BitsyErrorCodes code) {
8 | super(code.toString());
9 |
10 | this.code = code;
11 | }
12 |
13 | public BitsyException(BitsyErrorCodes code, String s) {
14 | super(code.toString() + ". " + s);
15 |
16 | this.code = code;
17 | }
18 |
19 | public BitsyException(BitsyErrorCodes code, String s, Throwable t) {
20 | super(code.toString() + ". " + s, t);
21 |
22 | this.code = code;
23 | }
24 |
25 | public BitsyErrorCodes getErrorCode() {
26 | return code;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyGraphMBean.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public interface BitsyGraphMBean {
4 | /**
5 | * Returns the reorgFactor which typically determines when the V?.txt and
6 | * E?.txt file will be reorganized. Reorganization is triggered only when the
7 | * total number of new vertices and edges added is more than the factor
8 | * multiplied by the original number of vertices and edges. Default value is 1.
9 | */
10 | public double getReorgFactor();
11 |
12 | /**
13 | * Set the reorgFactor. A higher number indicates fewer file operations, but
14 | * more disk space and startup time in the worst case. Default value is 1.
15 | */
16 | public void setReorgFactor(double factor);
17 |
18 | /**
19 | * Returns the minimum number of vertices and edges that must be added
20 | * before a reorganization is considered. This rule is used in combination
21 | * with the reorgFactor. Default value is 1000.
22 | */
23 | public int getMinLinesPerReorg();
24 |
25 | /**
26 | * Modify the minimum lines to be added before a reorganization is
27 | * considered. Default value is 1000.
28 | */
29 | public void setMinLinesPerReorg(int minLinesPerReorg);
30 |
31 | /**
32 | * Returns the transaction log threshold which is the minimum size of the
33 | * transaction log (T?.txt) in bytes, before which the contents of the log
34 | * are copied to V?.txt and E?.txt. Default value is 4MB.
35 | */
36 | public long getTxLogThreshold();
37 |
38 | /**
39 | * Modify the transaction log threshold. A higher number indicates fewer
40 | * file operations, but more disk space and startup time in the worst case.
41 | * Default value is 4MB.
42 | */
43 | public void setTxLogThreshold(long txLogThreshold);
44 |
45 | /** This method flushes the transaction log to the V/E text files */
46 | public void flushTxLog();
47 |
48 | /** This method backs up the database while it is still operational. Only one backup can be in progress at a time.
49 | *
50 | * @param pathToDir directory to which the database must be backed up.
51 | */
52 | public void backup(String pathToDir);
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyGraphSONModule.java:
--------------------------------------------------------------------------------
1 | // Copyright 2017 JanusGraph Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.lambdazen.bitsy;
16 |
17 | import com.lambdazen.bitsy.store.EdgeBean;
18 | import com.lambdazen.bitsy.store.VertexBean;
19 | import java.io.IOException;
20 | import java.util.Collections;
21 | import java.util.LinkedHashMap;
22 | import java.util.Map;
23 | import org.apache.tinkerpop.gremlin.structure.io.graphson.TinkerPopJacksonModule;
24 | import org.apache.tinkerpop.shaded.jackson.core.*;
25 | import org.apache.tinkerpop.shaded.jackson.core.type.WritableTypeId;
26 | import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext;
27 | import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
28 | import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer;
29 | import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
30 | import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
31 |
32 | /**
33 | * @author Stephen Mallette (http://stephen.genoprime.com)
34 | */
35 | public class BitsyGraphSONModule extends TinkerPopJacksonModule {
36 |
37 | private static final String TYPE_NAMESPACE = "bitsy";
38 |
39 | private static final Map TYPE_DEFINITIONS =
40 | Collections.unmodifiableMap(new LinkedHashMap() {
41 | {
42 | put(UUID.class, "UUID");
43 | put(VertexBean.class, "VertexBean");
44 | put(EdgeBean.class, "EdgeBean");
45 | }
46 | });
47 |
48 | private BitsyGraphSONModule() {
49 | super("bitsy");
50 | addSerializer(UUID.class, new UUIDSerializer());
51 | addDeserializer(UUID.class, new UUIDDeserializer());
52 |
53 | // addSerializer(VertexBean.class, new UUIDSerializer());
54 | // addSerializer(EdgeBean.class, new UUIDSerializer());
55 | }
56 |
57 | private static final BitsyGraphSONModule INSTANCE = new BitsyGraphSONModule();
58 |
59 | public static final BitsyGraphSONModule getInstance() {
60 | return INSTANCE;
61 | }
62 |
63 | @Override
64 | public Map getTypeDefinitions() {
65 | return TYPE_DEFINITIONS;
66 | }
67 |
68 | @Override
69 | public String getTypeNamespace() {
70 | return TYPE_NAMESPACE;
71 | }
72 |
73 | public static class UUIDSerializer extends StdSerializer {
74 |
75 | public UUIDSerializer() {
76 | super(UUID.class);
77 | }
78 |
79 | @Override
80 | public void serialize(
81 | final UUID uuid, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider)
82 | throws IOException, JsonGenerationException {
83 | String uuidStr = UUID.toString(uuid);
84 | jsonGenerator.writeString(uuidStr);
85 | }
86 |
87 | @Override
88 | public void serializeWithType(
89 | final UUID uuid,
90 | final JsonGenerator jsonGenerator,
91 | final SerializerProvider serializerProvider,
92 | final TypeSerializer typeSerializer)
93 | throws IOException, JsonProcessingException {
94 | // since jackson 2.9, must keep track of `typeIdDef` in order to close it properly
95 | final WritableTypeId typeIdDef =
96 | typeSerializer.writeTypePrefix(jsonGenerator, typeSerializer.typeId(uuid, JsonToken.VALUE_STRING));
97 | String uuidStr = UUID.toString(uuid);
98 | jsonGenerator.writeString(uuidStr);
99 | typeSerializer.writeTypeSuffix(jsonGenerator, typeIdDef);
100 | }
101 | }
102 |
103 | public static class UUIDDeserializer extends StdDeserializer {
104 | public UUIDDeserializer() {
105 | super(UUID.class);
106 | }
107 |
108 | @Override
109 | public UUID deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext)
110 | throws IOException, JsonProcessingException {
111 | jsonParser.nextToken();
112 | final String uuidStr = deserializationContext.readValue(jsonParser, String.class);
113 | return UUID.fromString(uuidStr);
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyIoRegistryV3d0.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import com.lambdazen.bitsy.store.EdgeBean;
4 | import com.lambdazen.bitsy.store.VertexBean;
5 | import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
6 | import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryIo;
7 | import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
8 | import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoIo;
9 | import org.apache.tinkerpop.shaded.kryo.Kryo;
10 | import org.apache.tinkerpop.shaded.kryo.Serializer;
11 | import org.apache.tinkerpop.shaded.kryo.io.Input;
12 | import org.apache.tinkerpop.shaded.kryo.io.Output;
13 |
14 | public class BitsyIoRegistryV3d0 extends AbstractIoRegistry {
15 | private static final BitsyIoRegistryV3d0 INSTANCE = new BitsyIoRegistryV3d0();
16 |
17 | private BitsyIoRegistryV3d0() {
18 | register(GryoIo.class, UUID.class, new UUIDGryoSerializer());
19 | register(GryoIo.class, VertexBean.class, new UUIDGryoSerializer());
20 | register(GryoIo.class, EdgeBean.class, new UUIDGryoSerializer());
21 |
22 | register(GraphSONIo.class, UUID.class, BitsyGraphSONModule.getInstance());
23 | register(GraphSONIo.class, VertexBean.class, BitsyGraphSONModule.getInstance());
24 | register(GraphSONIo.class, EdgeBean.class, BitsyGraphSONModule.getInstance());
25 |
26 | register(GraphBinaryIo.class, UUID.class, new UUIDGraphBinarySerializer());
27 | register(GraphBinaryIo.class, VertexBean.class, new UUIDGraphBinarySerializer());
28 | register(GraphBinaryIo.class, EdgeBean.class, new UUIDGraphBinarySerializer());
29 | }
30 |
31 | public static BitsyIoRegistryV3d0 instance() {
32 | return INSTANCE;
33 | }
34 |
35 | static final class UUIDGryoSerializer extends Serializer {
36 | @Override
37 | public void write(final Kryo kryo, final Output output, final UUID uuid) {
38 | output.writeLong(uuid.getMostSignificantBits());
39 | output.writeLong(uuid.getLeastSignificantBits());
40 | }
41 |
42 | @Override
43 | public UUID read(final Kryo kryo, final Input input, final Class aClass) {
44 | long msb = input.readLong();
45 | long lsb = input.readLong();
46 | return new UUID(msb, lsb);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyIsolationLevel.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public enum BitsyIsolationLevel {
4 | READ_COMMITTED, // default
5 | REPEATABLE_READ
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyProperty.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import java.util.NoSuchElementException;
4 | import org.apache.tinkerpop.gremlin.structure.Element;
5 | import org.apache.tinkerpop.gremlin.structure.Property;
6 | import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
7 | import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
8 |
9 | public class BitsyProperty implements Property {
10 | BitsyElement element;
11 | String key;
12 | T value;
13 | boolean removed = false;
14 |
15 | public BitsyProperty(BitsyElement element, String key, T value) {
16 | this.element = element;
17 | this.key = key;
18 | this.value = value;
19 | }
20 |
21 | @Override
22 | public String key() {
23 | return key;
24 | }
25 |
26 | @Override
27 | public T value() throws NoSuchElementException {
28 | if (removed) {
29 | throw new NoSuchElementException("This property is empty");
30 | } else {
31 | return value;
32 | }
33 | }
34 |
35 | @Override
36 | public boolean isPresent() {
37 | return !removed;
38 | }
39 |
40 | @Override
41 | public Element element() {
42 | return element;
43 | }
44 |
45 | @Override
46 | public void remove() {
47 | if (isPresent()) {
48 | element.removeProperty(key);
49 | this.removed = true;
50 | }
51 | }
52 |
53 | // Moved to ElementHelper hashCode and equals in TP3
54 | @Override
55 | public int hashCode() {
56 | return ElementHelper.hashCode(this);
57 | }
58 |
59 | @Override
60 | public boolean equals(final Object object) {
61 | return ElementHelper.areEqual(this, object);
62 | }
63 |
64 | public String toString() {
65 | return StringFactory.propertyString(this);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyRetryException.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public class BitsyRetryException extends BitsyException {
4 | private static final long serialVersionUID = 976641612846833462L;
5 | BitsyErrorCodes code;
6 |
7 | public BitsyRetryException(BitsyErrorCodes code) {
8 | super(code);
9 | }
10 |
11 | public BitsyRetryException(BitsyErrorCodes code, String s) {
12 | super(code, s);
13 | }
14 |
15 | public BitsyRetryException(BitsyErrorCodes code, String s, Throwable t) {
16 | super(code, s, t);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyState.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public enum BitsyState {
4 | U, // unmodified
5 | M, // modified
6 | D // deleted
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/BitsyVertexProperty.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import java.util.Collections;
4 | import java.util.Iterator;
5 | import java.util.Set;
6 | import org.apache.tinkerpop.gremlin.structure.Property;
7 | import org.apache.tinkerpop.gremlin.structure.Vertex;
8 | import org.apache.tinkerpop.gremlin.structure.VertexProperty;
9 | import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
10 |
11 | public class BitsyVertexProperty extends BitsyProperty implements VertexProperty {
12 | public BitsyVertexProperty(final BitsyVertex vertex, final String key, final V value) {
13 | super(vertex, key, value);
14 | }
15 |
16 | @Override
17 | public Set keys() {
18 | return Collections.emptySet();
19 | }
20 |
21 | @Override
22 | public Property property(final String key) {
23 | throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT);
24 | }
25 |
26 | @Override
27 | public Property property(final String key, final U value) {
28 | throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT);
29 | }
30 |
31 | @Override
32 | public Vertex element() {
33 | return (BitsyVertex) super.element();
34 | }
35 |
36 | @Override
37 | public Iterator> properties(final String... propertyKeys) {
38 | throw new BitsyException(BitsyErrorCodes.NO_META_PROPERTY_SUPPORT);
39 | }
40 |
41 | @Override
42 | public Object id() {
43 | return element().id().toString() + ":" + key();
44 | }
45 |
46 | public String toString() {
47 | return StringFactory.propertyString(this);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ICommitChanges.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import java.util.Collection;
4 |
5 | public interface ICommitChanges {
6 | public Collection getVertexChanges();
7 |
8 | public Collection getEdgeChanges();
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/IEdge.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | public interface IEdge {
4 | public UUID getInVertexId();
5 |
6 | public UUID getOutVertexId();
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/IGraphStore.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import com.lambdazen.bitsy.store.EdgeBean;
4 | import com.lambdazen.bitsy.store.VertexBean;
5 | import com.lambdazen.bitsy.tx.BitsyTransaction;
6 | import java.util.Collection;
7 | import java.util.List;
8 | import java.util.Set;
9 | import org.apache.tinkerpop.gremlin.structure.Direction;
10 | import org.apache.tinkerpop.gremlin.structure.Element;
11 |
12 | public interface IGraphStore {
13 | public void commit(ICommitChanges changes);
14 |
15 | /** Only to be used internally within the store */
16 | public VertexBean getVertex(UUID id);
17 |
18 | /** Returns a transaction-specific BitsyVertex given the tx and the ID */
19 | public BitsyVertex getBitsyVertex(BitsyTransaction tx, UUID id);
20 |
21 | /** Only to be used internally within the store */
22 | public EdgeBean getEdge(UUID id);
23 |
24 | /** Returns a transaction-specific BitsyEdge given the tx and the ID */
25 | public BitsyEdge getBitsyEdge(BitsyTransaction tx, UUID id);
26 |
27 | public List getEdges(UUID vertexId, Direction dir, String[] edgeLabels);
28 |
29 | public Collection getAllVertices();
30 |
31 | public Collection getAllEdges();
32 |
33 | public void createKeyIndex(String key, Class elementType);
34 |
35 | public void dropKeyIndex(String key, Class elementType);
36 |
37 | public Set getIndexedKeys(Class elementType);
38 |
39 | public void shutdown();
40 |
41 | public Collection lookupVertices(String key, Object value);
42 |
43 | public Collection lookupEdges(String key, Object value);
44 |
45 | public boolean allowFullGraphScans();
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ITransaction.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import java.util.Iterator;
4 | import org.apache.tinkerpop.gremlin.structure.Direction;
5 | import org.apache.tinkerpop.gremlin.structure.Edge;
6 | import org.apache.tinkerpop.gremlin.structure.Transaction;
7 | import org.apache.tinkerpop.gremlin.structure.Vertex;
8 |
9 | public interface ITransaction extends Transaction {
10 | public void save(boolean commit);
11 |
12 | public void validateForQuery(BitsyElement bitsyElement) throws BitsyException;
13 |
14 | public Vertex getVertex(UUID outVertexId) throws BitsyException;
15 |
16 | public Edge getEdge(UUID id) throws BitsyException;
17 |
18 | public Iterable getEdges(BitsyVertex bitsyVertex, Direction dir, String... edgeLabels) throws BitsyException;
19 |
20 | public void markForPropertyUpdate(BitsyElement bitsyElement) throws BitsyException;
21 |
22 | public void addVertex(BitsyVertex vertex) throws BitsyException;
23 |
24 | public void removeVertex(BitsyVertex vertex) throws BitsyException;
25 |
26 | public void addEdge(BitsyEdge edge) throws BitsyException;
27 |
28 | public void removeEdge(BitsyEdge edge) throws BitsyException;
29 |
30 | public Iterator getAllVertices();
31 |
32 | public Iterator getAllEdges();
33 |
34 | public Iterator lookupVertices(String key, Object value);
35 |
36 | public Iterator lookupEdges(String key, Object value);
37 |
38 | public BitsyIsolationLevel getIsolationLevel();
39 |
40 | public void setIsolationLevel(BitsyIsolationLevel level);
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ThreadedBitsyGraph.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import com.lambdazen.bitsy.tx.BitsyTransaction;
4 | import com.lambdazen.bitsy.tx.BitsyTransactionContext;
5 |
6 | public class ThreadedBitsyGraph extends BitsyGraph {
7 | BitsyGraph underlyingGraph;
8 | BitsyTransaction tx;
9 |
10 | public ThreadedBitsyGraph(BitsyGraph g) {
11 | // Using protected constructor that doesn't create a graph store
12 | super('_', g.isFullGraphScanAllowed());
13 |
14 | this.underlyingGraph = g;
15 | this.tx = null;
16 | }
17 |
18 | public String toString() {
19 | return underlyingGraph.toString();
20 | }
21 |
22 | @Override
23 | public Features features() {
24 | return underlyingGraph.features();
25 | }
26 |
27 | @Override
28 | protected BitsyTransaction getTx() {
29 | // Overriding the getTx() method ensures that the work will be done on
30 | // the local transaction, NOT the ThreadLocal transaction
31 | if ((tx == null) || (!tx.isOpen())) {
32 | this.tx = new BitsyTransaction(
33 | new BitsyTransactionContext(underlyingGraph.getStore()),
34 | getDefaultIsolationLevel(),
35 | underlyingGraph);
36 | }
37 |
38 | return tx;
39 | }
40 |
41 | @Override
42 | /** This method can be used to check if the current threaded-graph is actively executing a transaction */
43 | public boolean isTransactionActive() {
44 | return (tx != null);
45 | }
46 |
47 | public BitsyIsolationLevel getDefaultIsolationLevel() {
48 | return underlyingGraph.getDefaultIsolationLevel();
49 | }
50 |
51 | public void setDefaultIsolationLevel(BitsyIsolationLevel level) {
52 | underlyingGraph.setDefaultIsolationLevel(level);
53 | }
54 |
55 | public BitsyIsolationLevel getTxIsolationLevel() {
56 | return getTx().getIsolationLevel();
57 | }
58 |
59 | public void setTxIsolationLevel(BitsyIsolationLevel level) {
60 | getTx().setIsolationLevel(level);
61 | }
62 |
63 | @Override
64 | public void shutdown() {
65 | // As per Blueprints tests, shutdown() implies automatic commit
66 | if (tx == null) {
67 | // Nothing to do
68 | } else {
69 | try {
70 | // Stop the old transaction if it exists
71 | tx.commit();
72 | } finally {
73 | // Remove this transaction -- independent of success/failure
74 | this.tx = null;
75 | }
76 | }
77 |
78 | // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one
79 | }
80 |
81 | // @Deprecated
82 | // public void stopTransaction(Conclusion conclusion) {
83 | // stopTx(conclusion == Conclusion.SUCCESS);
84 | // }
85 |
86 | // @Override
87 | // public void commit() {
88 | // tx.save(commit);
89 | // }
90 | //
91 | // @Override
92 | // public void rollback() {
93 | // stopTx(false);
94 | // }
95 | //
96 | // public void stopTx(boolean commit) {
97 | // if (tx == null) {
98 | // // Nothing to do
99 | // } else {
100 | // try {
101 | // // Stop the old transaction if it exists
102 | // tx.save(commit);
103 | // } finally {
104 | // // Remove this transaction -- independent of success/failure
105 | // this.tx = null;
106 | // }
107 | // }
108 | // }
109 | //
110 | // @Override
111 | // public TransactionalGraph startTransaction() {
112 | // throw new UnsupportedOperationException("Can not startTransaction on a threaded transaction graph");
113 | // }
114 | //
115 | // @Override
116 | // public void shutdown() {
117 | // // As per Blueprints tests, shutdown() implies automatic commit
118 | // stopTx(true);
119 | //
120 | // // Don't mess with the graph store -- this is only a ThreadedGraph, not the main one
121 | // }
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/UUID.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 |
5 | /** This class captures a UUID and is modeled after java.util.UUID */
6 | public class UUID implements Comparable {
7 | // Java guarantees that
8 | // "Reads and writes are atomic for reference variables and for most primitive variables (all types except long and
9 | // double)."
10 | // Therefore, mostSigBits and leastSigBits must not be changed during the lifetime of this object.
11 | // Also, these objects must not be accessible to other threads without a memory flush/fence/barrier
12 | // Typically this memory barrier is handled by the ConcurrentHashMap that holds the vertex/edge bean.
13 | private final long mostSigBits;
14 | private final long leastSigBits;
15 |
16 | public UUID(long msb, long lsb) {
17 | this.mostSigBits = msb;
18 | this.leastSigBits = lsb;
19 | }
20 |
21 | @JsonIgnore
22 | public long getMostSignificantBits() {
23 | return mostSigBits;
24 | }
25 |
26 | @JsonIgnore
27 | public long getLeastSignificantBits() {
28 | return leastSigBits;
29 | }
30 |
31 | public String toString() {
32 | return uuidRepr();
33 | }
34 |
35 | public String uuidRepr() {
36 | return new java.util.UUID(mostSigBits, leastSigBits).toString();
37 | }
38 |
39 | public static UUID fromString(String str) {
40 | java.util.UUID ans = java.util.UUID.fromString(str);
41 |
42 | return new UUID(ans.getMostSignificantBits(), ans.getLeastSignificantBits());
43 | }
44 |
45 | public static UUID randomUUID() {
46 | java.util.UUID ans = java.util.UUID.randomUUID();
47 |
48 | return new UUID(ans.getMostSignificantBits(), ans.getLeastSignificantBits());
49 | }
50 |
51 | public int compareTo(UUID other) {
52 | if (this.mostSigBits < other.mostSigBits) {
53 | return -1;
54 | } else if (this.mostSigBits > other.mostSigBits) {
55 | return 1;
56 | } else if (this.leastSigBits < other.leastSigBits) {
57 | return -1;
58 | } else if (this.leastSigBits > other.leastSigBits) {
59 | return 1;
60 | } else {
61 | return 0;
62 | }
63 | }
64 |
65 | @Override
66 | public int hashCode() {
67 | // Same as java.util.UUID
68 | long hilo = mostSigBits ^ leastSigBits;
69 | return ((int) (hilo >> 32)) ^ (int) hilo;
70 | }
71 |
72 | @Override
73 | public boolean equals(Object obj) {
74 | if (obj == null) {
75 | return false;
76 | } else if (this == obj) {
77 | return true;
78 | } else {
79 | try {
80 | UUID other = (UUID) obj;
81 | return (mostSigBits == other.getMostSignificantBits())
82 | && (leastSigBits == other.getLeastSignificantBits());
83 | } catch (ClassCastException e) {
84 | return false;
85 | }
86 | }
87 | }
88 |
89 | public static String toString(UUID obj) {
90 | return new java.util.UUID(obj.getMostSignificantBits(), obj.getLeastSignificantBits()).toString();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/UUIDGraphBinarySerializer.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy;
2 |
3 | import java.io.IOException;
4 | import org.apache.tinkerpop.gremlin.structure.io.Buffer;
5 | import org.apache.tinkerpop.gremlin.structure.io.binary.DataType;
6 | import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
7 | import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
8 | import org.apache.tinkerpop.gremlin.structure.io.binary.types.CustomTypeSerializer;
9 |
10 | public class UUIDGraphBinarySerializer implements CustomTypeSerializer {
11 |
12 | private final byte[] typeInfoBuffer = new byte[] {0, 0, 0, 0};
13 |
14 | @Override
15 | public String getTypeName() {
16 | return "bitsy.UUID";
17 | }
18 |
19 | @Override
20 | public DataType getDataType() {
21 | return DataType.CUSTOM;
22 | }
23 |
24 | @Override
25 | public UUID read(Buffer buffer, GraphBinaryReader context) throws IOException {
26 | // {custom type info}, {value_flag} and {value}
27 | // No custom_type_info
28 | if (buffer.readInt() != 0) {
29 | throw new IOException("{custom_type_info} should not be provided for this custom type");
30 | }
31 |
32 | return readValue(buffer, context, true);
33 | }
34 |
35 | @Override
36 | public UUID readValue(Buffer buffer, GraphBinaryReader context, boolean nullable) throws IOException {
37 | if (nullable) {
38 | final byte valueFlag = buffer.readByte();
39 | if ((valueFlag & 1) == 1) {
40 | return null;
41 | }
42 | }
43 |
44 | // Read the byte length of the value bytes
45 | final int valueLength = buffer.readInt();
46 |
47 | if (valueLength <= 0) {
48 | throw new IOException(String.format("Unexpected value length: %d", valueLength));
49 | }
50 |
51 | if (valueLength > buffer.readableBytes()) {
52 | throw new IOException(
53 | String.format("Not enough readable bytes: %d (expected %d)", valueLength, buffer.readableBytes()));
54 | }
55 |
56 | long msb = context.readValue(buffer, Long.class, false);
57 | long lsb = context.readValue(buffer, Long.class, false);
58 | return new UUID(msb, lsb);
59 | }
60 |
61 | @Override
62 | public void write(UUID value, Buffer buffer, GraphBinaryWriter context) throws IOException {
63 | // Write {custom type info}, {value_flag} and {value}
64 | buffer.writeBytes(typeInfoBuffer);
65 |
66 | writeValue(value, buffer, context, true);
67 | }
68 |
69 | @Override
70 | public void writeValue(UUID value, Buffer buffer, GraphBinaryWriter context, boolean nullable) throws IOException {
71 | if (value == null) {
72 | if (!nullable) {
73 | throw new IOException("Unexpected null value when nullable is false");
74 | }
75 |
76 | context.writeValueFlagNull(buffer);
77 | return;
78 | }
79 |
80 | if (nullable) {
81 | context.writeValueFlagNone(buffer);
82 | }
83 |
84 | final Long msb = value.getMostSignificantBits();
85 | final Long lsb = value.getLeastSignificantBits();
86 |
87 | // value_length = name_byte_length + long + long
88 | buffer.writeInt(4 + 8 + 8);
89 |
90 | context.writeValue(msb, buffer, false);
91 | context.writeValue(lsb, buffer, false);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | import com.lambdazen.bitsy.store.IStringCanonicalizer;
4 |
5 | /**
6 | * This is an re-organizing (not immutable) map from String to Object. The set
7 | * and remove methods return a reference to a new map with the value.
8 | */
9 | public interface Dictionary {
10 | public int size();
11 |
12 | public Object getProperty(String key);
13 |
14 | public String[] getPropertyKeys();
15 |
16 | public Dictionary setProperty(String key, Object value);
17 |
18 | public Dictionary removeProperty(String key);
19 |
20 | public Dictionary copyOf();
21 |
22 | // public TreeMap toMap();
23 |
24 | public void canonicalizeKeys(IStringCanonicalizer canonicalizer);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary1.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | /** This class implements a dictionary with one element */
4 | public class Dictionary1 extends PrimitiveDictionary implements Dictionary {
5 | public static final int CAPACITY = 1;
6 |
7 | String key0;
8 | Object value0;
9 |
10 | // Expand constructor
11 | public Dictionary1(String key, Object value) {
12 | this.key0 = key;
13 | this.value0 = value;
14 | }
15 |
16 | // Contract constructor
17 | public Dictionary1(Dictionary2 base) {
18 | this.key0 = base.key0;
19 | this.value0 = base.value0;
20 | }
21 |
22 | // Copy constructor
23 | public Dictionary1(Dictionary1 base) {
24 | this.key0 = base.key0;
25 | this.value0 = base.value0;
26 | }
27 |
28 | @Override
29 | protected String[] keys() {
30 | return new String[] {key0};
31 | }
32 |
33 | @Override
34 | protected Object[] values() {
35 | return new Object[] {value0};
36 | }
37 |
38 | @Override
39 | public Dictionary copyOf() {
40 | return new Dictionary1(this);
41 | }
42 |
43 | protected int contractThreshold() {
44 | return 0;
45 | }
46 |
47 | protected Dictionary contract() {
48 | return null;
49 | }
50 |
51 | protected Dictionary expand(String key, Object value) {
52 | return new Dictionary2(this, key, value);
53 | }
54 |
55 | protected void write(int index, String key, Object value) {
56 | key0 = key;
57 | value0 = value;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary2.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | public class Dictionary2 extends PrimitiveDictionary implements Dictionary {
4 | public static final int CAPACITY = 2;
5 |
6 | String key0;
7 | Object value0;
8 |
9 | String key1;
10 | Object value1;
11 |
12 | // Expand constructor
13 | public Dictionary2(Dictionary1 base, String key, Object value) {
14 | this.key0 = base.key0;
15 | this.value0 = base.value0;
16 |
17 | // Last key
18 | this.key1 = key;
19 | this.value1 = value;
20 | }
21 |
22 | // Contract constructor
23 | public Dictionary2(Dictionary3 base) {
24 | this.key0 = base.key0;
25 | this.value0 = base.value0;
26 |
27 | this.key1 = base.key1;
28 | this.value1 = base.value1;
29 | }
30 |
31 | // Copy constructor
32 | public Dictionary2(Dictionary2 base) {
33 | this.key0 = base.key0;
34 | this.value0 = base.value0;
35 |
36 | this.key1 = base.key1;
37 | this.value1 = base.value1;
38 | }
39 |
40 | // FromMap constructor
41 | public Dictionary2(String[] keys, Object[] values) {
42 | this.key0 = lookupKey(keys, 0);
43 | this.value0 = lookupValue(values, 0);
44 |
45 | this.key1 = lookupKey(keys, 1);
46 | this.value1 = lookupValue(values, 1);
47 | }
48 |
49 | @Override
50 | String[] keys() {
51 | return new String[] {key0, key1};
52 | }
53 |
54 | @Override
55 | Object[] values() {
56 | return new Object[] {value0, value1};
57 | }
58 |
59 | @Override
60 | void write(int index, String key, Object value) {
61 | switch (index) {
62 | case 0:
63 | key0 = key;
64 | value0 = value;
65 | break;
66 |
67 | case 1:
68 | key1 = key;
69 | value1 = value;
70 | break;
71 |
72 | default:
73 | throw new IllegalArgumentException("Invalid index " + index);
74 | }
75 | }
76 |
77 | @Override
78 | Dictionary expand(String key, Object value) {
79 | return new Dictionary3(this, key, value);
80 | }
81 |
82 | @Override
83 | int contractThreshold() {
84 | return Dictionary1.CAPACITY;
85 | }
86 |
87 | @Override
88 | Dictionary contract() {
89 | return new Dictionary1(this);
90 | }
91 |
92 | @Override
93 | public Dictionary copyOf() {
94 | return new Dictionary2(this);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary3.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | public class Dictionary3 extends PrimitiveDictionary implements Dictionary {
4 | public static final int CAPACITY = 3;
5 |
6 | String key0;
7 | Object value0;
8 |
9 | String key1;
10 | Object value1;
11 |
12 | String key2;
13 | Object value2;
14 |
15 | // Expand constructor
16 | public Dictionary3(Dictionary2 base, String key, Object value) {
17 | this.key0 = base.key0;
18 | this.value0 = base.value0;
19 |
20 | this.key1 = base.key1;
21 | this.value1 = base.value1;
22 |
23 | // Last key
24 | this.key2 = key;
25 | this.value2 = value;
26 | }
27 |
28 | // Contract constructor
29 | public Dictionary3(Dictionary4 base) {
30 | this.key0 = base.key0;
31 | this.value0 = base.value0;
32 |
33 | this.key1 = base.key1;
34 | this.value1 = base.value1;
35 |
36 | this.key2 = base.key2;
37 | this.value2 = base.value2;
38 | }
39 |
40 | // Copy constructor
41 | public Dictionary3(Dictionary3 base) {
42 | this.key0 = base.key0;
43 | this.value0 = base.value0;
44 |
45 | this.key1 = base.key1;
46 | this.value1 = base.value1;
47 |
48 | this.key2 = base.key2;
49 | this.value2 = base.value2;
50 | }
51 |
52 | // FromMap constructor
53 | public Dictionary3(String[] keys, Object[] values) {
54 | this.key0 = lookupKey(keys, 0);
55 | this.value0 = lookupValue(values, 0);
56 |
57 | this.key1 = lookupKey(keys, 1);
58 | this.value1 = lookupValue(values, 1);
59 |
60 | this.key2 = lookupKey(keys, 2);
61 | this.value2 = lookupValue(values, 2);
62 | }
63 |
64 | @Override
65 | String[] keys() {
66 | return new String[] {key0, key1, key2};
67 | }
68 |
69 | @Override
70 | Object[] values() {
71 | return new Object[] {value0, value1, value2};
72 | }
73 |
74 | @Override
75 | void write(int index, String key, Object value) {
76 | switch (index) {
77 | case 0:
78 | key0 = key;
79 | value0 = value;
80 | break;
81 |
82 | case 1:
83 | key1 = key;
84 | value1 = value;
85 | break;
86 |
87 | case 2:
88 | key2 = key;
89 | value2 = value;
90 | break;
91 |
92 | default:
93 | throw new IllegalArgumentException("Invalid index " + index);
94 | }
95 | }
96 |
97 | @Override
98 | Dictionary expand(String key, Object value) {
99 | return new Dictionary4(this, key, value);
100 | }
101 |
102 | @Override
103 | int contractThreshold() {
104 | return Dictionary2.CAPACITY;
105 | }
106 |
107 | @Override
108 | Dictionary contract() {
109 | return new Dictionary2(this);
110 | }
111 |
112 | @Override
113 | public Dictionary copyOf() {
114 | return new Dictionary3(this);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary4.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | public class Dictionary4 extends PrimitiveDictionary implements Dictionary {
4 | public static final int CAPACITY = 4;
5 |
6 | String key0;
7 | Object value0;
8 |
9 | String key1;
10 | Object value1;
11 |
12 | String key2;
13 | Object value2;
14 |
15 | String key3;
16 | Object value3;
17 |
18 | // Expand constructor
19 | public Dictionary4(Dictionary3 base, String key, Object value) {
20 | this.key0 = base.key0;
21 | this.value0 = base.value0;
22 |
23 | this.key1 = base.key1;
24 | this.value1 = base.value1;
25 |
26 | this.key2 = base.key2;
27 | this.value2 = base.value2;
28 |
29 | // Last key
30 | this.key3 = key;
31 | this.value3 = value;
32 | }
33 |
34 | // Contract constructor
35 | public Dictionary4(Dictionary6 base) {
36 | this.key0 = base.key0;
37 | this.value0 = base.value0;
38 |
39 | this.key1 = base.key1;
40 | this.value1 = base.value1;
41 |
42 | this.key2 = base.key2;
43 | this.value2 = base.value2;
44 |
45 | this.key3 = base.key3;
46 | this.value3 = base.value3;
47 | }
48 |
49 | // Copy constructor
50 | public Dictionary4(Dictionary4 base) {
51 | this.key0 = base.key0;
52 | this.value0 = base.value0;
53 |
54 | this.key1 = base.key1;
55 | this.value1 = base.value1;
56 |
57 | this.key2 = base.key2;
58 | this.value2 = base.value2;
59 |
60 | this.key3 = base.key3;
61 | this.value3 = base.value3;
62 | }
63 |
64 | // FromMap constructor
65 | public Dictionary4(String[] keys, Object[] values) {
66 | this.key0 = lookupKey(keys, 0);
67 | this.value0 = lookupValue(values, 0);
68 |
69 | this.key1 = lookupKey(keys, 1);
70 | this.value1 = lookupValue(values, 1);
71 |
72 | this.key2 = lookupKey(keys, 2);
73 | this.value2 = lookupValue(values, 2);
74 |
75 | this.key3 = lookupKey(keys, 3);
76 | this.value3 = lookupValue(values, 3);
77 | }
78 |
79 | @Override
80 | String[] keys() {
81 | return new String[] {key0, key1, key2, key3};
82 | }
83 |
84 | @Override
85 | Object[] values() {
86 | return new Object[] {value0, value1, value2, value3};
87 | }
88 |
89 | @Override
90 | void write(int index, String key, Object value) {
91 | switch (index) {
92 | case 0:
93 | key0 = key;
94 | value0 = value;
95 | break;
96 |
97 | case 1:
98 | key1 = key;
99 | value1 = value;
100 | break;
101 |
102 | case 2:
103 | key2 = key;
104 | value2 = value;
105 | break;
106 |
107 | case 3:
108 | key3 = key;
109 | value3 = value;
110 | break;
111 |
112 | default:
113 | throw new IllegalArgumentException("Invalid index " + index);
114 | }
115 | }
116 |
117 | @Override
118 | Dictionary expand(String key, Object value) {
119 | return new Dictionary6(this, key, value);
120 | }
121 |
122 | @Override
123 | int contractThreshold() {
124 | return Dictionary3.CAPACITY;
125 | }
126 |
127 | @Override
128 | Dictionary contract() {
129 | return new Dictionary3(this);
130 | }
131 |
132 | @Override
133 | public Dictionary copyOf() {
134 | return new Dictionary4(this);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/Dictionary6.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | public class Dictionary6 extends PrimitiveDictionary implements Dictionary {
4 | public static final int CAPACITY = 6;
5 |
6 | String key0;
7 | Object value0;
8 |
9 | String key1;
10 | Object value1;
11 |
12 | String key2;
13 | Object value2;
14 |
15 | String key3;
16 | Object value3;
17 |
18 | String key4;
19 | Object value4;
20 |
21 | String key5;
22 | Object value5;
23 |
24 | // Expand constructor
25 | public Dictionary6(Dictionary4 base, String key, Object value) {
26 | this.key0 = base.key0;
27 | this.value0 = base.value0;
28 |
29 | this.key1 = base.key1;
30 | this.value1 = base.value1;
31 |
32 | this.key2 = base.key2;
33 | this.value2 = base.value2;
34 |
35 | this.key3 = base.key3;
36 | this.value3 = base.value3;
37 |
38 | // Last key
39 | this.key4 = key;
40 | this.value4 = value;
41 | }
42 |
43 | // Contract constructor
44 | public Dictionary6(Dictionary8 base) {
45 | this.key0 = base.key0;
46 | this.value0 = base.value0;
47 |
48 | this.key1 = base.key1;
49 | this.value1 = base.value1;
50 |
51 | this.key2 = base.key2;
52 | this.value2 = base.value2;
53 |
54 | this.key3 = base.key3;
55 | this.value3 = base.value3;
56 |
57 | this.key4 = base.key4;
58 | this.value4 = base.value4;
59 |
60 | this.key5 = base.key5;
61 | this.value5 = base.value5;
62 | }
63 |
64 | // Copy constructor
65 | public Dictionary6(Dictionary6 base) {
66 | this.key0 = base.key0;
67 | this.value0 = base.value0;
68 |
69 | this.key1 = base.key1;
70 | this.value1 = base.value1;
71 |
72 | this.key2 = base.key2;
73 | this.value2 = base.value2;
74 |
75 | this.key3 = base.key3;
76 | this.value3 = base.value3;
77 |
78 | this.key4 = base.key4;
79 | this.value4 = base.value4;
80 |
81 | this.key5 = base.key5;
82 | this.value5 = base.value5;
83 | }
84 |
85 | // FromMap constructor
86 | public Dictionary6(String[] keys, Object[] values) {
87 | this.key0 = lookupKey(keys, 0);
88 | this.value0 = lookupValue(values, 0);
89 |
90 | this.key1 = lookupKey(keys, 1);
91 | this.value1 = lookupValue(values, 1);
92 |
93 | this.key2 = lookupKey(keys, 2);
94 | this.value2 = lookupValue(values, 2);
95 |
96 | this.key3 = lookupKey(keys, 3);
97 | this.value3 = lookupValue(values, 3);
98 |
99 | this.key4 = lookupKey(keys, 4);
100 | this.value4 = lookupValue(values, 4);
101 |
102 | this.key5 = lookupKey(keys, 5);
103 | this.value5 = lookupValue(values, 5);
104 | }
105 |
106 | @Override
107 | String[] keys() {
108 | return new String[] {key0, key1, key2, key3, key4, key5};
109 | }
110 |
111 | @Override
112 | Object[] values() {
113 | return new Object[] {value0, value1, value2, value3, value4, value5};
114 | }
115 |
116 | @Override
117 | void write(int index, String key, Object value) {
118 | switch (index) {
119 | case 0:
120 | key0 = key;
121 | value0 = value;
122 | break;
123 |
124 | case 1:
125 | key1 = key;
126 | value1 = value;
127 | break;
128 |
129 | case 2:
130 | key2 = key;
131 | value2 = value;
132 | break;
133 |
134 | case 3:
135 | key3 = key;
136 | value3 = value;
137 | break;
138 |
139 | case 4:
140 | key4 = key;
141 | value4 = value;
142 | break;
143 |
144 | case 5:
145 | key5 = key;
146 | value5 = value;
147 | break;
148 |
149 | default:
150 | throw new IllegalArgumentException("Invalid index " + index);
151 | }
152 | }
153 |
154 | @Override
155 | Dictionary expand(String key, Object value) {
156 | return new Dictionary8(this, key, value);
157 | }
158 |
159 | @Override
160 | int contractThreshold() {
161 | return Dictionary4.CAPACITY;
162 | }
163 |
164 | @Override
165 | Dictionary contract() {
166 | return new Dictionary4(this);
167 | }
168 |
169 | @Override
170 | public Dictionary copyOf() {
171 | return new Dictionary6(this);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryFactory.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | import java.util.Map;
4 |
5 | public class DictionaryFactory {
6 | public static Dictionary fromMap(Map properties) {
7 | if (properties == null) {
8 | return null;
9 | }
10 |
11 | int size = properties.size();
12 | String[] keys = new String[size];
13 | Object[] values = new Object[size];
14 |
15 | int counter = 0;
16 | for (Map.Entry entry : properties.entrySet()) {
17 | keys[counter] = entry.getKey();
18 | values[counter] = entry.getValue();
19 | counter++;
20 | }
21 |
22 | // assert counter == size;
23 |
24 | if (size == 0) {
25 | return null;
26 | } else if (size <= 1) {
27 | return new Dictionary1(keys[0], values[0]);
28 | } else if (size <= 2) {
29 | return new Dictionary2(keys, values);
30 | } else if (size <= 3) {
31 | return new Dictionary3(keys, values);
32 | } else if (size <= 4) {
33 | return new Dictionary4(keys, values);
34 | } else if (size <= 6) {
35 | return new Dictionary6(keys, values);
36 | } else if (size <= 8) {
37 | return new Dictionary8(keys, values);
38 | } else if (size <= 11) {
39 | return new Dictionary11(keys, values);
40 | } else if (size <= 16) {
41 | return new Dictionary16(keys, values);
42 | } else {
43 | return new DictionaryMax(keys, values);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/dict/DictionaryMax.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.dict;
2 |
3 | import java.util.Arrays;
4 |
5 | public class DictionaryMax extends PrimitiveDictionary implements Dictionary {
6 | int capacity;
7 | String[] keys;
8 | Object[] values;
9 |
10 | // Expand constructor
11 | public DictionaryMax(Dictionary16 base, String key, Object value) {
12 | this.capacity = 24;
13 | keys = Arrays.copyOf(base.keys(), capacity);
14 | values = Arrays.copyOf(base.values(), capacity);
15 |
16 | keys[16] = key;
17 | values[16] = value;
18 | }
19 |
20 | // Copy constructor
21 | public DictionaryMax(DictionaryMax base) {
22 | this.capacity = base.capacity;
23 | keys = Arrays.copyOf(base.keys(), capacity);
24 | values = Arrays.copyOf(base.values(), capacity);
25 | }
26 |
27 | // FromMap constructor
28 | public DictionaryMax(String[] keys, Object[] values) {
29 | this.capacity = Math.max(24, keys.length + keys.length / 2);
30 |
31 | this.keys = Arrays.copyOf(keys, capacity);
32 | this.values = Arrays.copyOf(values, capacity);
33 | }
34 |
35 | @Override
36 | String[] keys() {
37 | return keys;
38 | }
39 |
40 | @Override
41 | Object[] values() {
42 | return values;
43 | }
44 |
45 | @Override
46 | void write(int index, String key, Object value) {
47 | keys[index] = key;
48 | values[index] = value;
49 | }
50 |
51 | @Override
52 | Dictionary expand(String key, Object value) {
53 | int newCapacity = capacity + (capacity / 2);
54 | keys = Arrays.copyOf(keys, newCapacity);
55 | values = Arrays.copyOf(values, newCapacity);
56 |
57 | keys[capacity] = key;
58 | values[capacity] = value;
59 |
60 | this.capacity = newCapacity;
61 |
62 | return this;
63 | }
64 |
65 | @Override
66 | int contractThreshold() {
67 | return capacity / 2;
68 | }
69 |
70 | @Override
71 | Dictionary contract() {
72 | if (capacity < 14) {
73 | // Move to Dictionary16
74 | return new Dictionary16(this);
75 | } else {
76 | int newCapacity = capacity * 3 / 4;
77 | keys = Arrays.copyOf(keys, newCapacity);
78 | values = Arrays.copyOf(values, newCapacity);
79 | this.capacity = newCapacity;
80 |
81 | return this;
82 | }
83 | }
84 |
85 | @Override
86 | public Dictionary copyOf() {
87 | return new DictionaryMax(this);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/ArraySet.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * This class uses an array-based set implementation rather than SetMax and
7 | * CompactMultiSetMax classes that implement a hash-based set. Neither
8 | * implementation throws ConcurrentModificationException on reads, but expect
9 | * writes to be serialized.
10 | */
11 | public class ArraySet implements Set {
12 | int size;
13 | Object[] elements;
14 |
15 | public ArraySet(Object[] elements) {
16 | this(elements, elements.length);
17 | }
18 |
19 | protected ArraySet(Object[] elements, int size) {
20 | this.size = size;
21 | this.elements = new Object[size + size / 2];
22 |
23 | for (int i = 0; i < size; i++) {
24 | this.elements[i] = (T) elements[i];
25 | }
26 | }
27 |
28 | @Override
29 | public int size() {
30 | return size;
31 | }
32 |
33 | @Override
34 | public Object[] getElements() {
35 | return Arrays.copyOf(elements, size);
36 | }
37 |
38 | @Override
39 | public Object removeElement(T elem) {
40 | // Go over elements and remove the one
41 | for (int i = 0; i < size; i++) {
42 | if (elem.equals(elements[i])) {
43 | if (i < size - 1) {
44 | elements[i] = elements[size - 1];
45 | }
46 |
47 | this.size--;
48 | elements[size] = null;
49 |
50 | break;
51 | }
52 | }
53 |
54 | if (size < 16) {
55 | return new Set24(getElements());
56 | } else if (size < elements.length / 2) {
57 | // Using the constructor that cuts the size -- to avoid two array creations
58 | return new ArraySet(elements, size);
59 | } else {
60 | // Use the same object
61 | return this;
62 | }
63 | }
64 |
65 | @Override
66 | public Set addElement(T elem) {
67 | for (int i = 0; i < size; i++) {
68 | if (elem.equals(elements[i])) {
69 | // Nothing to do
70 | return this;
71 | }
72 | }
73 |
74 | if (size < elements.length) {
75 | elements[size] = elem;
76 | this.size++;
77 | return this;
78 | } else {
79 | Set ans = new ArraySet(elements);
80 | ans.addElement(elem);
81 | return ans;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/ClassifierGetter.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public interface ClassifierGetter {
4 | public C getClassifier(T obj);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/CompactSet.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class CompactSet {
4 | public static int size(Object set) {
5 | if (set == null) {
6 | return 0;
7 | } else if (set instanceof Set) {
8 | return ((Set) set).size();
9 | } else {
10 | return 1;
11 | }
12 | }
13 |
14 | public static Object[] getElements(Object set) {
15 | if (set == null) {
16 | return new Object[0];
17 | } else if (set instanceof Set) {
18 | return ((Set>) set).getElements();
19 | } else {
20 | return new Object[] {set};
21 | }
22 | }
23 |
24 | public static Object add(Object set, T elem) {
25 | if (set == null) {
26 | return elem;
27 | } else if (set instanceof Set) {
28 | return ((Set) set).addElement(elem);
29 | } else {
30 | if (set.equals(elem)) {
31 | return set;
32 | } else {
33 | return new Set2(set, elem);
34 | }
35 | }
36 | }
37 |
38 | public static Object addSafe(Object set, T elem) {
39 | if ((set instanceof Set24) && (CompactSet.size(set) == 24)) {
40 | // Move to ArraySet instead of SetMax to avoid cyclic dependency from CompactMultiSetMax and SetMax
41 | set = new ArraySet(CompactSet.getElements(set));
42 | }
43 |
44 | return CompactSet.add(set, elem);
45 | }
46 |
47 | public static Object remove(Object set, T elem) {
48 | if (set == null) {
49 | return null;
50 | } else if (set instanceof Set) {
51 | return ((Set) set).removeElement(elem);
52 | } else {
53 | if ((set == elem) || (set.equals(elem))) {
54 | return null;
55 | } else {
56 | return set;
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/PrimitiveSet.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | import java.util.Arrays;
4 |
5 | public abstract class PrimitiveSet implements Set {
6 | public PrimitiveSet() {
7 | // Nothing to do
8 | }
9 |
10 | abstract Object[] elements();
11 |
12 | abstract void write(int index, T elem);
13 |
14 | abstract Set expand(T elem);
15 |
16 | abstract int contractThreshold();
17 |
18 | abstract Object contract();
19 |
20 | public int size() {
21 | Object[] elems = elements();
22 |
23 | return size(elems);
24 | }
25 |
26 | private int size(Object[] elems) {
27 | int i;
28 | for (i = 0; i < elems.length; i++) {
29 | if (elems[i] == null) {
30 | break;
31 | }
32 | }
33 |
34 | return i;
35 | }
36 |
37 | public Object[] getElements() {
38 | Object[] elems = elements();
39 |
40 | int i;
41 | for (i = 0; i < elems.length; i++) {
42 | if (elems[i] == null) {
43 | break;
44 | }
45 | }
46 |
47 | return Arrays.copyOf(elems, i);
48 | }
49 |
50 | public Set addElement(T elem) {
51 | Object[] elems = elements();
52 | int size = elems.length;
53 |
54 | boolean duplicate = false;
55 | int i;
56 | for (i = 0; i < size; i++) {
57 | T curElem = (T) elems[i];
58 |
59 | if (curElem == null) {
60 | // End of keys
61 | break;
62 | } else if (elems[i].equals(elem)) {
63 | duplicate = true;
64 | }
65 | }
66 |
67 | if (duplicate) {
68 | // Stick with this
69 | return this;
70 | } else {
71 | if (i == size) {
72 | // Reached end, need to move up
73 | return expand(elem);
74 | } else {
75 | // Not yet at the end
76 | write(i, elem);
77 |
78 | return this;
79 | }
80 | }
81 | }
82 |
83 | @Override
84 | public Object removeElement(T elem) {
85 | Object[] elems = elements();
86 | int size = elems.length;
87 |
88 | int overwritePos = -1;
89 | int i;
90 | for (i = 0; i < size; i++) {
91 | Object curElem = elems[i];
92 |
93 | if (curElem == null) {
94 | // End of keys
95 | break;
96 | } else if (curElem.equals(elem)) {
97 | overwritePos = i;
98 | }
99 | }
100 |
101 | if (overwritePos == -1) {
102 | // Couldn't find key
103 | return this;
104 | } else {
105 | // Overwrite from end to here
106 | int lastIdx = i - 1;
107 | if (overwritePos != lastIdx) {
108 | write(overwritePos, (T) elems[lastIdx]);
109 | }
110 | write(lastIdx, null);
111 |
112 | if (lastIdx <= contractThreshold()) {
113 | // The new size is at or below the contract threshold
114 | return contract();
115 | } else {
116 | return this;
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | /** A bag keeps an unordered, unstable collection of elements */
4 | public interface Set {
5 | public int size();
6 |
7 | public Object[] getElements();
8 |
9 | public Object removeElement(T elem);
10 |
11 | public Set addElement(T elem);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set12.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set12 extends PrimitiveSet implements Set {
4 | T elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11;
5 |
6 | public Set12(Set8 oldSet, T elem) {
7 | this.elem0 = oldSet.elem0;
8 | this.elem1 = oldSet.elem1;
9 | this.elem2 = oldSet.elem2;
10 | this.elem3 = oldSet.elem3;
11 | this.elem4 = oldSet.elem4;
12 | this.elem5 = oldSet.elem5;
13 | this.elem6 = oldSet.elem6;
14 | this.elem7 = oldSet.elem7;
15 | this.elem8 = elem;
16 | }
17 |
18 | public Set12(Set24 oldSet) {
19 | this.elem0 = oldSet.elem0;
20 | this.elem1 = oldSet.elem1;
21 | this.elem2 = oldSet.elem2;
22 | this.elem3 = oldSet.elem3;
23 | this.elem4 = oldSet.elem4;
24 | this.elem5 = oldSet.elem5;
25 | this.elem6 = oldSet.elem6;
26 | this.elem7 = oldSet.elem7;
27 | this.elem8 = oldSet.elem8;
28 | this.elem9 = oldSet.elem9;
29 | this.elem10 = oldSet.elem10;
30 | this.elem11 = oldSet.elem11;
31 | }
32 |
33 | @Override
34 | public Object[] elements() {
35 | return new Object[] {elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7, elem8, elem9, elem10, elem11};
36 | }
37 |
38 | protected void write(int index, T elem) {
39 | if (index < 4) {
40 | switch (index) {
41 | case 0:
42 | this.elem0 = elem;
43 | break;
44 |
45 | case 1:
46 | this.elem1 = elem;
47 | break;
48 |
49 | case 2:
50 | this.elem2 = elem;
51 | break;
52 |
53 | case 3:
54 | this.elem3 = elem;
55 | break;
56 |
57 | default:
58 | throw new RuntimeException("Bug in code");
59 | }
60 | } else if (index < 8) {
61 | switch (index) {
62 | case 4:
63 | this.elem4 = elem;
64 | break;
65 |
66 | case 5:
67 | this.elem5 = elem;
68 | break;
69 |
70 | case 6:
71 | this.elem6 = elem;
72 | break;
73 |
74 | case 7:
75 | this.elem7 = elem;
76 | break;
77 |
78 | default:
79 | throw new IllegalArgumentException("Invalid index " + index);
80 | }
81 | } else {
82 | switch (index) {
83 | case 8:
84 | this.elem8 = elem;
85 | break;
86 |
87 | case 9:
88 | this.elem9 = elem;
89 | break;
90 |
91 | case 10:
92 | this.elem10 = elem;
93 | break;
94 |
95 | case 11:
96 | this.elem11 = elem;
97 | break;
98 |
99 | default:
100 | throw new IllegalArgumentException("Invalid index " + index);
101 | }
102 | }
103 | }
104 |
105 | @Override
106 | Set expand(T elem) {
107 | return new Set24(this, elem);
108 | }
109 |
110 | @Override
111 | int contractThreshold() {
112 | return 8;
113 | }
114 |
115 | @Override
116 | Set contract() {
117 | return new Set8(this);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set2.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set2 extends PrimitiveSet implements Set {
4 | T elem0, elem1;
5 |
6 | public Set2(T elem0, T elem1) {
7 | this.elem0 = elem0;
8 | this.elem1 = elem1;
9 | }
10 |
11 | public Set2(Set3 oldBag) {
12 | this.elem0 = oldBag.elem0;
13 | this.elem1 = oldBag.elem1;
14 | }
15 |
16 | @Override
17 | public Object[] elements() {
18 | return new Object[] {elem0, elem1};
19 | }
20 |
21 | protected void write(int index, T elem) {
22 | switch (index) {
23 | case 0:
24 | elem0 = elem;
25 | break;
26 |
27 | case 1:
28 | elem1 = elem;
29 | break;
30 |
31 | default:
32 | throw new IllegalArgumentException("Invalid index " + index);
33 | }
34 | }
35 |
36 | @Override
37 | Set expand(T elem) {
38 | return new Set3(this, elem);
39 | }
40 |
41 | @Override
42 | int contractThreshold() {
43 | return 1;
44 | }
45 |
46 | @Override
47 | Object contract() {
48 | return this.elem0;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set3.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set3 extends PrimitiveSet implements Set {
4 | T elem0, elem1, elem2;
5 |
6 | public Set3(Set2 oldSet, T elem) {
7 | this.elem0 = oldSet.elem0;
8 | this.elem1 = oldSet.elem1;
9 | this.elem2 = elem;
10 | }
11 |
12 | public Set3(Set4 oldSet) {
13 | this.elem0 = oldSet.elem0;
14 | this.elem1 = oldSet.elem1;
15 | this.elem2 = oldSet.elem2;
16 | }
17 |
18 | @Override
19 | public Object[] elements() {
20 | return new Object[] {elem0, elem1, elem2};
21 | }
22 |
23 | protected void write(int index, T elem) {
24 | switch (index) {
25 | case 0:
26 | elem0 = elem;
27 | break;
28 |
29 | case 1:
30 | elem1 = elem;
31 | break;
32 |
33 | case 2:
34 | elem2 = elem;
35 | break;
36 |
37 | default:
38 | throw new IllegalArgumentException("Invalid index " + index);
39 | }
40 | }
41 |
42 | @Override
43 | Set expand(T elem) {
44 | return new Set4(this, elem);
45 | }
46 |
47 | @Override
48 | int contractThreshold() {
49 | return 2;
50 | }
51 |
52 | @Override
53 | Set contract() {
54 | return new Set2(this);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set4.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set4 extends PrimitiveSet implements Set {
4 | T elem0, elem1, elem2, elem3;
5 |
6 | public Set4(Set3 oldSet, T elem) {
7 | this.elem0 = oldSet.elem0;
8 | this.elem1 = oldSet.elem1;
9 | this.elem2 = oldSet.elem2;
10 | this.elem3 = elem;
11 | }
12 |
13 | public Set4(Set6 oldSet) {
14 | this.elem0 = oldSet.elem0;
15 | this.elem1 = oldSet.elem1;
16 | this.elem2 = oldSet.elem2;
17 | this.elem3 = oldSet.elem3;
18 | }
19 |
20 | @Override
21 | public Object[] elements() {
22 | return new Object[] {elem0, elem1, elem2, elem3};
23 | }
24 |
25 | protected void write(int index, T elem) {
26 | switch (index) {
27 | case 0:
28 | elem0 = elem;
29 | break;
30 |
31 | case 1:
32 | elem1 = elem;
33 | break;
34 |
35 | case 2:
36 | elem2 = elem;
37 | break;
38 |
39 | case 3:
40 | elem3 = elem;
41 | break;
42 |
43 | default:
44 | throw new IllegalArgumentException("Invalid index " + index);
45 | }
46 | }
47 |
48 | @Override
49 | Set expand(T elem) {
50 | return new Set6(this, elem);
51 | }
52 |
53 | @Override
54 | int contractThreshold() {
55 | return 3;
56 | }
57 |
58 | @Override
59 | Set contract() {
60 | return new Set3(this);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set6.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set6 extends PrimitiveSet implements Set {
4 | T elem0, elem1, elem2, elem3, elem4, elem5;
5 |
6 | public Set6(Set4 oldSet, T elem) {
7 | this.elem0 = oldSet.elem0;
8 | this.elem1 = oldSet.elem1;
9 | this.elem2 = oldSet.elem2;
10 | this.elem3 = oldSet.elem3;
11 | this.elem4 = elem;
12 | }
13 |
14 | public Set6(Set8 oldSet) {
15 | this.elem0 = oldSet.elem0;
16 | this.elem1 = oldSet.elem1;
17 | this.elem2 = oldSet.elem2;
18 | this.elem3 = oldSet.elem3;
19 | this.elem4 = oldSet.elem4;
20 | this.elem5 = oldSet.elem5;
21 | }
22 |
23 | @Override
24 | public Object[] elements() {
25 | return new Object[] {elem0, elem1, elem2, elem3, elem4, elem5};
26 | }
27 |
28 | protected void write(int index, T elem) {
29 | switch (index) {
30 | case 0:
31 | elem0 = elem;
32 | break;
33 |
34 | case 1:
35 | elem1 = elem;
36 | break;
37 |
38 | case 2:
39 | elem2 = elem;
40 | break;
41 |
42 | case 3:
43 | elem3 = elem;
44 | break;
45 |
46 | case 4:
47 | elem4 = elem;
48 | break;
49 |
50 | case 5:
51 | elem5 = elem;
52 | break;
53 |
54 | default:
55 | throw new IllegalArgumentException("Invalid index " + index);
56 | }
57 | }
58 |
59 | @Override
60 | Set expand(T elem) {
61 | return new Set8(this, elem);
62 | }
63 |
64 | @Override
65 | int contractThreshold() {
66 | return 4;
67 | }
68 |
69 | @Override
70 | Set contract() {
71 | return new Set4(this);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/Set8.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class Set8 extends PrimitiveSet implements Set {
4 | T elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7;
5 |
6 | public Set8(Set6 oldSet, T elem) {
7 | this.elem0 = oldSet.elem0;
8 | this.elem1 = oldSet.elem1;
9 | this.elem2 = oldSet.elem2;
10 | this.elem3 = oldSet.elem3;
11 | this.elem4 = oldSet.elem4;
12 | this.elem5 = oldSet.elem5;
13 | this.elem6 = elem;
14 | }
15 |
16 | public Set8(Set12 oldSet) {
17 | this.elem0 = oldSet.elem0;
18 | this.elem1 = oldSet.elem1;
19 | this.elem2 = oldSet.elem2;
20 | this.elem3 = oldSet.elem3;
21 | this.elem4 = oldSet.elem4;
22 | this.elem5 = oldSet.elem5;
23 | this.elem6 = oldSet.elem6;
24 | this.elem7 = oldSet.elem7;
25 | }
26 |
27 | @Override
28 | public Object[] elements() {
29 | return new Object[] {elem0, elem1, elem2, elem3, elem4, elem5, elem6, elem7};
30 | }
31 |
32 | protected void write(int index, T elem) {
33 | if (index < 4) {
34 | switch (index) {
35 | case 0:
36 | this.elem0 = elem;
37 | break;
38 |
39 | case 1:
40 | this.elem1 = elem;
41 | break;
42 |
43 | case 2:
44 | this.elem2 = elem;
45 | break;
46 |
47 | case 3:
48 | this.elem3 = elem;
49 | break;
50 |
51 | default:
52 | throw new RuntimeException("Bug in code");
53 | }
54 | } else {
55 | switch (index) {
56 | case 4:
57 | this.elem4 = elem;
58 | break;
59 |
60 | case 5:
61 | this.elem5 = elem;
62 | break;
63 |
64 | case 6:
65 | this.elem6 = elem;
66 | break;
67 |
68 | case 7:
69 | this.elem7 = elem;
70 | break;
71 |
72 | default:
73 | throw new IllegalArgumentException("Invalid index " + index);
74 | }
75 | }
76 | }
77 |
78 | @Override
79 | Set expand(T elem) {
80 | return new Set12(this, elem);
81 | }
82 |
83 | @Override
84 | int contractThreshold() {
85 | return 6;
86 | }
87 |
88 | @Override
89 | Set contract() {
90 | return new Set6(this);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/ads/set/SetMax.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.ads.set;
2 |
3 | public class SetMax implements Set {
4 | private static final long serialVersionUID = 129583038274146507L;
5 |
6 | private static final ClassifierGetter identityClassifer = new ClassifierGetter() {
7 | @Override
8 | public Object getClassifier(Object obj) {
9 | return obj;
10 | }
11 | };
12 |
13 | int size;
14 | CompactMultiSetMax hashSet;
15 |
16 | public SetMax(Set24 oldSet, Object elem) {
17 | // When using a compact multi-set inside a set, it is better to use
18 | // safe-mode to avoid a cyclic dependency when all hash-codes are same
19 | hashSet = new CompactMultiSetMax(32, true);
20 |
21 | Object[] elems = oldSet.getElements();
22 | for (int i = 0; i < elems.length; i++) {
23 | T curElem = (T) elems[i];
24 | hashSet.addElementNoRehash(curElem.hashCode(), curElem);
25 | }
26 |
27 | T curElem = (T) elem;
28 | hashSet.addElementNoRehash(curElem.hashCode(), curElem);
29 |
30 | this.size = 1 + elems.length;
31 |
32 | assert (this.size == 25);
33 | }
34 |
35 | @Override
36 | public int size() {
37 | // Expensive operation -- could be inaccurate for lock-free reads
38 | // Doesn't matter because the read will retry
39 | return getElements().length;
40 | }
41 |
42 | @Override
43 | public Object[] getElements() {
44 | return hashSet.getAllElements();
45 | }
46 |
47 | @Override
48 | public Set removeElement(T elem) {
49 | if (hashSet.elements.length <= 32) {
50 | // Don't resize under 32 -- Better to move to Set24
51 | hashSet.removeElementNoHash(elem.hashCode(), elem);
52 | } else {
53 | // Resize is OK
54 | hashSet = hashSet.remove(elem, identityClassifer);
55 | }
56 |
57 | // The first check increases the chance of the second (more expensive one) succeeding
58 | if ((hashSet.getOccupiedCells() <= 13) && (size() <= 24)) {
59 | // The new size is at or below 24
60 | return new Set24(getElements());
61 | } else {
62 | return this;
63 | }
64 | }
65 |
66 | @Override
67 | public Set addElement(T elem) {
68 | // Resize is OK on add
69 | hashSet = hashSet.add(elem, identityClassifer);
70 |
71 | return this;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/gremlin/BitsyTraversalStrategy.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.gremlin;
2 |
3 | import org.apache.tinkerpop.gremlin.process.traversal.Step;
4 | import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
5 | import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
6 | import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
7 | import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
8 | import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
9 | import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
10 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
11 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
12 | import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
13 |
14 | // Bitsy traversal strategy based Tinkerpop's Neo4j implementation
15 | public class BitsyTraversalStrategy extends AbstractTraversalStrategy
16 | implements TraversalStrategy.ProviderOptimizationStrategy {
17 | private static final long serialVersionUID = 6405194525894707932L;
18 | private static final BitsyTraversalStrategy INSTANCE = new BitsyTraversalStrategy();
19 |
20 | private BitsyTraversalStrategy() {}
21 |
22 | @Override
23 | public void apply(final Traversal.Admin, ?> traversal) {
24 | for (final GraphStep originalGraphStep : TraversalHelper.getStepsOfClass(GraphStep.class, traversal)) {
25 | final BitsyGraphStep, ?> bitsyGraphStep = new BitsyGraphStep<>(originalGraphStep);
26 | TraversalHelper.replaceStep(originalGraphStep, bitsyGraphStep, traversal);
27 | Step, ?> currentStep = bitsyGraphStep.getNextStep();
28 | while (currentStep instanceof HasStep || currentStep instanceof NoOpBarrierStep) {
29 | if (currentStep instanceof HasStep) {
30 | for (final HasContainer hasContainer : ((HasContainerHolder) currentStep).getHasContainers()) {
31 | if (!GraphStep.processHasContainerIds(bitsyGraphStep, hasContainer))
32 | bitsyGraphStep.addHasContainer(hasContainer);
33 | }
34 | TraversalHelper.copyLabels(currentStep, currentStep.getPreviousStep(), false);
35 | traversal.removeStep(currentStep);
36 | }
37 | currentStep = currentStep.getNextStep();
38 | }
39 | }
40 | }
41 |
42 | public static BitsyTraversalStrategy instance() {
43 | return INSTANCE;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/lambdazen/bitsy/index/BitsyIndex.java:
--------------------------------------------------------------------------------
1 | package com.lambdazen.bitsy.index;
2 |
3 | import com.lambdazen.bitsy.ads.set.CompactSet;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.Iterator;
7 | import java.util.List;
8 | import java.util.Map;
9 | import java.util.concurrent.ConcurrentHashMap;
10 |
11 | public abstract class BitsyIndex {
12 | Map