package redis

import (
	
	
	
	

	
	
)

// ErrClosed performs any operation on the closed client will return this error.
var ErrClosed = pool.ErrClosed

// HasErrorPrefix checks if the err is a Redis error and the message contains a prefix.
func ( error,  string) bool {
	,  := .(Error)
	if ! {
		return false
	}
	 := .Error()
	 = strings.TrimPrefix(, "ERR ") // KVRocks adds such prefix
	return strings.HasPrefix(, )
}

type Error interface {
	error

	// RedisError is a no-op function but
	// serves to distinguish types that are Redis
	// errors from ordinary errors: a type is a
	// Redis error if it has a RedisError method.
	RedisError()
}

var _ Error = proto.RedisError("")

func shouldRetry( error,  bool) bool {
	switch  {
	case io.EOF, io.ErrUnexpectedEOF:
		return true
	case nil, context.Canceled, context.DeadlineExceeded:
		return false
	}

	if ,  := .(timeoutError);  {
		if .Timeout() {
			return 
		}
		return true
	}

	 := .Error()
	if  == "ERR max number of clients reached" {
		return true
	}
	if strings.HasPrefix(, "LOADING ") {
		return true
	}
	if strings.HasPrefix(, "READONLY ") {
		return true
	}
	if strings.HasPrefix(, "CLUSTERDOWN ") {
		return true
	}
	if strings.HasPrefix(, "TRYAGAIN ") {
		return true
	}

	return false
}

func isRedisError( error) bool {
	,  := .(proto.RedisError)
	return 
}

func isBadConn( error,  bool,  string) bool {
	switch  {
	case nil:
		return false
	case context.Canceled, context.DeadlineExceeded:
		return true
	}

	if isRedisError() {
		switch {
		case isReadOnlyError():
			// Close connections in read only state in case domain addr is used
			// and domain resolves to a different Redis Server. See #790.
			return true
		case isMovedSameConnAddr(, ):
			// Close connections when we are asked to move to the same addr
			// of the connection. Force a DNS resolution when all connections
			// of the pool are recycled
			return true
		default:
			return false
		}
	}

	if  {
		if ,  := .(net.Error);  && .Timeout() {
			return false
		}
	}

	return true
}

func isMovedError( error) ( bool,  bool,  string) {
	if !isRedisError() {
		return
	}

	 := .Error()
	switch {
	case strings.HasPrefix(, "MOVED "):
		 = true
	case strings.HasPrefix(, "ASK "):
		 = true
	default:
		return
	}

	 := strings.LastIndex(, " ")
	if  == -1 {
		return false, false, ""
	}
	 = [+1:]
	return
}

func isLoadingError( error) bool {
	return strings.HasPrefix(.Error(), "LOADING ")
}

func isReadOnlyError( error) bool {
	return strings.HasPrefix(.Error(), "READONLY ")
}

func isMovedSameConnAddr( error,  string) bool {
	 := .Error()
	if !strings.HasPrefix(, "MOVED ") {
		return false
	}
	return strings.HasSuffix(, " "+)
}

//------------------------------------------------------------------------------

type timeoutError interface {
	Timeout() bool
}