core/base/result.go (165 lines of code) (raw):
// Copyright 1999-2020 Alibaba Group Holding Ltd.
//
// 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 base
import (
"fmt"
"time"
)
type BlockType uint8
const (
BlockTypeUnknown BlockType = iota
BlockTypeFlow
BlockTypeIsolation
BlockTypeCircuitBreaking
BlockTypeSystemFlow
BlockTypeHotSpotParamFlow
)
var (
blockTypeMap = map[BlockType]string{
BlockTypeUnknown: "BlockTypeUnknown",
BlockTypeFlow: "BlockTypeFlowControl",
BlockTypeIsolation: "BlockTypeIsolation",
BlockTypeCircuitBreaking: "BlockTypeCircuitBreaking",
BlockTypeSystemFlow: "BlockTypeSystem",
BlockTypeHotSpotParamFlow: "BlockTypeHotSpotParamFlow",
}
blockTypeExisted = fmt.Errorf("block type existed")
)
// RegistryBlockType adds block type and corresponding description in order.
func RegistryBlockType(blockType BlockType, desc string) error {
_, exist := blockTypeMap[blockType]
if exist {
return blockTypeExisted
}
blockTypeMap[blockType] = desc
return nil
}
func (t BlockType) String() string {
name, ok := blockTypeMap[t]
if ok {
return name
}
return fmt.Sprintf("%d", t)
}
type TokenResultStatus uint8
const (
ResultStatusPass TokenResultStatus = iota
ResultStatusBlocked
ResultStatusShouldWait
)
func (s TokenResultStatus) String() string {
switch s {
case ResultStatusPass:
return "ResultStatusPass"
case ResultStatusBlocked:
return "ResultStatusBlocked"
case ResultStatusShouldWait:
return "ResultStatusShouldWait"
default:
return "Undefined"
}
}
type TokenResult struct {
status TokenResultStatus
blockErr *BlockError
nanosToWait time.Duration
filterNodes []string
halfOpenNodes []string
}
func (r *TokenResult) DeepCopyFrom(newResult *TokenResult) {
r.status = newResult.status
r.nanosToWait = newResult.nanosToWait
if r.blockErr == nil {
r.blockErr = &BlockError{
blockType: newResult.blockErr.blockType,
blockMsg: newResult.blockErr.blockMsg,
rule: newResult.blockErr.rule,
snapshotValue: newResult.blockErr.snapshotValue,
}
} else {
// TODO: review the reusing logic
r.blockErr.blockType = newResult.blockErr.blockType
r.blockErr.blockMsg = newResult.blockErr.blockMsg
r.blockErr.rule = newResult.blockErr.rule
r.blockErr.snapshotValue = newResult.blockErr.snapshotValue
}
}
func (r *TokenResult) ResetToPass() {
r.status = ResultStatusPass
r.blockErr = nil
r.nanosToWait = 0
}
func (r *TokenResult) ResetToBlockedWith(opts ...BlockErrorOption) {
r.status = ResultStatusBlocked
if r.blockErr == nil {
r.blockErr = NewBlockError(opts...)
} else {
r.blockErr.ResetBlockError(opts...)
}
r.nanosToWait = 0
}
func (r *TokenResult) ResetToBlocked(blockType BlockType) {
r.ResetToBlockedWith(WithBlockType(blockType))
}
func (r *TokenResult) ResetToBlockedWithMessage(blockType BlockType, blockMsg string) {
r.ResetToBlockedWith(WithBlockType(blockType), WithBlockMsg(blockMsg))
}
func (r *TokenResult) ResetToBlockedWithCause(blockType BlockType, blockMsg string, rule SentinelRule, snapshot interface{}) {
r.ResetToBlockedWith(WithBlockType(blockType), WithBlockMsg(blockMsg), WithRule(rule), WithSnapshotValue(snapshot))
}
func (r *TokenResult) IsPass() bool {
return r.status == ResultStatusPass
}
func (r *TokenResult) IsBlocked() bool {
return r.status == ResultStatusBlocked
}
func (r *TokenResult) Status() TokenResultStatus {
return r.status
}
func (r *TokenResult) BlockError() *BlockError {
return r.blockErr
}
func (r *TokenResult) NanosToWait() time.Duration {
return r.nanosToWait
}
func (r *TokenResult) FilterNodes() []string {
return r.filterNodes
}
func (r *TokenResult) HalfOpenNodes() []string {
return r.halfOpenNodes
}
func (r *TokenResult) SetFilterNodes(nodes []string) {
r.filterNodes = nodes
}
func (r *TokenResult) SetHalfOpenNodes(nodes []string) {
r.halfOpenNodes = nodes
}
func (r *TokenResult) String() string {
var blockMsg string
if r.blockErr == nil {
blockMsg = "none"
} else {
blockMsg = r.blockErr.Error()
}
return fmt.Sprintf("TokenResult{status=%s, blockErr=%s, nanosToWait=%d}", r.status.String(), blockMsg, r.nanosToWait)
}
func NewTokenResultPass() *TokenResult {
return NewTokenResult(ResultStatusPass)
}
func NewTokenResultBlocked(blockType BlockType) *TokenResult {
return NewTokenResult(ResultStatusBlocked, WithBlockType(blockType))
}
func NewTokenResultBlockedWithMessage(blockType BlockType, blockMsg string) *TokenResult {
return NewTokenResult(ResultStatusBlocked, WithBlockType(blockType), WithBlockMsg(blockMsg))
}
func NewTokenResultBlockedWithCause(blockType BlockType, blockMsg string, rule SentinelRule, snapshot interface{}) *TokenResult {
return NewTokenResult(ResultStatusBlocked, WithBlockType(blockType), WithBlockMsg(blockMsg), WithRule(rule), WithSnapshotValue(snapshot))
}
func NewTokenResult(status TokenResultStatus, blockErrOpts ...BlockErrorOption) *TokenResult {
return &TokenResult{
status: status,
blockErr: NewBlockError(blockErrOpts...),
nanosToWait: 0,
}
}
func NewTokenResultShouldWait(waitNs time.Duration) *TokenResult {
result := NewTokenResult(ResultStatusShouldWait)
result.nanosToWait = waitNs
return result
}