// 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.core.util; import com.google.common.base.Preconditions; import org.janusgraph.core.PropertyKey; import org.janusgraph.core.JanusGraphException; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.schema.RelationTypeIndex; import org.janusgraph.core.schema.JanusGraphIndex; import org.janusgraph.core.schema.Index; import org.janusgraph.core.schema.JanusGraphManagement; import org.janusgraph.diskstorage.util.time.TimestampProvider; import org.janusgraph.graphdb.database.StandardJanusGraph; import org.apache.commons.lang3.StringUtils; import java.time.Duration; import java.time.Instant; import java.time.temporal.TemporalUnit; /** * @author Matthias Broecheler (me@matthiasb.com) */ public class ManagementUtil { /** * This method blocks and waits until the provided index has been updated across the entire JanusGraph cluster * and reached a stable state. * This method will wait for the given period of time and throw an exception if the index did not reach a * final state within that time. The method simply returns when the index has reached the final state * prior to the time period expiring. * * This is a utility method to be invoked between two {@link org.janusgraph.core.schema.JanusGraphManagement#updateIndex(Index, org.janusgraph.core.schema.SchemaAction)} calls * to ensure that the previous update has successfully persisted. * * @param g * @param indexName * @param time * @param unit */ public static void awaitGraphIndexUpdate(JanusGraph g, String indexName, long time, TemporalUnit unit) { awaitIndexUpdate(g,indexName,null,time,unit); } public static void awaitVertexIndexUpdate(JanusGraph g, String indexName, String relationTypeName, long time, TemporalUnit unit) { awaitIndexUpdate(g,indexName,relationTypeName,time,unit); } private static void awaitIndexUpdate(JanusGraph g, String indexName, String relationTypeName, long time, TemporalUnit unit) { Preconditions.checkArgument(g!=null && g.isOpen(),"Need to provide valid, open graph instance"); Preconditions.checkArgument(time>0 && unit!=null,"Need to provide valid time interval"); Preconditions.checkArgument(StringUtils.isNotBlank(indexName),"Need to provide an index name"); StandardJanusGraph graph = (StandardJanusGraph)g; TimestampProvider times = graph.getConfiguration().getTimestampProvider(); Instant end = times.getTime().plus(Duration.of(time,unit)); boolean isStable = false; while (times.getTime().isBefore(end)) { JanusGraphManagement mgmt = graph.openManagement(); try { if (StringUtils.isNotBlank(relationTypeName)) { RelationTypeIndex idx = mgmt.getRelationIndex(mgmt.getRelationType(relationTypeName) ,indexName); Preconditions.checkArgument(idx!=null,"Index could not be found: %s @ %s",indexName,relationTypeName); isStable = idx.getIndexStatus().isStable(); } else { JanusGraphIndex idx = mgmt.getGraphIndex(indexName); Preconditions.checkArgument(idx!=null,"Index could not be found: %s",indexName); isStable = true; for (PropertyKey key : idx.getFieldKeys()) { if (!idx.getIndexStatus(key).isStable()) isStable = false; } } } finally { mgmt.rollback(); } if (isStable) break; try { times.sleepFor(Duration.ofMillis(500)); } catch (InterruptedException e) { } } if (!isStable) throw new JanusGraphException("Index did not stabilize within the given amount of time. For sufficiently long " + "wait periods this is most likely caused by a failed/incorrectly shut down JanusGraph instance or a lingering transaction."); } }