diff --git a/janusgraph-core/src/main/java/org/janusgraph/core/JanusGraphTransaction.java b/janusgraph-core/src/main/java/org/janusgraph/core/JanusGraphTransaction.java index e080314c63..1c8f8f71de 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/core/JanusGraphTransaction.java +++ b/janusgraph-core/src/main/java/org/janusgraph/core/JanusGraphTransaction.java @@ -49,9 +49,13 @@ public interface JanusGraphTransaction extends Transaction { * Note, that an exception is thrown if the vertex id is not a valid JanusGraph vertex id or if a vertex with the given * id already exists. *

- * Custom id setting must be enabled via the configuration option {@link org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration#ALLOW_SETTING_VERTEX_ID}. - *

- * Use {@link org.janusgraph.core.util.JanusGraphId#toVertexId(long)} to construct a valid JanusGraph vertex id from a user id. + * Custom id setting must be enabled via the configuration option {@link org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration#ALLOW_SETTING_VERTEX_ID} + * and valid JanusGraph vertex ids must be provided. Use {@link org.janusgraph.graphdb.idmanagement.IDManager#toVertexId(long)} + * to construct a valid JanusGraph vertex id from a user id, where idManager can be obtained through + * {@link org.janusgraph.graphdb.database.StandardJanusGraph#getIDManager()}. + *

+     * long vertexId = ((StandardJanusGraph) graph).getIDManager().toVertexId(userVertexId);
+     * 
* * @param id vertex id of the vertex to be created * @param vertexLabel vertex label for this vertex - can be null if no vertex label should be set. diff --git a/janusgraph-core/src/main/java/org/janusgraph/core/util/JanusGraphId.java b/janusgraph-core/src/main/java/org/janusgraph/core/util/JanusGraphId.java index a9a9131922..61d7364060 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/core/util/JanusGraphId.java +++ b/janusgraph-core/src/main/java/org/janusgraph/core/util/JanusGraphId.java @@ -22,7 +22,17 @@ * Utility methods for handling JanusGraph ids and converting them between indexing and storage backend representations. * * @author Matthias Broecheler (me@matthiasb.com) + * @deprecated This class does not produce valid JanusGraph vertex ids as it does not take into account partitioning + * bits used in vertex id assignment. Use {@link org.janusgraph.graphdb.idmanagement.IDManager}, which can be obtained + * through {@link org.janusgraph.graphdb.database.StandardJanusGraph#getIDManager()} and includes methods for converting + * a user id to ({@link org.janusgraph.graphdb.idmanagement.IDManager#toVertexId(long)}) and from + * ({@link org.janusgraph.graphdb.idmanagement.IDManager#fromVertexId(long)}) JanusGraph vertex id. + *

+ *

+ * IDManager idManager = ((StandardJanusGraph) graph).getIDManager();
+ * 
*/ +@Deprecated public class JanusGraphId { /** @@ -31,6 +41,7 @@ public class JanusGraphId { * * @param id long id * @return a corresponding JanusGraph vertex id + * @deprecated Use {@link org.janusgraph.graphdb.idmanagement.IDManager#toVertexId(long)}. */ public static final long toVertexId(long id) { Preconditions.checkArgument(id > 0, "Vertex id must be positive: %s", id); @@ -43,6 +54,7 @@ public static final long toVertexId(long id) { * * @param id JanusGraph vertex id (must be positive) * @return original user provided id + * @deprecated Use {@link org.janusgraph.graphdb.idmanagement.IDManager#fromVertexId(long)} */ public static final long fromVertexId(long id) { Preconditions.checkArgument(id > 0, "Invalid vertex id provided: %s", id); @@ -54,6 +66,7 @@ public static final long fromVertexId(long id) { * * @param v Vertex * @return original user provided id + * @deprecated Use {@link org.janusgraph.graphdb.idmanagement.IDManager#fromVertexId(long)} */ public static final long fromVertexID(JanusGraphVertex v) { Preconditions.checkArgument(v.hasId(), "Invalid vertex provided: %s", v); diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/idmanagement/IDManager.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/idmanagement/IDManager.java index 6f486fec32..afdd74f85a 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/idmanagement/IDManager.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/idmanagement/IDManager.java @@ -567,6 +567,33 @@ public long[] getPartitionedVertexRepresentatives(long partitionedVertexId) { return ids; } + /** + * Converts a user provided long id into a JanusGraph vertex id. The id must be positive and less than {@link #getVertexCountBound()}. + * This method is useful when providing ids during vertex creation via {@link org.apache.tinkerpop.gremlin.structure.Graph#addVertex(Object...)}. + * + * @param id long id + * @return a corresponding JanusGraph vertex id + * @see #fromVertexId(long) + */ + public long toVertexId(long id) { + Preconditions.checkArgument(id > 0, "Vertex id must be positive: %s", id); + Preconditions.checkArgument(vertexCountBound > id, "Vertex id is too large: %s", id); + return id<<(partitionBits+USERVERTEX_PADDING_BITWIDTH); + } + + /** + * Converts a JanusGraph vertex id to the user provided id as the inverse mapping of {@link #toVertexId(long)}. + * + * @param id JanusGraph vertex id (must be positive) + * @return original user provided id + * @see #toVertexId(long) + */ + public long fromVertexId(long id) { + Preconditions.checkArgument(id >>> USERVERTEX_PADDING_BITWIDTH+partitionBits > 0 + && id <= (vertexCountBound-1)<>USERVERTEX_PADDING_BITWIDTH+partitionBits; + } + public boolean isPartitionedVertex(long id) { return isUserVertexId(id) && VertexIDType.PartitionedVertex.is(id); } diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/JanusGraphBlueprintsTransaction.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/JanusGraphBlueprintsTransaction.java index bd1a4808fe..096f8720cf 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/JanusGraphBlueprintsTransaction.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/JanusGraphBlueprintsTransaction.java @@ -90,9 +90,13 @@ public FulgoraGraphComputer compute() throws IllegalArgumentException { * Note, that an exception is thrown if the vertex id is not a valid JanusGraph vertex id or if a vertex with the given * id already exists. Only accepts long ids - all others are ignored. *

- * Custom id setting must be enabled via the configuration option {@link org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration#ALLOW_SETTING_VERTEX_ID}. - *

- * Use {@link org.janusgraph.core.util.JanusGraphId#toVertexId(long)} to construct a valid JanusGraph vertex id from a user id. + * Custom id setting must be enabled via the configuration option {@link org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration#ALLOW_SETTING_VERTEX_ID} + * and valid JanusGraph vertex ids must be provided. Use {@link org.janusgraph.graphdb.idmanagement.IDManager#toVertexId(long)} + * to construct a valid JanusGraph vertex id from a user id, where idManager can be obtained through + * {@link org.janusgraph.graphdb.database.StandardJanusGraph#getIDManager()}. + *

+     * long vertexId = ((StandardJanusGraph) graph).getIDManager().toVertexId(userVertexId);
+     * 
* * @param keyValues key-value pairs of properties to characterize or attach to the vertex * @return New vertex @@ -115,11 +119,8 @@ public JanusGraphVertex addVertex(Object... keyValues) { label = (labelValue instanceof VertexLabel)?(VertexLabel)labelValue:getOrCreateVertexLabel((String) labelValue); } - final JanusGraphVertex vertex = addVertex(ElementHelper.getIdValue(keyValues).orElse(null), label); -// for (int i = 0; i < keyValues.length; i = i + 2) { -// if (!keyValues[i].equals(T.id) && !keyValues[i].equals(T.label)) -// ((StandardJanusGraphTx)this).addPropertyInternal(vertex,getOrCreatePropertyKey((String) keyValues[i]),keyValues[i+1]); -// } + final Long id = ElementHelper.getIdValue(keyValues).map(Number.class::cast).map(Number::longValue).orElse(null); + final JanusGraphVertex vertex = addVertex(id, label); org.janusgraph.graphdb.util.ElementHelper.attachProperties(vertex, keyValues); return vertex; } diff --git a/janusgraph-test/src/test/java/org/janusgraph/graphdb/idmanagement/VertexIDAssignerTest.java b/janusgraph-test/src/test/java/org/janusgraph/graphdb/idmanagement/VertexIDAssignerTest.java index 4b68748291..5fdf751299 100644 --- a/janusgraph-test/src/test/java/org/janusgraph/graphdb/idmanagement/VertexIDAssignerTest.java +++ b/janusgraph-test/src/test/java/org/janusgraph/graphdb/idmanagement/VertexIDAssignerTest.java @@ -16,6 +16,7 @@ import com.carrotsearch.hppc.LongHashSet; import com.carrotsearch.hppc.LongSet; +import org.apache.tinkerpop.gremlin.structure.T; import org.janusgraph.core.JanusGraphFactory; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphVertex; @@ -68,6 +69,12 @@ public static Collection configs() { private final long maxIDAssignments; + private final long numPartitionsBits; + + private enum CustomIdStrategy { + LOW, + HIGH + } /** * @@ -97,13 +104,17 @@ public VertexIDAssignerTest(int numPartitionsBits, int partitionMax, int[] local } else { this.maxIDAssignments = (1< vertices = new ArrayList(numVertices); List relations = new ArrayList(); @@ -171,5 +182,70 @@ public void testIDAssignment() { } } + @Test + public void testCustomIdAssignment() { + testCustomIdAssignment(CustomIdStrategy.LOW); + testCustomIdAssignment(CustomIdStrategy.HIGH); + + final IDManager idManager = idAssigner.getIDManager(); + for (final long id : new long[] {0, idManager.getVertexCountBound()}) { + try { + idManager.toVertexId(id); + fail("Should fail to convert out of range user id to graph vertex id"); + } catch (IllegalArgumentException e) { + // should throw this exception + } + } + + for (final long vertexId : new long[] {idManager.toVertexId(1)-1, idManager.toVertexId(idManager.getVertexCountBound()-1)+1}) { + try { + idManager.fromVertexId(vertexId); + fail("Should fail to convert out of range vertex id to user id"); + } catch (IllegalArgumentException e) { + // should throw this exception + } + } + } + + private void testCustomIdAssignment(CustomIdStrategy idStrategy) { + LongSet vertexIds = new LongHashSet(); + final long maxCount = idAssigner.getIDManager().getVertexCountBound(); + long count = 1; + for (int trial = 0; trial < 10; trial++) { + JanusGraph graph = getInMemoryGraph(true, true); + int numVertices = 1000; + List vertices = new ArrayList(numVertices); + try { + for (int i = 0; i < numVertices; i++, count++) { + final long userVertexId; + switch (idStrategy) { + case LOW: + userVertexId = count; + break; + case HIGH: + userVertexId = maxCount-count; + break; + default: + throw new RuntimeException("Unsupported custom id strategy: " + idStrategy); + } + final long id = idAssigner.getIDManager().toVertexId(userVertexId); + JanusGraphVertex next = graph.addVertex(T.id, id, "user_id", userVertexId); + vertices.add(next); + } + + //Verify that ids are set, unique and consistent with user id basis + for (JanusGraphVertex v : vertices) { + assertTrue(v.hasId()); + long id = v.longId(); + assertTrue(id>0 && id