/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.drill.exec.work.fragment; import org.apache.drill.common.exceptions.UserException; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.ops.FragmentContext; import org.apache.drill.exec.proto.BitControl.FragmentStatus; import org.apache.drill.exec.proto.ExecProtos.FragmentHandle; import org.apache.drill.exec.proto.UserBitShared.FragmentState; import org.apache.drill.exec.proto.UserBitShared.MinorFragmentProfile; import org.apache.drill.exec.proto.helper.QueryIdHelper; import org.apache.drill.exec.rpc.control.ControlTunnel; /** * The status reporter is responsible for receiving changes in fragment state and propagating the status back to the * Foreman through a control tunnel. */ public class FragmentStatusReporter { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FragmentStatusReporter.class); private final FragmentContext context; private final ControlTunnel tunnel; public FragmentStatusReporter(final FragmentContext context, final ControlTunnel tunnel) { this.context = context; this.tunnel = tunnel; } /** * Returns a {@link FragmentStatus} with the given state. {@link FragmentStatus} has additional information like * metrics, etc. that is gathered from the {@link FragmentContext}. * * @param state the state to include in the status * @return the status */ FragmentStatus getStatus(final FragmentState state) { return getStatus(state, null); } private FragmentStatus getStatus(final FragmentState state, final UserException ex) { final FragmentStatus.Builder status = FragmentStatus.newBuilder(); final MinorFragmentProfile.Builder b = MinorFragmentProfile.newBuilder(); context.getStats().addMetricsToStatus(b); b.setState(state); if (ex != null) { final boolean verbose = context.getOptions().getOption(ExecConstants.ENABLE_VERBOSE_ERRORS_KEY).bool_val; b.setError(ex.getOrCreatePBError(verbose)); } status.setHandle(context.getHandle()); b.setMemoryUsed(context.getAllocator().getAllocatedMemory()); b.setMinorFragmentId(context.getHandle().getMinorFragmentId()); status.setProfile(b); return status.build(); } /** * Reports the state change to the Foreman. The state is wrapped in a {@link FragmentStatus} that has additional * information like metrics, etc. This additional information is gathered from the {@link FragmentContext}. * NOTE: Use {@link #fail} to report state change to {@link FragmentState#FAILED}. * * @param newState the new state */ void stateChanged(final FragmentState newState) { final FragmentStatus status = getStatus(newState, null); logger.info("{}: State to report: {}", QueryIdHelper.getQueryIdentifier(context.getHandle()), newState); switch (newState) { case AWAITING_ALLOCATION: case CANCELLATION_REQUESTED: case CANCELLED: case FINISHED: case RUNNING: sendStatus(status); break; case SENDING: // no op. break; case FAILED: // shouldn't get here since fail() should be called. default: throw new IllegalStateException(String.format("Received state changed event for unexpected state of %s.", newState)); } } private void sendStatus(final FragmentStatus status) { tunnel.sendFragmentStatus(status); } /** * {@link FragmentStatus} with the {@link FragmentState#FAILED} state is reported to the Foreman. The * {@link FragmentStatus} has additional information like metrics, etc. that is gathered from the * {@link FragmentContext}. * * @param ex the exception related to the failure */ void fail(final UserException ex) { final FragmentStatus status = getStatus(FragmentState.FAILED, ex); sendStatus(status); } }