diff --git a/engine/routes.go b/engine/routes.go index 6bba811f4e..ca2acf58af 100644 --- a/engine/routes.go +++ b/engine/routes.go @@ -166,6 +166,8 @@ func (rpS *RouteService) matchingRouteProfilesForEvent(ev *utils.CGREvent, singl } if singleResult { matchingRPrf = make([]*RouteProfile, 1) + } else { + matchingRPrf = make([]*RouteProfile, 0, len(rPrfIDs)) } evNm := utils.MapStorage{utils.MetaReq: ev.Event} for lpID := range rPrfIDs { diff --git a/engine/stats.go b/engine/stats.go index ed0af3c3d5..27d234c3d8 100644 --- a/engine/stats.go +++ b/engine/stats.go @@ -151,12 +151,9 @@ func (sS *StatService) StoreStatQueue(sq *StatQueue) (err error) { // matchingStatQueuesForEvent returns ordered list of matching resources which are active by the time of the call func (sS *StatService) matchingStatQueuesForEvent(args *StatsArgsProcessEvent) (sqs StatQueues, err error) { - matchingSQs := make(map[string]*StatQueue) - var sqIDs []string - if len(args.StatIDs) != 0 { - sqIDs = args.StatIDs - } else { - mapIDs, err := MatchingItemIDsForEvent(args.Event, + sqIDs := utils.NewStringSet(args.StatIDs) + if len(sqIDs) == 0 { + sqIDs, err = MatchingItemIDsForEvent(args.Event, sS.cgrcfg.StatSCfg().StringIndexedFields, sS.cgrcfg.StatSCfg().PrefixIndexedFields, sS.dm, utils.CacheStatFilterIndexes, args.Tenant, @@ -164,12 +161,12 @@ func (sS *StatService) matchingStatQueuesForEvent(args *StatsArgsProcessEvent) ( sS.cgrcfg.StatSCfg().NestedFields, ) if err != nil { - return nil, err + return } - sqIDs = mapIDs.AsSlice() } evNm := utils.MapStorage{utils.MetaReq: args.Event} - for _, sqID := range sqIDs { + sqs = make(StatQueues, 0, len(sqIDs)) + for sqID := range sqIDs { sqPrfl, err := sS.dm.GetStatQueueProfile(args.Tenant, sqID, true, true, utils.NonTransactional) if err != nil { if err == utils.ErrNotFound { @@ -203,15 +200,12 @@ func (sS *StatService) matchingStatQueuesForEvent(args *StatsArgsProcessEvent) ( sq.ttl = utils.DurationPointer(sqPrfl.TTL) } sq.sqPrfl = sqPrfl - matchingSQs[sqPrfl.ID] = sq + sqs = append(sqs, sq) } - // All good, convert from Map to Slice so we can sort - sqs = make(StatQueues, len(matchingSQs)) - i := 0 - for _, s := range matchingSQs { - sqs[i] = s - i++ + if len(sqs) == 0 { + return nil, utils.ErrNotFound } + // All good, convert from Map to Slice so we can sort sqs.Sort() for i, s := range sqs { if s.sqPrfl.Blocker { // blocker will stop processing diff --git a/engine/thresholds.go b/engine/thresholds.go index 4d85b99e88..1819e6cc93 100644 --- a/engine/thresholds.go +++ b/engine/thresholds.go @@ -235,12 +235,9 @@ func (tS *ThresholdService) StoreThreshold(t *Threshold) (err error) { // matchingThresholdsForEvent returns ordered list of matching thresholds which are active for an Event func (tS *ThresholdService) matchingThresholdsForEvent(args *ArgsProcessEvent) (ts Thresholds, err error) { - matchingTs := make(map[string]*Threshold) - var tIDs []string - if len(args.ThresholdIDs) != 0 { - tIDs = args.ThresholdIDs - } else { - tIDsMap, err := MatchingItemIDsForEvent(args.Event, + tIDs := utils.NewStringSet(args.ThresholdIDs) + if len(tIDs) == 0 { + tIDs, err = MatchingItemIDsForEvent(args.Event, tS.cgrcfg.ThresholdSCfg().StringIndexedFields, tS.cgrcfg.ThresholdSCfg().PrefixIndexedFields, tS.dm, utils.CacheThresholdFilterIndexes, args.Tenant, @@ -250,12 +247,12 @@ func (tS *ThresholdService) matchingThresholdsForEvent(args *ArgsProcessEvent) ( if err != nil { return nil, err } - tIDs = tIDsMap.AsSlice() } evNm := utils.MapStorage{ utils.MetaReq: args.Event, } - for _, tID := range tIDs { + ts = make(Thresholds, 0, len(tIDs)) + for tID := range tIDs { tPrfl, err := tS.dm.GetThresholdProfile(args.Tenant, tID, true, true, utils.NonTransactional) if err != nil { if err == utils.ErrNotFound { @@ -281,14 +278,11 @@ func (tS *ThresholdService) matchingThresholdsForEvent(args *ArgsProcessEvent) ( t.dirty = utils.BoolPointer(false) } t.tPrfl = tPrfl - matchingTs[tPrfl.ID] = t + ts = append(ts, t) } // All good, convert from Map to Slice so we can sort - ts = make(Thresholds, len(matchingTs)) - i := 0 - for _, t := range matchingTs { - ts[i] = t - i++ + if len(ts) == 0 { + return nil, utils.ErrNotFound } ts.Sort() for i, t := range ts { diff --git a/engine/z_filterindexer_it_test.go b/engine/z_filterindexer_it_test.go index cb33655acc..70681b368c 100644 --- a/engine/z_filterindexer_it_test.go +++ b/engine/z_filterindexer_it_test.go @@ -1114,13 +1114,27 @@ func testITIndexRateProfile(t *testing.T) { ID: "FIRST_GI", FilterIDs: []string{"*string:~*req.Category:call"}, Weight: 0, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.12, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Minute), + }, + }, + Blocker: false, }, "SECOND_GI": { ID: "SECOND_GI", FilterIDs: []string{"*string:~*req.Category:voice"}, Weight: 10, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.06, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Second), + }, + }, + Blocker: false, }, }, } @@ -1161,19 +1175,40 @@ func testITIndexRateProfile(t *testing.T) { ID: "FIRST_GI", FilterIDs: []string{"*string:~*req.Category:call"}, Weight: 0, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.12, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Minute), + }, + }, + Blocker: false, }, "SECOND_GI": { ID: "SECOND_GI", FilterIDs: []string{"*string:~*req.Category:voice"}, Weight: 10, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.06, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Second), + }, + }, + Blocker: false, }, "THIRD_GI": { ID: "THIRD_GI", FilterIDs: []string{"*string:~*req.Category:custom"}, Weight: 20, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.06, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Second), + }, + }, + Blocker: false, }, }, } @@ -1215,13 +1250,27 @@ func testITIndexRateProfile(t *testing.T) { ID: "CUSTOM_RATE1", FilterIDs: []string{"*string:~*req.Subject:1001"}, Weight: 0, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.12, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Minute), + }, + }, + Blocker: false, }, "CUSTOM_RATE2": { ID: "CUSTOM_RATE2", FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Category:call"}, Weight: 10, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.6, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Second), + }, + }, + Blocker: false, }, }, } diff --git a/engine/z_onstor_it_test.go b/engine/z_onstor_it_test.go index 5b26b76370..e584cee8a9 100644 --- a/engine/z_onstor_it_test.go +++ b/engine/z_onstor_it_test.go @@ -2162,13 +2162,27 @@ func testOnStorITRateProfile(t *testing.T) { ID: "FIRST_GI", FilterIDs: []string{"*gi:~*req.Usage:0"}, Weight: 0, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.12, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Minute), + }, + }, + Blocker: false, }, "SECOND_GI": &Rate{ ID: "SECOND_GI", FilterIDs: []string{"*gi:~*req.Usage:1m"}, Weight: 10, - Blocker: false, + IntervalRates: []*IntervalRate{ + &IntervalRate{ + Value: 0.06, + Unit: time.Duration(1 * time.Minute), + Increment: time.Duration(1 * time.Second), + }, + }, + Blocker: false, }, }, } diff --git a/rates/rates.go b/rates/rates.go index a146db1e0b..ad6050ec65 100644 --- a/rates/rates.go +++ b/rates/rates.go @@ -20,7 +20,6 @@ package rates import ( "fmt" - "sort" "time" "github.com/cgrates/cgrates/config" @@ -89,7 +88,6 @@ func (rS *RateS) matchingRateProfileForEvent(args *ArgsCostForEvent, rPfIDs []st } rPfIDs = rPfIDMp.AsSlice() } - matchingRPfs := make([]*engine.RateProfile, 0, len(rPfIDs)) evNm := utils.MapStorage{utils.MetaReq: args.CGREvent.Event} var sTime time.Time if sTime, err = args.StartTime(rS.cfg.GeneralCfg().DefaultTimezone); err != nil { @@ -115,15 +113,14 @@ func (rS *RateS) matchingRateProfileForEvent(args *ArgsCostForEvent, rPfIDs []st } else if !pass { continue } - matchingRPfs = append(matchingRPfs, rPf) + if rtPfl == nil || rtPfl.Weight < rPf.Weight { + rtPfl = rPf + } } - if len(matchingRPfs) == 0 { + if rtPfl == nil { return nil, utils.ErrNotFound } - sort.Slice(matchingRPfs, func(i, j int) bool { - return matchingRPfs[i].Weight > matchingRPfs[j].Weight - }) - rtPfl = matchingRPfs[0] + return }