All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.transactions.error.internal.ErrorClasses Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Couchbase, Inc.
 *
 * 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 com.couchbase.transactions.error.internal;

import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.error.AmbiguousTimeoutException;
import com.couchbase.client.core.error.CasMismatchException;
import com.couchbase.client.core.error.DocumentExistsException;
import com.couchbase.client.core.error.DocumentNotFoundException;
import com.couchbase.client.core.error.DurabilityAmbiguousException;
import com.couchbase.client.core.error.DurableWriteInProgressException;
import com.couchbase.client.core.error.RequestCanceledException;
import com.couchbase.client.core.error.TemporaryFailureException;
import com.couchbase.client.core.error.UnambiguousTimeoutException;
import com.couchbase.client.core.error.ValueTooLargeException;
import com.couchbase.client.core.error.subdoc.PathExistsException;
import com.couchbase.client.core.error.subdoc.PathNotFoundException;
import com.couchbase.transactions.error.attempts.DocumentAlreadyInTransaction;
import com.couchbase.transactions.error.external.TransactionOperationFailed;

@Stability.Internal
public enum ErrorClasses {
    // This is a special internal error class indicating the error is already an TransactionOperationFailed, and usually should be
    // passed through directly
    TRANSACTION_OPERATION_FAILED,

    FAIL_TRANSIENT,
    FAIL_HARD,
    FAIL_OTHER,
    FAIL_AMBIGUOUS,
    FAIL_DOC_ALREADY_EXISTS,
    FAIL_DOC_NOT_FOUND,
    FAIL_PATH_ALREADY_EXISTS,
    FAIL_PATH_NOT_FOUND,
    FAIL_CAS_MISMATCH,
    FAIL_EXPIRY,
    FAIL_WRITE_WRITE_CONFLICT,
    FAIL_ATR_FULL;

    public static ErrorClasses classify(Throwable err) {
        if (err instanceof TransactionOperationFailed) {
            return TRANSACTION_OPERATION_FAILED;
        }
        else if (err instanceof ErrorClassException) {
            return ((ErrorClassException) err).errorClass();
        }
        else if (err instanceof DocumentAlreadyInTransaction) {
            return FAIL_WRITE_WRITE_CONFLICT;
        }
        else if (err instanceof DocumentNotFoundException) {
            return FAIL_DOC_NOT_FOUND;
        }
        else if (err instanceof DocumentExistsException) {
            return FAIL_DOC_ALREADY_EXISTS;
        }
        else if (err instanceof PathExistsException) {
            return FAIL_PATH_ALREADY_EXISTS;
        }
        else if (err instanceof PathNotFoundException) {
            return FAIL_PATH_NOT_FOUND;
        }
        else if (err instanceof CasMismatchException) {
            return FAIL_CAS_MISMATCH;
        }
        else if (isFailTransient(err)) {
            return FAIL_TRANSIENT;
        }
        else if (isFailAmbiguous(err)) {
            return FAIL_AMBIGUOUS;
        }
        else if (isFailHard(err)) {
            return FAIL_HARD;
        }
        else if (err instanceof AttemptExpired) {
            return FAIL_EXPIRY;
        }
        else if (err instanceof ValueTooLargeException) {
            return FAIL_ATR_FULL;
        }
        else {
            return FAIL_OTHER;
        }
    }


    /*
     * What exceptions cause a retry has evolved.  Originally (DP1 and DP2) the rule was to retry on most exceptions.
     * However, this can give a poor user experience.  If the developer has a bug that say raises a NPE, the txn will
     * retry until timeout.  It's confusing.  So as of alpha.3, the rule will be to fast-fail on most exceptions.
     */
    public static boolean isFailTransient(Throwable e) {
        return e instanceof CasMismatchException

                // TXNJ-156: With BestEffortRetryStrategy, many errors such as TempFails will now surface as
                // timeouts instead.  This will include AmbiguousTimeoutException - we should already be able to
                // handle ambiguity, as with DurabilityAmbiguousException
                || e instanceof UnambiguousTimeoutException

                // These only included because several tests explicitly throw them as an error-injection.  Those
                // should be changed to return a more correct TimeoutException.
                || e instanceof TemporaryFailureException
                || e instanceof DurableWriteInProgressException

                // For testing
                || e instanceof TestFailTransient;
    }

    // For testing, need a mechanism to bypass the usual rollback & error-handling logic and leave a txn in a lost state.
    public static boolean isFailHard(Throwable e) {
        return e instanceof TestFailHard
                || e instanceof AbortedAsRequestedNoRollback
                || e instanceof AbortedAsRequestedNoRollbackNoCleanup
                || e instanceof AssertionError;
    }

    public static boolean isFailAmbiguous(Throwable e) {
        return e instanceof DurabilityAmbiguousException
                || e instanceof AmbiguousTimeoutException

                // If a mutation request was cancelled, it may succeed or not
                // TXNJ-163: This is thrown in several situations, including during node failover and removal.
                || e instanceof RequestCanceledException

                // For testing
                || e instanceof TestFailAmbiguous;
    }

    /**
     * Map from gocbcore's ordering of the error classes.
     */
    public static ErrorClasses mapFromQuery(Integer ec) {
        if (ec == null) {
            return FAIL_OTHER;
        }

        switch (ec) {
            case 1: return FAIL_TRANSIENT;
            case 2: return FAIL_DOC_NOT_FOUND;
            case 3: return FAIL_DOC_ALREADY_EXISTS;
            case 4: return FAIL_PATH_NOT_FOUND;
            case 5: return FAIL_PATH_ALREADY_EXISTS;
            case 6: return FAIL_WRITE_WRITE_CONFLICT;
            case 7: return FAIL_CAS_MISMATCH;
            case 8: return FAIL_HARD;
            case 9: return FAIL_AMBIGUOUS;
            case 10: return FAIL_EXPIRY;
            case 11: return FAIL_ATR_FULL;
            default: return FAIL_OTHER;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy