// Copyright 2017 JanusGraph Authors // // 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 // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.janusgraph.graphdb.olap.job; import com.google.common.base.Preconditions; import org.janusgraph.core.RelationType; import org.janusgraph.core.JanusGraphException; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.schema.Index; import org.janusgraph.diskstorage.configuration.ConfigNamespace; import org.janusgraph.diskstorage.configuration.ConfigOption; import org.janusgraph.diskstorage.configuration.Configuration; import org.janusgraph.diskstorage.keycolumnvalue.scan.ScanMetrics; import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration; import org.janusgraph.graphdb.database.StandardJanusGraph; import org.janusgraph.graphdb.database.management.ManagementSystem; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; import org.janusgraph.graphdb.transaction.StandardTransactionBuilder; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Instant; /** * @author Matthias Broecheler (me@matthiasb.com) */ public abstract class IndexUpdateJob { protected static final Logger log = LoggerFactory.getLogger(IndexRepairJob.class); protected static final String SUCCESS_TX = "success-tx"; protected static final String FAILED_TX = "failed-tx"; public static ConfigNamespace INDEX_JOB_NS = new ConfigNamespace(GraphDatabaseConfiguration.JOB_NS,"index","Configuration options relating to index jobs"); public static final ConfigOption<String> INDEX_NAME = new ConfigOption<String>(INDEX_JOB_NS,"index-name", "The name of the index to be repaired. For vertex-centric indexes this is the name of " + "the edge label or property key on which the index is installed.", ConfigOption.Type.LOCAL, String.class); public static final ConfigOption<String> INDEX_RELATION_TYPE = new ConfigOption<String>(INDEX_JOB_NS,"relation-type", "For a vertex-centric index, this is the name of the index associated with the " + "relation type configured under index-name. This should remain empty for global graph indexes.", ConfigOption.Type.LOCAL, "", str -> null != str); protected String indexRelationTypeName = null; protected String indexName = null; protected StandardJanusGraph graph; protected ManagementSystem mgmt = null; protected StandardJanusGraphTx writeTx; protected Index index; protected RelationType indexRelationType; protected Instant jobStartTime; public IndexUpdateJob() { } protected IndexUpdateJob(IndexUpdateJob copy) { this.indexName = copy.indexName; this.indexRelationTypeName = copy.indexRelationTypeName; } public IndexUpdateJob(final String indexName, final String indexRelationTypeName) { this.indexName = indexName; this.indexRelationTypeName = indexRelationTypeName; } public boolean isGlobalGraphIndex() { return indexRelationTypeName ==null || StringUtils.isBlank(indexRelationTypeName); } public boolean isRelationTypeIndex() { return !isGlobalGraphIndex(); } public void workerIterationStart(JanusGraph graph, Configuration config, ScanMetrics metrics) { this.graph = (StandardJanusGraph)graph; Preconditions.checkArgument(config.has(GraphDatabaseConfiguration.JOB_START_TIME),"Invalid configuration for this job. Start time is required."); this.jobStartTime = Instant.ofEpochMilli(config.get(GraphDatabaseConfiguration.JOB_START_TIME)); if (indexName == null) { Preconditions.checkArgument(config.has(INDEX_NAME), "Need to configure the name of the index to be repaired"); indexName = config.get(INDEX_NAME); indexRelationTypeName = config.get(INDEX_RELATION_TYPE); log.info("Read index information: name={} type={}", indexName, indexRelationTypeName); } try { this.mgmt = (ManagementSystem)graph.openManagement(); if (isGlobalGraphIndex()) { index = mgmt.getGraphIndex(indexName); } else { indexRelationType = mgmt.getRelationType(indexRelationTypeName); Preconditions.checkArgument(indexRelationType!=null,"Could not find relation type: %s", indexRelationTypeName); index = mgmt.getRelationIndex(indexRelationType,indexName); } Preconditions.checkArgument(index!=null,"Could not find index: %s [%s]",indexName,indexRelationTypeName); log.info("Found index {}", indexName); validateIndexStatus(); StandardTransactionBuilder txb = this.graph.buildTransaction(); txb.commitTime(jobStartTime); writeTx = (StandardJanusGraphTx)txb.start(); } catch (final Exception e) { if (null != mgmt && mgmt.isOpen()) mgmt.rollback(); if (writeTx!=null && writeTx.isOpen()) writeTx.rollback(); metrics.incrementCustom(FAILED_TX); throw new JanusGraphException(e.getMessage(), e); } } public void workerIterationEnd(ScanMetrics metrics) { try { if (null != mgmt && mgmt.isOpen()) mgmt.commit(); if (writeTx!=null && writeTx.isOpen()) writeTx.commit(); metrics.incrementCustom(SUCCESS_TX); } catch (RuntimeException e) { log.error("Transaction commit threw runtime exception:", e); metrics.incrementCustom(FAILED_TX); throw e; } } protected abstract void validateIndexStatus(); }