From ffef415e8cb2578aedfbb12fdb73c9454ba3e2c2 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 5 Feb 2020 18:11:23 +0200 Subject: [PATCH] Added cache for EventCost.FieldAsInterface --- engine/cdr.go | 9 +++---- engine/cdr_test.go | 6 ++--- engine/eventcost.go | 49 ++++++++++++++++++++++++++++++++++ engine/eventcost_test.go | 2 ++ engine/filters_test.go | 3 +-- engine/responder_test.go | 1 + engine/storage_mongo_stordb.go | 2 ++ engine/storage_sql.go | 2 ++ 8 files changed, 63 insertions(+), 11 deletions(-) diff --git a/engine/cdr.go b/engine/cdr.go index ed944710a..985b2c277 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -60,6 +60,7 @@ func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { if err = json.Unmarshal([]byte(extCdr.CostDetails), cdr.CostDetails); err != nil { return nil, err } + cdr.CostDetails.initCache() } if extCdr.ExtraFields != nil { cdr.ExtraFields = make(map[string]string) @@ -156,7 +157,7 @@ func (cdr *CDR) FieldAsString(rsrPrs *config.RSRParser) (parsed string, err erro config.NewNavigableMap(map[string]interface{}{ utils.MetaReq: cdr.AsMapStringIface(), utils.MetaEC: cdr.CostDetails, - }), utils.NestingSep) + }), utils.NestingSep) if err != nil { return } @@ -169,7 +170,7 @@ func (cdr *CDR) FieldsAsString(rsrFlds config.RSRParsers) string { config.NewNavigableMap(map[string]interface{}{ utils.MetaReq: cdr.AsMapStringIface(), utils.MetaEC: cdr.CostDetails, - }), utils.NestingSep) + }), utils.NestingSep) if err != nil { return "" } @@ -242,9 +243,7 @@ func (cdr *CDR) AsMapStringIface() (mp map[string]interface{}) { mp[utils.CostSource] = cdr.CostSource mp[utils.Cost] = cdr.Cost if cdr.CostDetails != nil { - var result map[string]interface{} - json.Unmarshal([]byte(utils.ToJSON(cdr.CostDetails)), &result) - mp[utils.CostDetails] = result + mp[utils.CostDetails] = cdr.CostDetails } return } diff --git a/engine/cdr_test.go b/engine/cdr_test.go index a90ea7128..6d43facaf 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -18,7 +18,6 @@ along with this program. If not, see package engine import ( - "encoding/json" "reflect" "strconv" "testing" @@ -489,6 +488,7 @@ func TestCdrClone(t *testing.T) { Cost: utils.Float64Pointer(0.74), }, } + eOut.CostDetails.initCache() if rcv := cdr.Clone(); !reflect.DeepEqual(rcv, eOut) { t.Errorf("Expecting: %+v,\n received: %+v", eOut, rcv) } @@ -579,8 +579,6 @@ func TestCDRTestCDRAsMapStringIface2(t *testing.T) { CostDetails: NewEventCostFromCallCost(cc, "TestCDRTestCDRAsMapStringIface2", utils.MetaDefault), } - var result map[string]interface{} - json.Unmarshal([]byte(utils.ToJSON(cdr.CostDetails)), &result) mp := map[string]interface{}{ "field_extr1": "val_extr1", "fieldextr2": "valextr2", @@ -605,7 +603,7 @@ func TestCDRTestCDRAsMapStringIface2(t *testing.T) { utils.PreRated: false, utils.Partial: false, utils.ExtraInfo: cdr.ExtraInfo, - utils.CostDetails: result, + utils.CostDetails: cdr.CostDetails, } if cdrMp := cdr.AsMapStringIface(); !reflect.DeepEqual(mp, cdrMp) { t.Errorf("Expecting: %+v, received: %+v", mp, cdrMp) diff --git a/engine/eventcost.go b/engine/eventcost.go index 116090a31..9fcbbb2d9 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -37,6 +37,7 @@ func NewBareEventCost() *EventCost { Rates: make(ChargedRates), Timings: make(ChargedTimings), Charges: make([]*ChargingInterval, 0), + cache: config.NewNavigableMap(nil), } } @@ -117,6 +118,14 @@ type EventCost struct { RatingFilters RatingFilters Rates ChargedRates Timings ChargedTimings + + cache *config.NavigableMap +} + +func (ec *EventCost) initCache() { + if ec != nil { + ec.cache = config.NewNavigableMap(nil) + } } func (ec *EventCost) ratingIDForRateInterval(ri *RateInterval, rf RatingMatchedFilters) string { @@ -180,6 +189,7 @@ func (ec *EventCost) Clone() (cln *EventCost) { return } cln = new(EventCost) + cln.initCache() cln.CGRID = ec.CGRID cln.RunID = ec.RunID cln.StartTime = ec.StartTime @@ -845,6 +855,27 @@ func (ec *EventCost) FieldAsInterface(fldPath []string) (val interface{}, err er if len(fldPath) == 0 { return nil, utils.ErrNotFound } + if val, err = ec.cache.FieldAsInterface(fldPath); err != nil { + if err != utils.ErrNotFound { // item found in cache + return + } + err = nil // cancel previous err + } else if val == nil { + return nil, utils.ErrNotFound + } else { + return // data found in cache + } + val, err = ec.fieldAsInterface(fldPath) + if err == nil { + ec.cache.Set(fldPath, val, false, false) + } else if err == utils.ErrNotFound { + ec.cache.Set(fldPath, nil, false, false) + } + return +} + +// FieldAsInterface the implementation of FieldAsInterface +func (ec *EventCost) fieldAsInterface(fldPath []string) (val interface{}, err error) { switch fldPath[0] { default: // "Charges[1]" opath, indx := utils.GetPathIndex(fldPath[0]) @@ -888,16 +919,34 @@ func (ec *EventCost) FieldAsInterface(fldPath []string) (val interface{}, err er } return ec.Cost, nil case utils.AccountSummary: + if len(fldPath) == 1 { + return ec.AccountSummary, nil + } return ec.AccountSummary.FieldAsInterface(fldPath[1:]) case utils.Timings: + if len(fldPath) == 1 { + return ec.Timings, nil + } return ec.Timings.FieldAsInterface(fldPath[1:]) case utils.Rates: + if len(fldPath) == 1 { + return ec.Rates, nil + } return ec.Rates.FieldAsInterface(fldPath[1:]) case utils.RatingFilters: + if len(fldPath) == 1 { + return ec.RatingFilters, nil + } return ec.RatingFilters.FieldAsInterface(fldPath[1:]) case utils.Accounting: + if len(fldPath) == 1 { + return ec.Accounting, nil + } return ec.Accounting.FieldAsInterface(fldPath[1:]) case utils.Rating: + if len(fldPath) == 1 { + return ec.Rating, nil + } return ec.Rating.FieldAsInterface(fldPath[1:]) } return nil, fmt.Errorf("unsupported field prefix: <%s>", fldPath[0]) diff --git a/engine/eventcost_test.go b/engine/eventcost_test.go index 8c0b0f447..257702daa 100644 --- a/engine/eventcost_test.go +++ b/engine/eventcost_test.go @@ -204,6 +204,7 @@ var testEC = &EventCost{ StartTime: "00:00:00", }, }, + cache: config.NewNavigableMap(nil), } func TestECClone(t *testing.T) { @@ -2514,6 +2515,7 @@ func TestECSyncKeys(t *testing.T) { StartTime: "00:00:00", }, }, + cache: config.NewNavigableMap(nil), } ec.SyncKeys(refEC) diff --git a/engine/filters_test.go b/engine/filters_test.go index e53f2adf1..b00e7d9a3 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -1019,7 +1019,6 @@ func TestPassFilterMissingField(t *testing.T) { } func TestEventCostFilter(t *testing.T) { - cfg, _ := config.NewDefaultCGRConfig() data := NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items) dmFilterPass := NewDataManager(data, config.CgrConfig().CacheCfg(), nil) @@ -1153,7 +1152,7 @@ func TestEventCostFilter(t *testing.T) { }, }, } - + cd.initCache() cgrDp := config.NewNavigableMap(map[string]interface{}{utils.MetaEC: cd}) if pass, err := filterS.Pass("cgrates.org", diff --git a/engine/responder_test.go b/engine/responder_test.go index 413811025..2f86a8964 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -124,6 +124,7 @@ func TestResponderGobSMCost(t *testing.T) { if err != nil { t.Error("decode error: ", err) } + q.Cost.CostDetails.initCache() if !reflect.DeepEqual(attr, q) { t.Error("wrong transmission") } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 0993ac9d8..b121341bd 100644 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -906,6 +906,7 @@ func (ms *MongoStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix stri return err } clone := smCost + clone.CostDetails.initCache() smcs = append(smcs, &clone) } if len(smcs) == 0 { @@ -1165,6 +1166,7 @@ func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, return err } clone := cdr + clone.CostDetails.initCache() cdrs = append(cdrs, &clone) } if len(cdrs) == 0 { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index c5c8cb4a0..4ec7299a6 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -863,6 +863,7 @@ func (self *SQLStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix stri if err := json.Unmarshal([]byte(result.CostDetails), smc.CostDetails); err != nil { return nil, err } + smc.CostDetails.initCache() smCosts = append(smCosts, smc) } if len(smCosts) == 0 { @@ -1158,6 +1159,7 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, if cdr, err := NewCDRFromSQL(result); err != nil { return nil, 0, err } else { + cdr.CostDetails.initCache() cdrs = append(cdrs, cdr) } }