[ 
https://issues.apache.org/jira/browse/TINKERPOP-3261?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18094655#comment-18094655
 ] 

ASF GitHub Bot commented on TINKERPOP-3261:
-------------------------------------------

spmallette commented on code in PR #3483:
URL: https://github.com/apache/tinkerpop/pull/3483#discussion_r3546304062


##########
tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java:
##########
@@ -54,31 +57,150 @@ public class TinkerVertex extends TinkerElement implements 
Vertex {
     private boolean allowNullPropertyValues;
     private final boolean isTxMode;
 
+    /**
+     * Multi-label storage for this vertex. Starts as an immutable set 
(lightweight) and is
+     * upgraded to a mutable ConcurrentHashMap-backed set on first label 
mutation.
+     */
+    protected Set<String> vertexLabels;
+
     protected TinkerVertex(final Object id, final String label, final 
AbstractTinkerGraph graph) {
-        super(id, label);
-        this.graph = graph;
-        this.isTxMode = graph instanceof TinkerTransactionGraph;
-        this.allowNullPropertyValues = 
graph.features().vertex().supportsNullPropertyValues();
+        this(id, Collections.singleton(label != null ? label : 
Vertex.DEFAULT_LABEL), graph, -1);
     }
 
     protected TinkerVertex(final Object id, final String label, final 
AbstractTinkerGraph graph, final long currentVersion) {
-        super(id, label, currentVersion);
+        this(id, Collections.singleton(label != null ? label : 
Vertex.DEFAULT_LABEL), graph, currentVersion);
+    }
+
+    /**
+     * Constructs a TinkerVertex with multiple labels.
+     */
+    protected TinkerVertex(final Object id, final Set<String> labels, final 
AbstractTinkerGraph graph) {
+        this(id, labels, graph, -1);
+    }
+
+    /**
+     * Canonical constructor. Constructs a TinkerVertex with multiple labels 
and a specific version (for transactional graphs).
+     * Uses a single-switch pattern to handle default label injection per the 
configured cardinality.
+     */
+    protected TinkerVertex(final Object id, final Set<String> labels, final 
AbstractTinkerGraph graph, final long currentVersion) {
+        super(id, null, currentVersion);  // label field set below
         this.graph = graph;
         this.isTxMode = graph instanceof TinkerTransactionGraph;
         this.allowNullPropertyValues = 
graph.features().vertex().supportsNullPropertyValues();
+
+        // Build the initial label set. Use lightweight immutable sets when 
possible.
+        final Set<String> initial = new LinkedHashSet<>();
+        switch (graph.vertexLabelCardinality) {
+            case ONE:
+                // Exactly 1 label: use provided or default
+                if (labels != null && !labels.isEmpty())
+                    initial.addAll(labels);
+                else
+                    initial.add(graph.defaultVertexLabel);
+                break;
+            case ONE_OR_MORE:
+                // Default label always present alongside any user labels
+                initial.add(graph.defaultVertexLabel);
+                if (labels != null) initial.addAll(labels);
+                break;
+            case ZERO_OR_MORE:
+                if (labels != null) initial.addAll(labels);
+                break;
+        }
+
+        // Validate the resulting set conforms to cardinality
+        
LabelCardinalityValidator.validateCreation(graph.vertexLabelCardinality, 
initial);
+
+        // Store as immutable — will be upgraded on first mutation via 
ensureMutableLabels()
+        this.vertexLabels = initial.size() <= 1
+                ? (initial.isEmpty() ? Collections.emptySet() : 
Collections.singleton(initial.iterator().next()))
+                : Collections.unmodifiableSet(initial);
+
+        this.label = this.vertexLabels.isEmpty() ? "" : 
this.vertexLabels.iterator().next();
+    }
+
+    /**
+     * Upgrades the label set to a mutable ConcurrentHashMap-backed set on 
first mutation.
+     * This is a one-time cost per vertex that actually needs label mutation.
+     */
+    private void ensureMutableLabels() {
+        if (!(this.vertexLabels instanceof ConcurrentHashMap.KeySetView)) {
+            final Set<String> mutable = ConcurrentHashMap.newKeySet();
+            mutable.addAll(this.vertexLabels);
+            this.vertexLabels = mutable;
+        }
+    }
+
+    @Override
+    public Set<String> labels() {
+        if (this.vertexLabels.isEmpty()) {
+            return Collections.emptySet();
+        }
+        // If already immutable (pre-mutation), return directly. If mutable 
(post-mutation), wrap.
+        if (this.vertexLabels instanceof ConcurrentHashMap.KeySetView) {
+            return Collections.unmodifiableSet(this.vertexLabels);
+        }
+        return this.vertexLabels; // already immutable from construction
+    }
+
+    @Override
+    @Deprecated
+    public String label() {
+        if (this.vertexLabels.isEmpty()) {
+            return "";
+        }
+        return this.vertexLabels.iterator().next();
+    }
+
+    @Override
+    public void addLabel(final String label, final String... labels) {
+        ElementHelper.validateLabel(label);
+        for (final String l : labels) {
+            ElementHelper.validateLabel(l);
+        }
+        
LabelCardinalityValidator.validateAdd(this.graph.vertexLabelCardinality, 
this.vertexLabels, label, labels);
+        graph.touch(this);
+        ensureMutableLabels();
+        this.vertexLabels.add(label);
+        Collections.addAll(this.vertexLabels, labels);
+        this.label = this.vertexLabels.iterator().next();
+        this.graph.updateVertexLabelIndex(this);

Review Comment:
   we never update the `vertexLabelCounts` with this or with `dropLabels` 
below. 





> Enable multiple label support on vertex with configurable label cardinality
> ---------------------------------------------------------------------------
>
>                 Key: TINKERPOP-3261
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-3261
>             Project: TinkerPop
>          Issue Type: Task
>    Affects Versions: 4.0.0
>            Reporter: Yang Xia
>            Priority: Major
>
> Vertices are currently limited to a single immutable label assigned at 
> creation. This prevents modeling common real-world scenarios where entities 
> naturally belong to multiple categories (e.g., a person who is both an 
> employee and a manager).
>   
> Introduce a configurable LabelCardinality that controls how many labels a 
> vertex may have and whether they can be mutated after creation. Three 
> proposed modes: ONE (current behavior, default), ONE_OR_MORE (mutable, 
> minimum one), ZERO_OR_MORE (fully flexible).
>   
> New steps:
>   
> - labels() — flatMap step emitting each label as a traverser
> - addLabel(String, String...) — add labels to a vertex
> - dropLabel(String, String...) — remove specific labels
> - dropLabels() — remove all labels
> Edge labels remain at cardinality ONE. The infrastructure would support 
> future edge multi-label enablement without wire format changes.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to