github.com/matrixorigin/matrixone@v1.2.0/pkg/logservice/errors.go (about)

     1  // Copyright 2021 - 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package logservice
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net"
    21  
    22  	"github.com/cockroachdb/errors"
    23  	"github.com/lni/dragonboat/v4"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/logutil"
    27  	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    28  )
    29  
    30  type errorToCode struct {
    31  	err     error
    32  	code    uint16
    33  	reverse bool
    34  }
    35  
    36  var errorToCodeMappings = getErrorToCodeMapping()
    37  
    38  // XXX This is strange code mapping.   Esp, the those mapped to
    39  // timeout -- per dragonbat, ErrTimeout is temp, but TimeoutTooSmall
    40  // and InvalidDeadline are not temp.
    41  func getErrorToCodeMapping() []errorToCode {
    42  	return []errorToCode{
    43  		{dragonboat.ErrTimeout, moerr.ErrDragonboatTimeout, true},
    44  		{dragonboat.ErrTimeoutTooSmall, moerr.ErrDragonboatTimeout, false},
    45  		{dragonboat.ErrInvalidDeadline, moerr.ErrDragonboatTimeout, false},
    46  		{dragonboat.ErrPayloadTooBig, moerr.ErrDragonboatInvalidPayloadSize, true},
    47  		{dragonboat.ErrRejected, moerr.ErrDragonboatRejected, true},
    48  		{dragonboat.ErrShardNotReady, moerr.ErrDragonboatShardNotReady, true},
    49  		{dragonboat.ErrSystemBusy, moerr.ErrDragonboatShardNotReady, false},
    50  		{dragonboat.ErrClosed, moerr.ErrDragonboatSystemClosed, true},
    51  		{dragonboat.ErrInvalidRange, moerr.ErrDragonboatInvalidRange, true},
    52  		{dragonboat.ErrShardNotFound, moerr.ErrDragonboatShardNotFound, true},
    53  	}
    54  }
    55  
    56  func toErrorCode(err error) (uint32, string) {
    57  	if err == nil {
    58  		return uint32(moerr.Ok), ""
    59  	}
    60  	for _, rec := range errorToCodeMappings {
    61  		if errors.Is(err, rec.err) {
    62  			logutil.Error(fmt.Sprintf("error: %v, converted to code %d", err, rec.code))
    63  			return uint32(rec.code), ""
    64  		}
    65  	}
    66  
    67  	merr, ok := err.(*moerr.Error)
    68  	if ok {
    69  		return uint32(merr.ErrorCode()), merr.Error()
    70  	}
    71  	return uint32(moerr.ErrDragonboatOtherSystemError), err.Error()
    72  }
    73  
    74  // toError reverse the response to dragonboat error.
    75  func toError(ctx context.Context, resp pb.Response) error {
    76  	if resp.ErrorCode == uint32(moerr.Ok) {
    77  		return nil
    78  	} else if resp.ErrorCode == uint32(moerr.ErrDragonboatOtherSystemError) {
    79  		return moerr.NewDragonboatOtherSystemError(ctx, resp.ErrorMessage)
    80  	}
    81  	// Mapped errors, not that we return a dragonboat error in these cases.
    82  	for _, rec := range errorToCodeMappings {
    83  		if uint32(rec.code) == resp.ErrorCode && rec.reverse {
    84  			return rec.err
    85  		}
    86  	}
    87  	// Three of our own errors.
    88  	if resp.ErrorCode == uint32(moerr.ErrNoHAKeeper) {
    89  		return moerr.NewNoHAKeeper(ctx)
    90  	} else if resp.ErrorCode == uint32(moerr.ErrInvalidTruncateLsn) {
    91  		return moerr.NewInvalidTruncateLsn(ctx, 0, 0)
    92  	} else if resp.ErrorCode == uint32(moerr.ErrNotLeaseHolder) {
    93  		// holder id get lost?
    94  		return moerr.NewNotLeaseHolder(ctx, 0xDEADBEEF)
    95  	} else if resp.ErrorCode == uint32(moerr.ErrInternal) {
    96  		// internal error
    97  		return moerr.NewInternalError(ctx, resp.ErrorMessage)
    98  	} else {
    99  		// will logger.Panicf panic?
   100  		panic(moerr.NewInternalError(ctx, "unknown error code: %d", resp.ErrorCode))
   101  	}
   102  	// will never reach here
   103  }
   104  
   105  func isTempError(err error) bool {
   106  	// non mo errors reached here, we handle first.
   107  	if dragonboat.IsTempError(err) {
   108  		return true
   109  	}
   110  
   111  	// XXX this error, while dragonboat says it is not temp
   112  	// we say yes.
   113  	if errors.Is(err, dragonboat.ErrShardNotFound) {
   114  		return true
   115  	}
   116  
   117  	//
   118  	if _, ok := err.(net.Error); ok {
   119  		return true
   120  	}
   121  
   122  	// How about those mapped from dragonboat errors?
   123  	// ErrDragonboatTimeout
   124  	// ErrDragonboatShardNotReady
   125  	// ErrDragonboatSystemClosed
   126  	//
   127  	// But, dragonboad ShardNotFound was not temp, but the code
   128  	// says we treat it as temp.
   129  	//
   130  	// Note that drgonboat errors are handled before moerr.
   131  	if moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper) ||
   132  		moerr.IsMoErrCode(err, moerr.ErrDragonboatShardNotFound) {
   133  		return true
   134  	}
   135  
   136  	return false
   137  }