From 2c8cf6fbc0e7bf5b79a3bdb6a11d447800d4a1de Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 20 Sep 2016 18:26:15 +0200 Subject: [PATCH] SMGeneric with storeSMCost separately and goroutine only for large timespans --- engine/callcost.go | 1 - engine/timespans.go | 22 ++++++++-------------- sessionmanager/smg_session.go | 26 +++++++++++++++++++++----- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/engine/callcost.go b/engine/callcost.go index c04b53ca2..5e4ee8c75 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -29,7 +29,6 @@ type CallCost struct { Direction, Category, Tenant, Subject, Account, Destination, TOR string Cost float64 Timespans TimeSpans - TimespansMerged bool RatedUsage float64 deductConnectFee bool negativeConnectFee bool // the connect fee went negative on default balance diff --git a/engine/timespans.go b/engine/timespans.go index caedf35f1..4d18af209 100644 --- a/engine/timespans.go +++ b/engine/timespans.go @@ -260,20 +260,14 @@ func (tss *TimeSpans) Decompress() { // must be pointer receiver func (tss *TimeSpans) Merge() { // Merge whenever possible tssVal := *tss - - if len(tssVal) > 2 { - - middle := len(tssVal) / 2 - - tssVal1 := tssVal[:middle] - tssVal2 := tssVal[middle:] - - tssVal1.Merge() - tssVal2.Merge() - - tssVal = append(tssVal1, tssVal2 ...) - } - + if len(tssVal) > 2 { // Optimization for faster merge + middle := len(tssVal) / 2 + tssVal1 := tssVal[:middle] + tssVal2 := tssVal[middle:] + tssVal1.Merge() + tssVal2.Merge() + tssVal = append(tssVal1, tssVal2...) + } for i := 1; i < len(tssVal); i++ { if tssVal[i-1].Merge(tssVal[i]) { tssVal = append(tssVal[:i], tssVal[i+1:]...) diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index 0eb2665fc..6bad4956c 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -253,11 +253,6 @@ func (self *SMGSession) saveOperations(originID string) error { return err } } - if len(cc.Timespans) > 50 { // Merge since we will get a callCost too big - cc.Timespans.Decompress() - cc.Timespans.Merge() // Here we could wait a while depending on the size of the timespans - cc.Timespans.Compress() - } smCost := &engine.SMCost{ CGRID: self.eventStart.GetCgrId(self.timezone), CostSource: utils.SESSION_MANAGER_SOURCE, @@ -267,6 +262,27 @@ func (self *SMGSession) saveOperations(originID string) error { Usage: self.TotalUsage().Seconds(), CostDetails: cc, } + if len(smCost.CostDetails.Timespans) > MaxTimespansInCost { // Merge since we will get a callCost too big + if err := utils.Clone(cc, &smCost.CostDetails); err != nil { // Avoid concurrency on CC + utils.Logger.Err(fmt.Sprintf(" Could not clone callcost for sessionID: %s, runId: %s, error: %s", originID, self.runId, err.Error())) + } + go func(smCost *engine.SMCost) { // could take longer than the locked stage + if err := self.storeSMCost(smCost); err != nil { + utils.Logger.Err(fmt.Sprintf(" Could not store callcost for sessionID: %s, runId: %s, error: %s", originID, self.runId, err.Error())) + } + }(smCost) + } else { + return self.storeSMCost(smCost) + } + return nil +} + +func (self *SMGSession) storeSMCost(smCost *engine.SMCost) error { + if len(smCost.CostDetails.Timespans) > MaxTimespansInCost { // Merge so we can compress the CostDetails + smCost.CostDetails.Timespans.Decompress() + smCost.CostDetails.Timespans.Merge() + smCost.CostDetails.Timespans.Compress() + } var reply string if err := self.cdrsrv.Call("CdrsV1.StoreSMCost", engine.AttrCDRSStoreSMCost{Cost: smCost, CheckDuplicate: true}, &reply); err != nil { if err == utils.ErrExists {