Enhance SchemaGenerator to also generate indices for relationships 34/137334/3
authorFiete Ostkamp <Fiete.Ostkamp@telekom.de>
Wed, 21 Feb 2024 12:41:30 +0000 (13:41 +0100)
committerFiete Ostkamp <Fiete.Ostkamp@telekom.de>
Wed, 21 Feb 2024 14:06:36 +0000 (15:06 +0100)
- generate edge indexes when they not already exist
- reindex existing indexes when they are not in status ENABLED
- try to recover indexes that are in INSTALLED state
- bump version to 1.13.5

Issue-ID: AAI-3782
Change-Id: I127e0f83b17485d7a6721206ade92cd50c89a51b
Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
21 files changed:
.gitignore
aai-aaf-auth/pom.xml
aai-annotations/pom.xml
aai-auth/pom.xml
aai-common-docker/aai-common-images/pom.xml
aai-common-docker/aai-haproxy-image/pom.xml
aai-common-docker/pom.xml
aai-core/pom.xml
aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator.java
aai-core/src/main/java/org/onap/aai/dbmap/AAIGraph.java
aai-core/src/main/java/org/onap/aai/dbmap/InMemoryGraph.java
aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceWithSoTTest.java
aai-els-onap-logging/pom.xml
aai-failover/pom.xml
aai-parent/pom.xml
aai-rest/pom.xml
aai-schema-abstraction/pom.xml
aai-schema-ingest/pom.xml
aai-utils/pom.xml
pom.xml
version.properties

index baf2967..413c5b3 100644 (file)
@@ -15,4 +15,5 @@ bundleconfig-local/etc/logback.xml
 .vscode/
 .devcontainer/
 *.log
-aai-core/logs/
\ No newline at end of file
+aai-core/logs/
+.classpath
\ No newline at end of file
index 9e69e60..12ca1b7 100644 (file)
@@ -6,7 +6,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-aaf-auth</artifactId>
index 60fa4eb..e8ef692 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-annotations</artifactId>
index 3922d6c..ac251a4 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-auth</artifactId>
index 4cb9365..e15c6f2 100644 (file)
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-common-docker</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>aai-common-images</artifactId>
-    <version>1.13.4-SNAPSHOT</version>
+    <version>1.13.5-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>aai-aai-common-images</name>
     <description>Contains dockerfiles for aai-common images (alpine and ubuntu based).</description>
index f77f4ef..c217230 100644 (file)
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-common-docker</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>aai-haproxy-image</artifactId>
-    <version>1.13.4-SNAPSHOT</version>
+    <version>1.13.5-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>aai-aai-haproxy-image</name>
     <description>Contains dockerfiles for aai-haproxy image.</description>
index e0e29fe..80d7ece 100644 (file)
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
 
index 348d4eb..fb64669 100644 (file)
@@ -26,7 +26,7 @@ limitations under the License.
        <parent>
                <groupId>org.onap.aai.aai-common</groupId>
                <artifactId>aai-parent</artifactId>
-               <version>1.13.4-SNAPSHOT</version>
+               <version>1.13.5-SNAPSHOT</version>
                <relativePath>../aai-parent/pom.xml</relativePath>
        </parent>
        <artifactId>aai-core</artifactId>
index 250c126..6430df5 100644 (file)
@@ -4,6 +4,8 @@
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
+ * Modifications Copyright © 2024 DEUTSCHE TELEKOM AG.
+ * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -22,21 +24,38 @@ package org.onap.aai.dbgen;
 
 import com.google.common.collect.Multimap;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.janusgraph.core.Cardinality;
+import org.janusgraph.core.EdgeLabel;
+import org.janusgraph.core.JanusGraph;
 import org.janusgraph.core.Multiplicity;
 import org.janusgraph.core.PropertyKey;
 import org.janusgraph.core.schema.ConsistencyModifier;
 import org.janusgraph.core.schema.JanusGraphIndex;
 import org.janusgraph.core.schema.JanusGraphManagement;
+import org.janusgraph.core.schema.JanusGraphManagement.IndexJobFuture;
+import org.janusgraph.core.schema.RelationTypeIndex;
+import org.janusgraph.core.schema.SchemaAction;
+import org.janusgraph.core.schema.SchemaStatus;
+import org.janusgraph.graphdb.database.StandardJanusGraph;
+import org.janusgraph.graphdb.database.management.ManagementSystem;
+import org.janusgraph.graphdb.database.management.RelationIndexStatusReport;
 import org.onap.aai.config.SpringContextAware;
 import org.onap.aai.edges.EdgeIngestor;
 import org.onap.aai.edges.EdgeRule;
