diff --git a/engine/lcr.go b/engine/lcr.go index cdab45627..653bcbf1e 100644 --- a/engine/lcr.go +++ b/engine/lcr.go @@ -20,6 +20,7 @@ package engine import ( "fmt" + "math/rand" "sort" "strconv" "strings" @@ -37,6 +38,12 @@ const ( LCR_STRATEGY_QOS_THRESHOLD = "*qos_threshold" LCR_STRATEGY_QOS = "*qos" LCR_STRATEGY_LOAD = "*load_distribution" + + // used for load distribution sorting + RAND_LIMIT = 99 + LOW_PRIORITY_LIMIT = 100 + MED_PRIORITY_LIMIT = 200 + HIGH_PRIORITY_LIMIT = 300 ) // A request for LCR, used in APIer and SM where we need to expose it @@ -295,6 +302,7 @@ func (lc *LCRCost) Sort() { sort.Sort(QOSSorter(lc.SupplierCosts)) case LCR_STRATEGY_LOAD: lc.SortLoadDistribution() + sort.Sort(HighestSupplierCostSorter(lc.SupplierCosts)) } } @@ -317,11 +325,11 @@ func (lc *LCRCost) SortLoadDistribution() { } } } - supplierQueues := make(map[string]*StatsQueue) + supplierQueues := make(map[*LCRSupplierCost]*StatsQueue) for _, supCost := range lc.SupplierCosts { for _, sq := range supCost.supplierQueues { if sq.conf.TimeWindow == winnerTimeWindow { - supplierQueues[supCost.Supplier] = sq + supplierQueues[supCost] = sq break } } @@ -333,13 +341,29 @@ func (lc *LCRCost) SortLoadDistribution() { // if some have a cdr count not divisible by ponder return them first and all ordered by cdr times, oldest first // if all have a multiple of ponder return in the order of cdr times, oldest first + // first put them in one of the above categories + for supCost, sq := range supplierQueues { + ponder := lc.GetSupplierPonder(supCost.Supplier) + cdrCount := len(sq.Cdrs) + if cdrCount < ponder { + supCost.Cost = float64(LOW_PRIORITY_LIMIT + rand.Intn(RAND_LIMIT)) + continue + } + if cdrCount%ponder == 0 { + supCost.Cost = float64(MED_PRIORITY_LIMIT+rand.Intn(RAND_LIMIT)) + time.Now().Sub(sq.Cdrs[len(sq.Cdrs)-1].SetupTime).Seconds() + continue + } else { + supCost.Cost = float64(HIGH_PRIORITY_LIMIT+rand.Intn(RAND_LIMIT)) + time.Now().Sub(sq.Cdrs[len(sq.Cdrs)-1].SetupTime).Seconds() + continue + } + } } // used in load distribution strategy only // receives a long supplier id and will return the ponder found in strategy params -func (lc *LCRCost) GetSupplierPonder(supplier string) float64 { +func (lc *LCRCost) GetSupplierPonder(supplier string) int { // parse strategy params - ponders := make(map[string]float64) + ponders := make(map[string]int) params := strings.Split(lc.Entry.StrategyParams, utils.INFIELD_SEP) for _, param := range params { ponderSlice := strings.Split(param, utils.CONCATENATED_KEY_SEP) @@ -347,7 +371,7 @@ func (lc *LCRCost) GetSupplierPonder(supplier string) float64 { Logger.Warning(fmt.Sprintf("bad format in load distribution strategy param: %s", lc.Entry.StrategyParams)) continue } - p, err := strconv.ParseFloat(ponderSlice[1], 64) + p, err := strconv.Atoi(ponderSlice[1]) if err != nil { Logger.Warning(fmt.Sprintf("bad format in load distribution strategy param: %s", lc.Entry.StrategyParams)) continue diff --git a/engine/lcr_test.go b/engine/lcr_test.go index 847eefbda..4ecb1d8bc 100644 --- a/engine/lcr_test.go +++ b/engine/lcr_test.go @@ -280,6 +280,7 @@ func TestLCRCostSuppliersString(t *testing.T) { } func TestLCRCostSuppliersLoad(t *testing.T) { + setupTime := time.Date(2015, 7, 31, 6, 43, 0, 0, time.UTC) lcrCost := &LCRCost{ Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_LOAD, StrategyParams: "ivo12:10;dan12:3;*default:7", Weight: 10.0}, SupplierCosts: []*LCRSupplierCost{ @@ -287,21 +288,21 @@ func TestLCRCostSuppliersLoad(t *testing.T) { Supplier: "*out:tenant12:call:ivo12", supplierQueues: []*StatsQueue{ &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 3 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 1 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, @@ -313,21 +314,21 @@ func TestLCRCostSuppliersLoad(t *testing.T) { Supplier: "*out:tenant12:call:dan12", supplierQueues: []*StatsQueue{ &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, @@ -339,28 +340,28 @@ func TestLCRCostSuppliersLoad(t *testing.T) { Supplier: "*out:tenant12:call:rif12", supplierQueues: []*StatsQueue{ &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, }, }, &StatsQueue{ - Cdrs: []*QCdr{&QCdr{}, &QCdr{}}, + Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 1 * time.Minute, @@ -374,6 +375,6 @@ func TestLCRCostSuppliersLoad(t *testing.T) { if lcrCost.SupplierCosts[0].Supplier != "" || lcrCost.SupplierCosts[1].Supplier != "" || lcrCost.SupplierCosts[2].Supplier != "" { - //t.Error("Error soring on load distribution: ", utils.ToIJSON(lcrCost)) + t.Error("Error soring on load distribution: ", utils.ToIJSON(lcrCost)) } }