github.com/polarismesh/polaris@v1.17.8/store/boltdb/ratelimit.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package boltdb
    19  
    20  import (
    21  	"errors"
    22  	"reflect"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	bolt "go.etcd.io/bbolt"
    29  
    30  	"github.com/polarismesh/polaris/common/model"
    31  	"github.com/polarismesh/polaris/common/utils"
    32  	"github.com/polarismesh/polaris/store"
    33  )
    34  
    35  var _ store.RateLimitStore = (*rateLimitStore)(nil)
    36  
    37  var (
    38  	ErrBadParam       = errors.New("missing some params")
    39  	ErrMultipleResult = errors.New("multiple ratelimit find")
    40  )
    41  
    42  const (
    43  	// rule 相关信息以及映射
    44  	tblRateLimitConfig       string = "ratelimit_config"
    45  	RateLimitFieldID         string = "ID"
    46  	RateLimitFieldServiceID  string = "ServiceID"
    47  	RateLimitFieldClusterID  string = "ClusterID"
    48  	RateLimitFieldEnableTime string = "EnableTime"
    49  	RateLimitFieldName       string = "Name"
    50  	RateLimitFieldDisable    string = "Disable"
    51  	RateLimitFieldMethod     string = "Method"
    52  	RateLimitFieldLabels     string = "Labels"
    53  	RateLimitFieldPriority   string = "Priority"
    54  	RateLimitFieldRule       string = "Rule"
    55  	RateLimitFieldRevision   string = "Revision"
    56  	RateLimitFieldValid      string = "Valid"
    57  	RateLimitFieldCreateTime string = "CreateTime"
    58  	RateLimitFieldModifyTime string = "ModifyTime"
    59  	RateConfFieldMtime       string = "ModifyTime"
    60  	RateConfFieldServiceID   string = "ServiceID"
    61  	RateConfFieldValid       string = "Valid"
    62  )
    63  
    64  type rateLimitStore struct {
    65  	handler BoltHandler
    66  }
    67  
    68  // CreateRateLimit 新增限流规则
    69  func (r *rateLimitStore) CreateRateLimit(limit *model.RateLimit) error {
    70  	if limit.ID == "" || limit.Revision == "" {
    71  		log.Error("[Store][boltdb] create ratelimit missing some params")
    72  		return ErrBadParam
    73  	}
    74  
    75  	return r.createRateLimit(limit)
    76  }
    77  
    78  // UpdateRateLimit 更新限流规则
    79  func (r *rateLimitStore) UpdateRateLimit(limit *model.RateLimit) error {
    80  	if limit.ID == "" || limit.Revision == "" {
    81  		log.Error("[Store][boltdb] update ratelimit missing some params")
    82  		return ErrBadParam
    83  	}
    84  
    85  	return r.updateRateLimit(limit)
    86  }
    87  
    88  // EnableRateLimit 激活限流规则
    89  func (r *rateLimitStore) EnableRateLimit(limit *model.RateLimit) error {
    90  	if limit.ID == "" || limit.Revision == "" {
    91  		log.Error("[Store][boltdb] update ratelimit missing some params")
    92  		return ErrBadParam
    93  	}
    94  	return r.enableRateLimit(limit)
    95  }
    96  
    97  // DeleteRateLimit 删除限流规则
    98  func (r *rateLimitStore) DeleteRateLimit(limit *model.RateLimit) error {
    99  	if limit.ID == "" || limit.Revision == "" {
   100  		log.Error("[Store][boltdb] delete ratelimit missing some params")
   101  		return ErrBadParam
   102  	}
   103  
   104  	return r.deleteRateLimit(limit)
   105  }
   106  
   107  // GetExtendRateLimits 根据过滤条件拉取限流规则
   108  func (r *rateLimitStore) GetExtendRateLimits(
   109  	query map[string]string, offset uint32, limit uint32) (uint32, []*model.ExtendRateLimit, error) {
   110  
   111  	handler := r.handler
   112  	fields := append(utils.CollectMapKeys(query), RateConfFieldServiceID, RateConfFieldValid)
   113  
   114  	result, err := handler.LoadValuesByFilter(tblRateLimitConfig, fields, &model.RateLimit{},
   115  		func(m map[string]interface{}) bool {
   116  			validVal, ok := m[RateConfFieldValid]
   117  			if ok && !validVal.(bool) {
   118  				return false
   119  			}
   120  			delete(m, RateConfFieldValid)
   121  
   122  			for k, v := range query {
   123  				if k == "name" || k == "method" || k == "labels" {
   124  					if !strings.Contains(m[k].(string), v) {
   125  						return false
   126  					}
   127  				} else if k == "disable" {
   128  					if v != strconv.FormatBool(m[RateLimitFieldDisable].(bool)) {
   129  						return false
   130  					}
   131  				} else {
   132  					qV := m[k]
   133  					if !reflect.DeepEqual(qV, v) {
   134  						return false
   135  					}
   136  				}
   137  			}
   138  			return true
   139  		})
   140  
   141  	if err != nil {
   142  		return 0, nil, err
   143  	}
   144  	if len(result) == 0 {
   145  		return 0, []*model.ExtendRateLimit{}, nil
   146  	}
   147  
   148  	out := make([]*model.ExtendRateLimit, 0, len(result))
   149  	for _, r := range result {
   150  		var temp model.ExtendRateLimit
   151  		temp.RateLimit = r.(*model.RateLimit)
   152  
   153  		out = append(out, &temp)
   154  	}
   155  
   156  	return uint32(len(result)), getRealRateConfList(out, offset, limit), nil
   157  }
   158  
   159  // GetRateLimitWithID 根据限流ID拉取限流规则
   160  func (r *rateLimitStore) GetRateLimitWithID(id string) (*model.RateLimit, error) {
   161  	if id == "" {
   162  		return nil, ErrBadParam
   163  	}
   164  
   165  	handler := r.handler
   166  	result, err := handler.LoadValues(tblRateLimitConfig, []string{id}, &model.RateLimit{})
   167  
   168  	if err != nil {
   169  		log.Errorf("[Store][boltdb] get rate limit fail : %s", err.Error())
   170  		return nil, err
   171  	}
   172  
   173  	if len(result) > 1 {
   174  		return nil, ErrMultipleResult
   175  	}
   176  
   177  	if len(result) == 0 {
   178  		return nil, nil
   179  	}
   180  
   181  	rateLimitRet := result[id].(*model.RateLimit)
   182  	if rateLimitRet.Valid {
   183  		return rateLimitRet, nil
   184  	}
   185  
   186  	return nil, nil
   187  }
   188  
   189  // GetRateLimitsForCache 根据修改时间拉取增量限流规则及最新版本号
   190  func (r *rateLimitStore) GetRateLimitsForCache(mtime time.Time,
   191  	firstUpdate bool) ([]*model.RateLimit, error) {
   192  	handler := r.handler
   193  
   194  	if firstUpdate {
   195  		mtime = time.Time{}
   196  	}
   197  
   198  	var (
   199  		fields = []string{RateConfFieldMtime, RateConfFieldServiceID}
   200  	)
   201  	limitResults, err := handler.LoadValuesByFilter(tblRateLimitConfig, fields, &model.RateLimit{},
   202  		func(m map[string]interface{}) bool {
   203  			mt := m[RateConfFieldMtime].(time.Time)
   204  			isAfter := !mt.Before(mtime)
   205  			return isAfter
   206  		})
   207  
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	if len(limitResults) == 0 {
   213  		return []*model.RateLimit{}, nil
   214  	}
   215  
   216  	limits := make([]*model.RateLimit, 0, len(limitResults))
   217  
   218  	for i := range limitResults {
   219  		rule := limitResults[i].(*model.RateLimit)
   220  		limits = append(limits, rule)
   221  	}
   222  
   223  	return limits, nil
   224  }
   225  
   226  // createRateLimit save model.RateLimit and model.RateLimitRevision
   227  //
   228  //	@receiver r *rateLimitStore
   229  //	@param limit current limiting configuration data to be saved
   230  //	@return error
   231  func (r *rateLimitStore) createRateLimit(limit *model.RateLimit) error {
   232  	handler := r.handler
   233  	tNow := time.Now()
   234  	limit.CreateTime = tNow
   235  	limit.ModifyTime = tNow
   236  	if !limit.Disable {
   237  		limit.EnableTime = tNow
   238  	} else {
   239  		limit.EnableTime = time.Unix(0, 0)
   240  	}
   241  	limit.Valid = true
   242  	return handler.Execute(true, func(tx *bolt.Tx) error {
   243  		// create ratelimit_config
   244  		if err := saveValue(tx, tblRateLimitConfig, limit.ID, limit); err != nil {
   245  			log.Errorf("[Store][RateLimit] create rate_limit(%s, %s), %+v, err: %s",
   246  				limit.ID, limit.ServiceID, limit, err.Error())
   247  			return err
   248  		}
   249  		return nil
   250  	})
   251  }
   252  
   253  // enableRateLimit
   254  //
   255  //	@receiver r
   256  //	@param limit
   257  //	@return error
   258  func (r *rateLimitStore) enableRateLimit(limit *model.RateLimit) error {
   259  	handler := r.handler
   260  	return handler.Execute(true, func(tx *bolt.Tx) error {
   261  		properties := make(map[string]interface{})
   262  		properties[RateLimitFieldDisable] = limit.Disable
   263  		properties[RateLimitFieldRevision] = limit.Revision
   264  		properties[RateLimitFieldModifyTime] = time.Now()
   265  		if limit.Disable {
   266  			properties[RateLimitFieldEnableTime] = time.Unix(0, 0)
   267  		} else {
   268  			properties[RateLimitFieldEnableTime] = time.Now()
   269  		}
   270  		// create ratelimit_config
   271  		if err := updateValue(tx, tblRateLimitConfig, limit.ID, properties); err != nil {
   272  			log.Errorf("[Store][RateLimit] update rate_limit(%s, %s) err: %s",
   273  				limit.ID, limit.ServiceID, err.Error())
   274  			return err
   275  		}
   276  		return nil
   277  	})
   278  }
   279  
   280  // updateRateLimit
   281  //
   282  //	@receiver r
   283  //	@param limit
   284  //	@return error
   285  func (r *rateLimitStore) updateRateLimit(limit *model.RateLimit) error {
   286  	handler := r.handler
   287  	return handler.Execute(true, func(tx *bolt.Tx) error {
   288  		properties := make(map[string]interface{})
   289  		properties[RateLimitFieldName] = limit.Name
   290  		properties[RateLimitFieldServiceID] = limit.ServiceID
   291  		properties[RateLimitFieldMethod] = limit.Method
   292  		properties[RateLimitFieldDisable] = limit.Disable
   293  		properties[RateLimitFieldLabels] = limit.Labels
   294  		properties[RateLimitFieldPriority] = limit.Priority
   295  		properties[RateLimitFieldRule] = limit.Rule
   296  		properties[RateLimitFieldRevision] = limit.Revision
   297  		properties[RateLimitFieldModifyTime] = time.Now()
   298  		if limit.Disable {
   299  			properties[RateLimitFieldEnableTime] = time.Unix(0, 0)
   300  		} else {
   301  			properties[RateLimitFieldEnableTime] = time.Now()
   302  		}
   303  		// create ratelimit_config
   304  		if err := updateValue(tx, tblRateLimitConfig, limit.ID, properties); err != nil {
   305  			log.Errorf("[Store][RateLimit] update rate_limit(%s, %s) err: %s",
   306  				limit.ID, limit.ServiceID, err.Error())
   307  			return err
   308  		}
   309  		return nil
   310  	})
   311  }
   312  
   313  // deleteRateLimit
   314  //
   315  //	@receiver r
   316  //	@param limit
   317  //	@return error
   318  func (r *rateLimitStore) deleteRateLimit(limit *model.RateLimit) error {
   319  	handler := r.handler
   320  
   321  	return handler.Execute(true, func(tx *bolt.Tx) error {
   322  
   323  		properties := make(map[string]interface{})
   324  		properties[RateLimitFieldValid] = false
   325  		properties[RateLimitFieldModifyTime] = time.Now()
   326  
   327  		if err := updateValue(tx, tblRateLimitConfig, limit.ID, properties); err != nil {
   328  			log.Errorf("[Store][RateLimit] delete rate_limit(%s, %s) err: %s",
   329  				limit.ID, limit.ServiceID, err.Error())
   330  			return err
   331  		}
   332  		return nil
   333  	})
   334  }
   335  
   336  func getRealRateConfList(routeConf []*model.ExtendRateLimit, offset, limit uint32) []*model.ExtendRateLimit {
   337  
   338  	beginIndex := offset
   339  	endIndex := beginIndex + limit
   340  	totalCount := uint32(len(routeConf))
   341  	// handle invalid offset, limit
   342  	if totalCount == 0 {
   343  		return routeConf
   344  	}
   345  	if beginIndex >= endIndex {
   346  		return routeConf
   347  	}
   348  	if beginIndex >= totalCount {
   349  		return routeConf
   350  	}
   351  	if endIndex > totalCount {
   352  		endIndex = totalCount
   353  	}
   354  
   355  	sort.Slice(routeConf, func(i, j int) bool {
   356  		// sort by modify time
   357  		if routeConf[i].RateLimit.ModifyTime.After(routeConf[j].RateLimit.ModifyTime) {
   358  			return true
   359  		} else if routeConf[i].RateLimit.ModifyTime.Before(routeConf[j].RateLimit.ModifyTime) {
   360  			return false
   361  		} else {
   362  			return strings.Compare(routeConf[i].RateLimit.ID, routeConf[j].RateLimit.ID) < 0
   363  		}
   364  	})
   365  
   366  	return routeConf[beginIndex:endIndex]
   367  }