@@ -53,6 +72,7 @@ import org.slf4j.LoggerFactory;
 public class SchemaGenerator {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SchemaGenerator.class);
+    private static int indexRecoveryRetryCounter = 0;
 
     private SchemaGenerator() {
     }
@@ -63,7 +83,9 @@ public class SchemaGenerator {
      * @param graphMgmt
      *        the graph mgmt
      */
-    public static void loadSchemaIntoJanusGraph(final JanusGraphManagement graphMgmt, String backend) {
+    public static List<String> loadSchemaIntoJanusGraph(final JanusGraph graph, String backend, boolean dbNotEmpty) {
+        JanusGraphManagement graphMgmt = graph.openManagement();
+        final List<String> elementsToReindex = new ArrayList<>();
 
         try {
             AAIConfig.init();
@@ -85,121 +107,342 @@ public class SchemaGenerator {
         // multiplicty definitions depends on which two types of nodes are being
         // connected.
 
-        makeEdgeLabels(graphMgmt);
+        final Map<String, Introspector> objs = LoaderUtil.getLatestVersion().getAllObjects();
+        final Map<String, PropertyKey> seenProps = new HashMap<>();
+        
+        for (Introspector obj : objs.values()) {
+            createSchemaForObject(graphMgmt, seenProps, obj);
+        }
 
-        Map<String, Introspector> objs = LoaderUtil.getLatestVersion().getAllObjects();
-        Map<String, PropertyKey> seenProps = new HashMap<>();
+        makeEdgeLabels(graphMgmt, elementsToReindex, dbNotEmpty);
 
-        for (Introspector obj : objs.values()) {
-            for (String propName : obj.getProperties()) {
-                String dbPropName = propName;
-                Optional<String> alias = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS);
-                if (alias.isPresent()) {
-                    dbPropName = alias.get();
+        LOGGER.info("-- About to call graphMgmt commit");
+        if (backend != null) {
+            LOGGER.info("Successfully loaded the schema to {}", backend);
+        }
+
+        graphMgmt.commit();
+        return elementsToReindex;
+    }
+
+    public static void reindexEdgeIndexes(final JanusGraph graph, Collection<String> edgeLabels) {
+        graph.tx().rollback();
+        if(edgeLabels.isEmpty()) {
+            LOGGER.info("Nothing to reindex.");
+            return;
+        }
+
+        ensureValidIndexState(graph, edgeLabels);
+
+        awaitRelationIndexStatus(graph, edgeLabels,SchemaStatus.REGISTERED);
+
+        LOGGER.info("Attempting to transition indexes in REGISTERED state to ENABLED");
+        updateRelationIndexes(graph, edgeLabels, SchemaAction.REINDEX);
+
+        ensureEnabledIndexState(graph, edgeLabels);
+    }
+
+    /**
+     * Indices need to be in status REGISTERED or ENABLED to allow reindexing.
+     * @param graph
+     * @param edgeLabels
+     */
+    private static void ensureEnabledIndexState(final JanusGraph graph, Collection<String> edgeLabels) {
+        JanusGraphManagement graphMgmt = graph.openManagement();
+        List<String> registeredIndexes = new ArrayList<>();
+        for(String label: edgeLabels) {
+            EdgeLabel relation = graphMgmt.getEdgeLabel(label);
+            RelationTypeIndex index = graphMgmt.getRelationIndex(relation, label);
+            SchemaStatus indexStatus = index.getIndexStatus();
+            if(indexStatus.equals(SchemaStatus.REGISTERED)) {
+                LOGGER.info("Detected relation index [{}] that is not yet in ENABLED state", relation.name());
+                registeredIndexes.add(label);
+            }
+        }
+        graphMgmt.commit();
+
+        if(indexRecoveryRetryCounter <= 8 && !registeredIndexes.isEmpty()) {
+            indexRecoveryRetryCounter++;
+            LOGGER.info("[{}] indexes not yet in ENABLED state", registeredIndexes.size());
+            awaitRelationIndexStatus(graph, registeredIndexes,SchemaStatus.ENABLED);
+
+            ensureEnabledIndexState(graph, edgeLabels); // recursively call to make sure there is no invalid state
+        } else {
+            LOGGER.info("All indexes are in ENABLED state, exiting.");
+            return;
+        }
+    }
+
+    /**
+     * Indices need to be in status REGISTERED or ENABLED to allow reindexing.
+     * @param graph
+     * @param edgeLabels
+     */
+    private static void ensureValidIndexState(final JanusGraph graph, Collection<String> edgeLabels) {
+        JanusGraphManagement graphMgmt = graph.openManagement();
+        List<String> installedIndexes = new ArrayList<>();
+        List<String> disabledIndexes = new ArrayList<>();
+        for(String label: edgeLabels) {
+            EdgeLabel relation = graphMgmt.getEdgeLabel(label);
+            RelationTypeIndex index = graphMgmt.getRelationIndex(relation, label);
+            SchemaStatus indexStatus = index.getIndexStatus();
+            if(indexStatus.equals(SchemaStatus.INSTALLED)) {
+                LOGGER.info("Detected relation index [{}] with invalid status [{}]", relation.name(), indexStatus);
+                installedIndexes.add(label);
+            } else if(indexStatus.equals(SchemaStatus.DISABLED)) {
+                LOGGER.info("Detected relation index [{}] with invalid status [{}]", relation.name(), indexStatus);
+                disabledIndexes.add(label);
+            }
+        }
+        graphMgmt.commit();
+
+        if(indexRecoveryRetryCounter <= 300 && (!installedIndexes.isEmpty() || !disabledIndexes.isEmpty())) {
+            indexRecoveryRetryCounter++;
+            if(!installedIndexes.isEmpty()) {
+                LOGGER.info("Attempting to transition indexes in INSTALLED state to REGISTERED");
+                updateRelationIndexes(graph, installedIndexes, SchemaAction.REGISTER_INDEX);
+                awaitRelationIndexStatus(graph, edgeLabels,SchemaStatus.REGISTERED);
+            }
+            if(!disabledIndexes.isEmpty()) {
+                LOGGER.info("Attempting to transition indexes in DISABLED state to ENABLED");
+                updateRelationIndexes(graph, disabledIndexes, SchemaAction.ENABLE_INDEX);
+                awaitRelationIndexStatus(graph, edgeLabels,SchemaStatus.ENABLED);
+            }
+            ensureValidIndexState(graph, edgeLabels); // recursively call to make sure there is no invalid state
+        } else {
+            return;
+        }
+    }
+
+    private static void createSchemaForObject(final JanusGraphManagement graphMgmt, Map<String, PropertyKey> seenProps,
+            Introspector obj) {
+        for (String propName : obj.getProperties()) {
+            String dbPropName = propName;
+            Optional<String> alias = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS);
+            if (alias.isPresent()) {
+                dbPropName = alias.get();
+            }
+            if (graphMgmt.containsRelationType(dbPropName)) {
+                LOGGER.debug(" PropertyKey  [{}] already existed in the DB. ", dbPropName);
+            } else {
+                Class<?> type = obj.getClass(propName);
+                Cardinality cardinality = Cardinality.SINGLE;
+                boolean process = false;
+                if (obj.isListType(propName) && obj.isSimpleGenericType(propName)) {
+                    cardinality = Cardinality.SET;
+                    type = obj.getGenericTypeClass(propName);
+                    process = true;
+                } else if (obj.isSimpleType(propName)) {
+                    process = true;
                 }
-                if (graphMgmt.containsRelationType(dbPropName)) {
-                    LOGGER.debug(" PropertyKey  [{}] already existed in the DB. ", dbPropName);
-                } else {
-                    Class<?> type = obj.getClass(propName);
-                    Cardinality cardinality = Cardinality.SINGLE;
-                    boolean process = false;
-                    if (obj.isListType(propName) && obj.isSimpleGenericType(propName)) {
-                        cardinality = Cardinality.SET;
-                        type = obj.getGenericTypeClass(propName);
-                        process = true;
-                    } else if (obj.isSimpleType(propName)) {
-                        process = true;
-                    }
 
-                    if (process) {
-
-                        LOGGER.info("Creating PropertyKey: [{}], [{}], [{}]", dbPropName, type.getSimpleName(),
-                                cardinality);
-                        PropertyKey propK;
-                        if (!seenProps.containsKey(dbPropName)) {
-                            propK = graphMgmt.makePropertyKey(dbPropName).dataType(type).cardinality(cardinality)
-                                    .make();
-                            if (dbPropName.equals("aai-uri")) {
-                                String aai_uri_lock_enabled = AAIConfig.get(AAIConstants.AAI_LOCK_URI_ENABLED, "false");
-                                LOGGER.info(" Info: aai_uri_lock_enabled:" + aai_uri_lock_enabled);
-                                if ("true".equals(aai_uri_lock_enabled)) {
-                                    LOGGER.info(" Lock is being set for aai-uri Property.");
-                                    graphMgmt.setConsistency(propK, ConsistencyModifier.LOCK);
-                                }
-                            } else if (dbPropName.equals("resource-version")) {
-                                String aai_rv_lock_enabled = AAIConfig.get(AAIConstants.AAI_LOCK_RV_ENABLED, "false");
-                                LOGGER.info(" Info: aai_rv_lock_enabled:" + aai_rv_lock_enabled);
-                                if ("true".equals(aai_rv_lock_enabled)) {
-                                    LOGGER.info(" Lock is being set for resource-version Property.");
-                                    graphMgmt.setConsistency(propK, ConsistencyModifier.LOCK);
-                                }
+                if (process) {
+
+                    LOGGER.info("Creating PropertyKey: [{}], [{}], [{}]", dbPropName, type.getSimpleName(),
+                            cardinality);
+                    PropertyKey propertyKey;
+                    if (!seenProps.containsKey(dbPropName)) {
+                        propertyKey = graphMgmt.makePropertyKey(dbPropName).dataType(type).cardinality(cardinality)
+                                .make();
+                        if (dbPropName.equals("aai-uri")) {
+                            String aai_uri_lock_enabled = AAIConfig.get(AAIConstants.AAI_LOCK_URI_ENABLED, "false");
+                            LOGGER.info(" Info: aai_uri_lock_enabled:" + aai_uri_lock_enabled);
+                            if ("true".equals(aai_uri_lock_enabled)) {
+                                LOGGER.info(" Lock is being set for aai-uri Property.");
+                                graphMgmt.setConsistency(propertyKey, ConsistencyModifier.LOCK);
+                            }
+                        } else if (dbPropName.equals("resource-version")) {
+                            String aai_rv_lock_enabled = AAIConfig.get(AAIConstants.AAI_LOCK_RV_ENABLED, "false");
+                            LOGGER.info(" Info: aai_rv_lock_enabled:" + aai_rv_lock_enabled);
+                            if ("true".equals(aai_rv_lock_enabled)) {
+                                LOGGER.info(" Lock is being set for resource-version Property.");
+                                graphMgmt.setConsistency(propertyKey, ConsistencyModifier.LOCK);
                             }
-                            seenProps.put(dbPropName, propK);
-                        } else {
-                            propK = seenProps.get(dbPropName);
                         }
-                        if (graphMgmt.containsGraphIndex(dbPropName)) {
-                            LOGGER.debug(" Index  [{}] already existed in the DB. ", dbPropName);
+                        seenProps.put(dbPropName, propertyKey);
+                    } else {
+                        propertyKey = seenProps.get(dbPropName);
+                    }
+                    if (graphMgmt.containsGraphIndex(dbPropName)) {
+                        LOGGER.debug(" Index  [{}] already existed in the DB. ", dbPropName);
+                    } else {
+                        if (obj.getIndexedProperties().contains(propName)) {
+                            createIndexForProperty(graphMgmt, obj, propName, dbPropName, propertyKey);
                         } else {
-                            if (obj.getIndexedProperties().contains(propName)) {
-                                JanusGraphIndex indexG = null;
-                                if (obj.getUniqueProperties().contains(propName)) {
-                                    LOGGER.info("Add Unique index for PropertyKey: [{}]", dbPropName);
-                                    indexG = graphMgmt.buildIndex(dbPropName, Vertex.class).addKey(propK).unique()
-                                            .buildCompositeIndex();
-                                } else {
-                                    LOGGER.info("Add index for PropertyKey: [{}]", dbPropName);
-                                    indexG = graphMgmt.buildIndex(dbPropName, Vertex.class).addKey(propK)
-                                            .buildCompositeIndex();
-                                }
-                                if (indexG != null && dbPropName.equals("aai-uri")) {
-                                    String aai_uri_lock_enabled =
-                                            AAIConfig.get(AAIConstants.AAI_LOCK_URI_ENABLED, "false");
-                                    LOGGER.info(" Info:: aai_uri_lock_enabled:" + aai_uri_lock_enabled);
-                                    if ("true".equals(aai_uri_lock_enabled)) {
-                                        LOGGER.info("Lock is being set for aai-uri Index.");
-                                        graphMgmt.setConsistency(indexG, ConsistencyModifier.LOCK);
-                                    }
-                                } else if (indexG != null && dbPropName.equals("resource-version")) {
-                                    String aai_rv_lock_enabled =
-                                            AAIConfig.get(AAIConstants.AAI_LOCK_RV_ENABLED, "false");
-                                    LOGGER.info(" Info:: aai_rv_lock_enabled:" + aai_rv_lock_enabled);
-                                    if ("true".equals(aai_rv_lock_enabled)) {
-                                        LOGGER.info("Lock is being set for resource-version Index.");
-                                        graphMgmt.setConsistency(indexG, ConsistencyModifier.LOCK);
-                                    }
-                                }
-                            } else {
-                                LOGGER.info("No index added for PropertyKey: [{}]", dbPropName);
-                            }
+                            LOGGER.info("No index added for PropertyKey: [{}]", dbPropName);
                         }
                     }
                 }
             }
         }
+    }
 
-        LOGGER.info("-- About to call graphMgmt commit");
-        if (backend != null) {
-            LOGGER.info("Successfully loaded the schema to {}", backend);
+    private static void createIndexForProperty(final JanusGraphManagement graphMgmt, Introspector obj, String propName,
+            String dbPropName, PropertyKey propertyKey) {
+        JanusGraphIndex indexG = null;
+        if (obj.getUniqueProperties().contains(propName)) {
+            LOGGER.info("Add Unique index for PropertyKey: [{}]", dbPropName);
+            indexG = graphMgmt.buildIndex(dbPropName, Vertex.class).addKey(propertyKey).unique()
+                    .buildCompositeIndex();
+        } else {
+            LOGGER.info("Add index for PropertyKey: [{}]", dbPropName);
+            indexG = graphMgmt.buildIndex(dbPropName, Vertex.class).addKey(propertyKey)
+                    .buildCompositeIndex();
+        }
+        if (indexG != null && dbPropName.equals("aai-uri")) {
+            String aai_uri_lock_enabled =
+                    AAIConfig.get(AAIConstants.AAI_LOCK_URI_ENABLED, "false");
+            LOGGER.info(" Info:: aai_uri_lock_enabled:" + aai_uri_lock_enabled);
+            if ("true".equals(aai_uri_lock_enabled)) {
+                LOGGER.info("Lock is being set for aai-uri Index.");
+                graphMgmt.setConsistency(indexG, ConsistencyModifier.LOCK);
+            }
+        } else if (indexG != null && dbPropName.equals("resource-version")) {
+            String aai_rv_lock_enabled =
+                    AAIConfig.get(AAIConstants.AAI_LOCK_RV_ENABLED, "false");
+            LOGGER.info(" Info:: aai_rv_lock_enabled:" + aai_rv_lock_enabled);
+            if ("true".equals(aai_rv_lock_enabled)) {
+                LOGGER.info("Lock is being set for resource-version Index.");
+                graphMgmt.setConsistency(indexG, ConsistencyModifier.LOCK);
+            }
+        }
+    }
+
+    /**
+     * Debug method to print current index states.
+     * This can help diagnosing indexes that are stuck in INSTALLED state.
+     * @param graph
+     */
+    public static void printCurrentRelationIndexStates(JanusGraph graph) {
+        JanusGraphManagement graphMgmt = graph.openManagement();
+        EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class);
+        try {
+            Set<String> edgeLabels = Optional.ofNullable(edgeIngestor.getAllCurrentRules())
+                        .map(collectValues(EdgeRule::getLabel)).orElseGet(HashSet::new);
+            edgeLabels.stream()
+                .forEach(label -> {
+                    EdgeLabel relation = graphMgmt.getEdgeLabel(label);
+                    RelationTypeIndex index = graphMgmt.getRelationIndex(relation, label);
+                    LOGGER.info("Index state of relation index [{}] is [{}]",label, index.getIndexStatus());
+                });
+        } catch (EdgeRuleNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Jointly wait for a set of relation indexes to change status.
+     * Use this after calling {@link JanusGraphManagement#updateIndex(org.janusgraph.core.schema.Index, SchemaAction)}
+     * @param graph the JanusGraph
+     * @param labels the names of the indexes
+     * @param newStatus the new SchemaStatus
+     */
+    private static void awaitRelationIndexStatus(JanusGraph graph, Collection<String> labels, SchemaStatus newStatus) {
+        LOGGER.info("Awaiting index status [{}]", newStatus);;
+        CompletableFuture<RelationIndexStatusReport>[] awaits = labels.stream()
+            .map(label -> 
+                CompletableFuture.supplyAsync(() -> {
+                    try {
+                        return ManagementSystem
+                            .awaitRelationIndexStatus(graph, label, label)
+                            .status(newStatus)
+                            .call();
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                        return null;
+                    }
+                }))
+            .toArray(CompletableFuture[]::new);
+        try {
+            CompletableFuture.allOf(awaits).get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.error("Error while waiting for change in relation index status");
+            e.printStackTrace();
         }
+        LOGGER.info("Completed waiting for index status [{}]", newStatus);
+    }
+
+    private static void updateRelationIndexes(JanusGraph graph, Collection<String> labels, SchemaAction updateAction) {
+        JanusGraphManagement graphMgmt = graph.openManagement();
 
+        CompletableFuture<IndexJobFuture>[] awaits = labels.stream()
+            .map(label -> 
+                CompletableFuture.supplyAsync(() -> {
+                    EdgeLabel relation = graphMgmt.getEdgeLabel(label);
+                    RelationTypeIndex index = graphMgmt.getRelationIndex(relation, label);
+                    LOGGER.info("Updating relation index [{}] status from [{}] to [{}]", relation.name(), index.getIndexStatus(), updateAction);
+                    return graphMgmt.updateIndex(index, updateAction);
+                }))
+            .toArray(CompletableFuture[]::new);
+        try {
+            CompletableFuture.allOf(awaits).get();
+            LOGGER.info("Completed reindex actions");
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.error("Error while waiting for change in relation index status");
+            e.printStackTrace();
+        }
         graphMgmt.commit();
     }
 
-    private static void makeEdgeLabels(JanusGraphManagement graphMgmt) {
+    /**
+     * Radical approach to avoiding index update failures.
+     * Indexes can get stuck in INSTALLED state, when there are stale transactions or JanusGraph instances.
+     * This is because a state change needs to be acknowledged by all instances before transitioning.
+     * @param graph
+     * @return
+     */
+    private static void killTransactionsAndInstances(JanusGraph graph) {
+        graph.tx().rollback();
+        final StandardJanusGraph janusGraph = (StandardJanusGraph) graph;
+        janusGraph.getOpenTransactions().stream().forEach(transaction -> {
+                LOGGER.debug("Closing open transaction [{}] before schema generation", transaction.toString());
+                transaction.rollback();
+        });
+        
+        final JanusGraphManagement graphMgtForClosing = graph.openManagement();
+
+        Set<String> instances = graphMgtForClosing.getOpenInstances();
+        LOGGER.info("Number of open instances: {}", instances.size());
+        LOGGER.info("Currently open instances: [{}]", instances);
+        instances.stream()
+            // .filter(instance -> !instance.contains("graphadmin"))
+            .filter(instance -> !instance.contains("(current)"))
+            .forEach(instance -> {
+                    LOGGER.debug("Closing open JanusGraph instance [{}] before reindexing procedure", instance);
+                    graphMgtForClosing.forceCloseInstance(instance);
+            });
+        graphMgtForClosing.commit();
+    }
+
+    private static void makeEdgeLabels(JanusGraphManagement graphMgmt, List<String> elementsToReindex, boolean dbNotEmpty) {
         try {
             EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class);
 
             Set<String> labels = Optional.ofNullable(edgeIngestor.getAllCurrentRules())
-                    .map(collectValues(EdgeRule::getLabel)).orElseGet(HashSet::new);
+            .map(collectValues(EdgeRule::getLabel)).orElseGet(HashSet::new);
 
             labels.forEach(label -> {
                 if (graphMgmt.containsRelationType(label)) {
-                    LOGGER.debug(" EdgeLabel  [{}] already existed. ", label);
+                    LOGGER.debug(" EdgeLabel  [{}] already exists.", label);
                 } else {
                     LOGGER.debug("Making EdgeLabel: [{}]", label);
-                    graphMgmt.makeEdgeLabel(label).multiplicity(Multiplicity.valueOf("MULTI")).make();
+                    graphMgmt.makeEdgeLabel(label).multiplicity(Multiplicity.MULTI).make();
                 }
+                EdgeLabel relation = graphMgmt.getEdgeLabel(label);
+                RelationTypeIndex relationIndex = graphMgmt.getRelationIndex(relation, label);
+                if(relationIndex == null) {
+                    LOGGER.debug("Creating edge index for relation: " + label);
+                    graphMgmt.buildEdgeIndex(relation, label, Direction.BOTH, graphMgmt.getPropertyKey("aai-node-type"));
+                    if(dbNotEmpty) {
+                        LOGGER.info("DB not empty. Registering edge [{}] for later reindexing.", label);
+                        elementsToReindex.add(relation.name());
+                    }
+                } else if(!relationIndex.getIndexStatus().equals(SchemaStatus.ENABLED)) {
+                    LOGGER.info("Relation index was already created but is not in ENABLED status. Current status: [{}]", relationIndex.getIndexStatus());
+                    elementsToReindex.add(label);
+                } else {
+                    LOGGER.debug("Edge index for label [{}] already exists", label);
+                };
             });
         } catch (EdgeRuleNotFoundException e) {
             LOGGER.error("Unable to find all rules {}", LogFormatTools.getStackTop(e));
index cb388cc..d9994f5 100644 (file)
@@ -147,14 +147,14 @@ public class AAIGraph {
 
     private void loadSchema(JanusGraph graph) {
         // Load the propertyKeys, indexes and edge-Labels into the DB
-        JanusGraphManagement graphMgt = graph.openManagement();
-
+        boolean dbNotEmpty = graph.traversal().V().limit(1).hasNext();
         logger.info("-- loading schema into JanusGraph");
         if ("true".equals(
-                SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.enabled", "false"))) {
+            SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.enabled", "false"))) {
+            JanusGraphManagement graphMgt = graph.openManagement();
             SchemaGenerator4Hist.loadSchemaIntoJanusGraph(graphMgt, IN_MEMORY);
         } else {
-            SchemaGenerator.loadSchemaIntoJanusGraph(graphMgt, IN_MEMORY);
+            SchemaGenerator.loadSchemaIntoJanusGraph(graph, IN_MEMORY, dbNotEmpty);
         }
     }
 
index 51a2c22..cca11c6 100644 (file)
@@ -50,10 +50,9 @@ public class InMemoryGraph {
 
             Properties graphProps = new Properties();
             graphProps.load(is);
-            JanusGraphManagement graphMgt = graph.openManagement();
             if (builder.isSchemaEnabled) {
                 LOGGER.info("Schema Enabled");
-                SchemaGenerator.loadSchemaIntoJanusGraph(graphMgt, graphProps.getProperty("storage.backend"));
+                SchemaGenerator.loadSchemaIntoJanusGraph(graph, graphProps.getProperty("storage.backend"), false);
             }
             try (JanusGraphTransaction transaction = graph.newTransaction()) {
                 LOGGER.info("Loading snapshot");
index ac08ae2..a1206b5 100644 (file)
@@ -47,7 +47,10 @@ import org.onap.aai.serialization.engines.TransactionalGraphEngine;
 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
 import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
 import org.onap.aai.setup.SchemaVersion;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
 
+@DirtiesContext(classMode=ClassMode.BEFORE_CLASS)
 public class ResourceWithSoTTest extends AAISetup {
     @Mock
     private UrlBuilder urlBuilder;
@@ -78,7 +81,7 @@ public class ResourceWithSoTTest extends AAISetup {
         graph = TinkerGraph.open();
 
         long currentTimeMs = System.currentTimeMillis();
-        String timeNowInMs = Long.toString(currentTimeMs);
+        final String timeNowInMs = Long.toString(currentTimeMs);
 
         // PUT / CREATE
         jsonPutObj.addProperty("aai-created-ts", timeNowInMs);
@@ -114,6 +117,24 @@ public class ResourceWithSoTTest extends AAISetup {
         createLoaderEngineSetup();
     }
 
+    public void createLoaderEngineSetup() throws AAIException {
+
+        loader = loaderFactory.createLoaderForVersion(factoryType, version);
+
+        dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader));
+        serializer = new DBSerializer(version, dbEngine, factoryType, "Junit");
+        resourceWithSoT = new ResourceWithSoT.Builder(loader, serializer, urlBuilder).build();
+
+        TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin());
+
+        when(dbEngine.tx()).thenReturn(graph);
+        when(dbEngine.asAdmin()).thenReturn(spyAdmin);
+
+        when(spyAdmin.getReadOnlyTraversalSource())
+                .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance()));
+        when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal());
+    }
+
     // This test is to simulate a PUT request
     @Test
     public void testGetJsonFromVertexWithCreateVertex() throws AAIFormatVertexException, AAIException {
@@ -148,24 +169,4 @@ public class ResourceWithSoTTest extends AAISetup {
         Optional<JsonObject> result = resourceWithSoT.getJsonFromVertex(null);
         assertFalse(result.isPresent());
     }
-
-    public void createLoaderEngineSetup() throws AAIException {
-
-        if (loader == null) {
-            loader = loaderFactory.createLoaderForVersion(factoryType, version);
-            // loader = LoaderFactory.createLoaderForVersion(factoryType, version);
-            dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader));
-            serializer = new DBSerializer(version, dbEngine, factoryType, "Junit");
-            resourceWithSoT = new ResourceWithSoT.Builder(loader, serializer, urlBuilder).build();
-
-            TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin());
-
-            when(dbEngine.tx()).thenReturn(graph);
-            when(dbEngine.asAdmin()).thenReturn(spyAdmin);
-
-            when(spyAdmin.getReadOnlyTraversalSource())
-                    .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance()));
-            when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal());
-        }
-    }
 }
index 820925a..694abfe 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-els-onap-logging</artifactId>
index 32a3c49..5df2733 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index 72c907b..2b5c191 100644 (file)
@@ -27,7 +27,7 @@ limitations under the License.
   <parent>
     <groupId>org.onap.aai.aai-common</groupId>
     <artifactId>aai-common</artifactId>
-    <version>1.13.4-SNAPSHOT</version>
+    <version>1.13.5-SNAPSHOT</version>
   </parent>
   <artifactId>aai-parent</artifactId>
   <name>aai-parent</name>
index 252c283..cb9e677 100644 (file)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-rest</artifactId>
index 24737ec..e91a493 100644 (file)
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.onap.aai.aai-common</groupId>
     <artifactId>aai-parent</artifactId>
-    <version>1.13.4-SNAPSHOT</version>
+    <version>1.13.5-SNAPSHOT</version>
     <relativePath>../aai-parent/pom.xml</relativePath>
   </parent>
 
index 14706af..3d530ae 100644 (file)
@@ -26,7 +26,7 @@ limitations under the License.
        <parent>
                <groupId>org.onap.aai.aai-common</groupId>
                <artifactId>aai-parent</artifactId>
-               <version>1.13.4-SNAPSHOT</version>
+               <version>1.13.5-SNAPSHOT</version>
                <relativePath>../aai-parent/pom.xml</relativePath>
        </parent>
        <artifactId>aai-schema-ingest</artifactId>
index e48e4c2..c83b804 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.aai.aai-common</groupId>
         <artifactId>aai-parent</artifactId>
-        <version>1.13.4-SNAPSHOT</version>
+        <version>1.13.5-SNAPSHOT</version>
         <relativePath>../aai-parent/pom.xml</relativePath>
     </parent>
     <artifactId>aai-utils</artifactId>
diff --git a/pom.xml b/pom.xml
index fa17a6d..08b2c12 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@
 
     <groupId>org.onap.aai.aai-common</groupId>
     <artifactId>aai-common</artifactId>
-    <version>1.13.4-SNAPSHOT</version>
+    <version>1.13.5-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>aai-aai-common</name>
     <description>Contains all of the common code for resources and traversal repos</description>
index c5bbf54..51a6e0a 100644 (file)
@@ -5,7 +5,7 @@
 
 major_version=1
 minor_version=13
-patch_version=4
+patch_version=5
 
 base_version=${major_version}.${minor_version}.${patch_version}