github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/merr/utils.go (about)

     1  // Licensed to the LF AI & Data foundation under one
     2  // or more contributor license agreements. See the NOTICE file
     3  // distributed with this work for additional information
     4  // regarding copyright ownership. The ASF licenses this file
     5  // to you under the Apache License, Version 2.0 (the
     6  // "License"); you may not use this file except in compliance
     7  // with the License. You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package merr
    18  
    19  import (
    20  	"context"
    21  	"strings"
    22  
    23  	"github.com/cockroachdb/errors"
    24  
    25  	"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
    26  )
    27  
    28  // Code returns the error code of the given error,
    29  // WARN: DO NOT use this for now
    30  func Code(err error) int32 {
    31  	if err == nil {
    32  		return 0
    33  	}
    34  
    35  	cause := errors.Cause(err)
    36  	switch cause := cause.(type) {
    37  	case milvusError:
    38  		return cause.code()
    39  
    40  	default:
    41  		if errors.Is(cause, context.Canceled) {
    42  			return CanceledCode
    43  		} else if errors.Is(cause, context.DeadlineExceeded) {
    44  			return TimeoutCode
    45  		} else {
    46  			return errUnexpected.code()
    47  		}
    48  	}
    49  }
    50  
    51  func IsRetryableErr(err error) bool {
    52  	if err, ok := err.(milvusError); ok {
    53  		return err.retriable
    54  	}
    55  
    56  	return false
    57  }
    58  
    59  func IsCanceledOrTimeout(err error) bool {
    60  	return errors.IsAny(err, context.Canceled, context.DeadlineExceeded)
    61  }
    62  
    63  // Status returns a status according to the given err,
    64  // returns Success status if err is nil
    65  func Status(err error) *commonpb.Status {
    66  	if err == nil {
    67  		return &commonpb.Status{}
    68  	}
    69  
    70  	code := Code(err)
    71  	return &commonpb.Status{
    72  		Code:   code,
    73  		Reason: previousLastError(err).Error(),
    74  		// Deprecated, for compatibility
    75  		ErrorCode: oldCode(code),
    76  		Retriable: IsRetryableErr(err),
    77  		Detail:    err.Error(),
    78  	}
    79  }
    80  
    81  func previousLastError(err error) error {
    82  	lastErr := err
    83  	for {
    84  		nextErr := errors.Unwrap(err)
    85  		if nextErr == nil {
    86  			break
    87  		}
    88  		lastErr = err
    89  		err = nextErr
    90  	}
    91  	return lastErr
    92  }
    93  
    94  func CheckRPCCall(resp interface{}, err error) error {
    95  	if err != nil {
    96  		return err
    97  	}
    98  	if resp == nil {
    99  		return errUnexpected
   100  	}
   101  	switch resp := resp.(type) {
   102  	case interface{ GetStatus() *commonpb.Status }:
   103  		return Error(resp.GetStatus())
   104  	case *commonpb.Status:
   105  		return Error(resp)
   106  	}
   107  	return nil
   108  }
   109  
   110  func Success(reason ...string) *commonpb.Status {
   111  	status := Status(nil)
   112  	// NOLINT
   113  	status.Reason = strings.Join(reason, " ")
   114  	return status
   115  }
   116  
   117  // Deprecated
   118  func StatusWithErrorCode(err error, code commonpb.ErrorCode) *commonpb.Status {
   119  	if err == nil {
   120  		return &commonpb.Status{}
   121  	}
   122  
   123  	return &commonpb.Status{
   124  		Code:      Code(err),
   125  		Reason:    err.Error(),
   126  		ErrorCode: code,
   127  	}
   128  }
   129  
   130  func oldCode(code int32) commonpb.ErrorCode {
   131  	switch code {
   132  	case ErrServiceNotReady.code():
   133  		return commonpb.ErrorCode_NotReadyServe
   134  
   135  	case ErrCollectionNotFound.code():
   136  		return commonpb.ErrorCode_CollectionNotExists
   137  
   138  	case ErrParameterInvalid.code():
   139  		return commonpb.ErrorCode_IllegalArgument
   140  
   141  	case ErrNodeNotMatch.code():
   142  		return commonpb.ErrorCode_NodeIDNotMatch
   143  
   144  	case ErrCollectionNotFound.code(), ErrPartitionNotFound.code(), ErrReplicaNotFound.code():
   145  		return commonpb.ErrorCode_MetaFailed
   146  
   147  	case ErrReplicaNotAvailable.code(), ErrChannelNotAvailable.code(), ErrNodeNotAvailable.code():
   148  		return commonpb.ErrorCode_NoReplicaAvailable
   149  
   150  	case ErrServiceMemoryLimitExceeded.code():
   151  		return commonpb.ErrorCode_InsufficientMemoryToLoad
   152  
   153  	case ErrServiceRateLimit.code():
   154  		return commonpb.ErrorCode_RateLimit
   155  
   156  	case ErrServiceForceDeny.code():
   157  		return commonpb.ErrorCode_ForceDeny
   158  
   159  	case ErrIndexNotFound.code():
   160  		return commonpb.ErrorCode_IndexNotExist
   161  
   162  	case ErrSegmentNotFound.code():
   163  		return commonpb.ErrorCode_SegmentNotFound
   164  
   165  	case ErrChannelLack.code():
   166  		return commonpb.ErrorCode_MetaFailed
   167  
   168  	default:
   169  		return commonpb.ErrorCode_UnexpectedError
   170  	}
   171  }
   172  
   173  func OldCodeToMerr(code commonpb.ErrorCode) error {
   174  	switch code {
   175  	case commonpb.ErrorCode_NotReadyServe:
   176  		return ErrServiceNotReady
   177  
   178  	case commonpb.ErrorCode_CollectionNotExists:
   179  		return ErrCollectionNotFound
   180  
   181  	case commonpb.ErrorCode_IllegalArgument:
   182  		return ErrParameterInvalid
   183  
   184  	case commonpb.ErrorCode_NodeIDNotMatch:
   185  		return ErrNodeNotMatch
   186  
   187  	case commonpb.ErrorCode_InsufficientMemoryToLoad, commonpb.ErrorCode_MemoryQuotaExhausted:
   188  		return ErrServiceMemoryLimitExceeded
   189  
   190  	case commonpb.ErrorCode_DiskQuotaExhausted:
   191  		return ErrServiceDiskLimitExceeded
   192  
   193  	case commonpb.ErrorCode_RateLimit:
   194  		return ErrServiceRateLimit
   195  
   196  	case commonpb.ErrorCode_ForceDeny:
   197  		return ErrServiceForceDeny
   198  
   199  	case commonpb.ErrorCode_IndexNotExist:
   200  		return ErrIndexNotFound
   201  
   202  	case commonpb.ErrorCode_SegmentNotFound:
   203  		return ErrSegmentNotFound
   204  
   205  	case commonpb.ErrorCode_MetaFailed:
   206  		return ErrChannelNotFound
   207  
   208  	default:
   209  		return errUnexpected
   210  	}
   211  }
   212  
   213  func Ok(status *commonpb.Status) bool {
   214  	return status.GetErrorCode() == commonpb.ErrorCode_Success && status.GetCode() == 0
   215  }
   216  
   217  // Error returns a error according to the given status,
   218  // returns nil if the status is a success status
   219  func Error(status *commonpb.Status) error {
   220  	if Ok(status) {
   221  		return nil
   222  	}
   223  
   224  	// use code first
   225  	code := status.GetCode()
   226  	if code == 0 {
   227  		return newMilvusErrorWithDetail(status.GetReason(), status.GetDetail(), Code(OldCodeToMerr(status.GetErrorCode())), false)
   228  	}
   229  	return newMilvusErrorWithDetail(status.GetReason(), status.GetDetail(), code, status.GetRetriable())
   230  }