org.apache.hadoop.io.retry.RetryUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.io.retry.RetryUtils.java

Source

/**
 * 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.hadoop.io.retry;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.retry.RetryPolicies.MultipleLinearRandomRetry;
import org.apache.hadoop.ipc.RemoteException;

import com.google.protobuf.ServiceException;
import org.apache.hadoop.ipc.RetriableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RetryUtils {
    public static final Logger LOG = LoggerFactory.getLogger(RetryUtils.class);

    /**
     * Return the default retry policy set in conf.
     * 
     * If the value retryPolicyEnabledKey is set to false in conf,
     * use TRY_ONCE_THEN_FAIL.
     * 
     * Otherwise, get the MultipleLinearRandomRetry policy specified in the conf
     * and then
     * (1) use multipleLinearRandomRetry for
     *     - remoteExceptionToRetry, or
     *     - IOException other than RemoteException, or
     *     - ServiceException; and
     * (2) use TRY_ONCE_THEN_FAIL for
     *     - non-remoteExceptionToRetry RemoteException, or
     *     - non-IOException.
     *     
     *
     * @param conf
     * @param retryPolicyEnabledKey     conf property key for enabling retry
     * @param defaultRetryPolicyEnabled default retryPolicyEnabledKey conf value 
     * @param retryPolicySpecKey        conf property key for retry policy spec
     * @param defaultRetryPolicySpec    default retryPolicySpecKey conf value
     * @param remoteExceptionToRetry    The particular RemoteException to retry
     * @return the default retry policy.
     */
    public static RetryPolicy getDefaultRetryPolicy(Configuration conf, String retryPolicyEnabledKey,
            boolean defaultRetryPolicyEnabled, String retryPolicySpecKey, String defaultRetryPolicySpec,
            final String remoteExceptionToRetry) {

        final RetryPolicy multipleLinearRandomRetry = getMultipleLinearRandomRetry(conf, retryPolicyEnabledKey,
                defaultRetryPolicyEnabled, retryPolicySpecKey, defaultRetryPolicySpec);

        LOG.debug("multipleLinearRandomRetry = {}", multipleLinearRandomRetry);

        if (multipleLinearRandomRetry == null) {
            //no retry
            return RetryPolicies.TRY_ONCE_THEN_FAIL;
        } else {
            return new WrapperRetryPolicy((MultipleLinearRandomRetry) multipleLinearRandomRetry,
                    remoteExceptionToRetry);
        }
    }

    private static final class WrapperRetryPolicy implements RetryPolicy {
        private MultipleLinearRandomRetry multipleLinearRandomRetry;
        private String remoteExceptionToRetry;

        private WrapperRetryPolicy(final MultipleLinearRandomRetry multipleLinearRandomRetry,
                final String remoteExceptionToRetry) {
            this.multipleLinearRandomRetry = multipleLinearRandomRetry;
            this.remoteExceptionToRetry = remoteExceptionToRetry;
        }

        @Override
        public RetryAction shouldRetry(Exception e, int retries, int failovers, boolean isMethodIdempotent)
                throws Exception {
            if (e instanceof ServiceException) {
                //unwrap ServiceException
                final Throwable cause = e.getCause();
                if (cause != null && cause instanceof Exception) {
                    e = (Exception) cause;
                }
            }

            //see (1) and (2) in the javadoc of this method.
            final RetryPolicy p;
            if (e instanceof RetriableException || RetryPolicies.getWrappedRetriableException(e) != null) {
                // RetriableException or RetriableException wrapped
                p = multipleLinearRandomRetry;
            } else if (e instanceof RemoteException) {
                final RemoteException re = (RemoteException) e;
                p = re.getClassName().equals(remoteExceptionToRetry) ? multipleLinearRandomRetry
                        : RetryPolicies.TRY_ONCE_THEN_FAIL;
            } else if (e instanceof IOException || e instanceof ServiceException) {
                p = multipleLinearRandomRetry;
            } else { //non-IOException
                p = RetryPolicies.TRY_ONCE_THEN_FAIL;
            }

            LOG.debug("RETRY {}) policy={}", retries, p.getClass().getSimpleName(), e);

            return p.shouldRetry(e, retries, failovers, isMethodIdempotent);
        }

        /**
         * remoteExceptionToRetry is ignored as part of equals since it does not
         * affect connection failure handling.
         */
        @Override
        public boolean equals(final Object obj) {
            if (obj == this) {
                return true;
            } else {
                return (obj instanceof WrapperRetryPolicy) && this.multipleLinearRandomRetry
                        .equals(((WrapperRetryPolicy) obj).multipleLinearRandomRetry);
            }
        }

        /**
         * Similarly, remoteExceptionToRetry is ignored as part of hashCode since it
         * does not affect connection failure handling.
         */
        @Override
        public int hashCode() {
            return multipleLinearRandomRetry.hashCode();
        }

        @Override
        public String toString() {
            return "RetryPolicy[" + multipleLinearRandomRetry + ", "
                    + RetryPolicies.TRY_ONCE_THEN_FAIL.getClass().getSimpleName() + "]";
        }
    }

    /**
     * Return the MultipleLinearRandomRetry policy specified in the conf,
     * or null if the feature is disabled.
     * If the policy is specified in the conf but the policy cannot be parsed,
     * the default policy is returned.
     * 
     * Retry policy spec:
     *   N pairs of sleep-time and number-of-retries "s1,n1,s2,n2,..."
     * 
     * @param conf
     * @param retryPolicyEnabledKey     conf property key for enabling retry
     * @param defaultRetryPolicyEnabled default retryPolicyEnabledKey conf value 
     * @param retryPolicySpecKey        conf property key for retry policy spec
     * @param defaultRetryPolicySpec    default retryPolicySpecKey conf value
     * @return the MultipleLinearRandomRetry policy specified in the conf,
     *         or null if the feature is disabled.
     */
    public static RetryPolicy getMultipleLinearRandomRetry(Configuration conf, String retryPolicyEnabledKey,
            boolean defaultRetryPolicyEnabled, String retryPolicySpecKey, String defaultRetryPolicySpec) {
        final boolean enabled = conf.getBoolean(retryPolicyEnabledKey, defaultRetryPolicyEnabled);
        if (!enabled) {
            return null;
        }

        final String policy = conf.get(retryPolicySpecKey, defaultRetryPolicySpec);

        final RetryPolicy r = RetryPolicies.MultipleLinearRandomRetry.parseCommaSeparatedString(policy);
        return (r != null) ? r
                : RetryPolicies.MultipleLinearRandomRetry.parseCommaSeparatedString(defaultRetryPolicySpec);
    }
}