SMGeneric - improved session indexing considering runID, passive sessions with session prefix implementation

This commit is contained in:
DanB
2016-11-09 16:53:06 +01:00
parent b3dbf0daa9
commit c8750261eb
3 changed files with 391 additions and 178 deletions

View File

@@ -58,11 +58,11 @@ func NewSMGeneric(cgrCfg *config.CGRConfig, rals rpcclient.RpcClientConnection,
Timezone: timezone,
activeSessions: make(map[string][]*SMGSession),
aSessionsIdxCfg: aSessIdxCfg,
aSessionsIndex: make(map[string]map[string]utils.StringMap),
aSessionsIndex: make(map[string]map[string]map[string]utils.StringMap),
aSessionsRIndex: make(map[string][]*riFieldNameVal),
passiveSessions: make(map[string][]*SMGSession),
pSessionsIdxCfg: utils.StringMap{utils.ACCID: true},
pSessionsIndex: make(map[string]map[string]utils.StringMap),
pSessionsIndex: make(map[string]map[string]map[string]utils.StringMap),
pSessionsRIndex: make(map[string][]*riFieldNameVal),
sessionTerminators: make(map[string]*smgSessionTerminator),
responseCache: cache.NewResponseCache(cgrCfg.ResponseCacheTTL)}
@@ -76,24 +76,24 @@ type SMGeneric struct {
Timezone string
activeSessions map[string][]*SMGSession // group sessions per sessionId, multiple runs based on derived charging
aSessionsMux sync.RWMutex
aSessionsIdxCfg utils.StringMap // index configuration
aSessionsIndex map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue]utils.StringMap[cgrID]
aSessionsRIndex map[string][]*riFieldNameVal // reverse indexes for active sessions, used on remove
aSIMux sync.RWMutex // protects aSessionsIndex
passiveSessions map[string][]*SMGSession // group passive sessions
aSessionsIdxCfg utils.StringMap // index configuration
aSessionsIndex map[string]map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue][runID]utils.StringMap[cgrID]
aSessionsRIndex map[string][]*riFieldNameVal // reverse indexes for active sessions, used on remove
aSIMux sync.RWMutex // protects aSessionsIndex
passiveSessions map[string][]*SMGSession // group passive sessions
pSessionsMux sync.RWMutex
pSessionsIdxCfg utils.StringMap
pSessionsIndex map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue]utils.StringMap[cgrID]
pSessionsRIndex map[string][]*riFieldNameVal // reverse indexes for active sessions, used on remove
pSIMux sync.RWMutex // protects pSessionsIndex
sessionTerminators map[string]*smgSessionTerminator // terminate and cleanup the session if timer expires
sTsMux sync.Mutex // protects sessionTerminators
responseCache *cache.ResponseCache // cache replies here
pSessionsIndex map[string]map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue][runID]utils.StringMap[cgrID]
pSessionsRIndex map[string][]*riFieldNameVal // reverse indexes for active sessions, used on remove
pSIMux sync.RWMutex // protects pSessionsIndex
sessionTerminators map[string]*smgSessionTerminator // terminate and cleanup the session if timer expires
sTsMux sync.Mutex // protects sessionTerminators
responseCache *cache.ResponseCache // cache replies here
}
// riFieldNameVal is a reverse index entry
type riFieldNameVal struct {
fieldName, fieldValue string
runID, fieldName, fieldValue string
}
type smgSessionTerminator struct {
@@ -184,7 +184,7 @@ func (smg *SMGeneric) recordASession(s *SMGSession) {
smg.aSessionsMux.Lock()
smg.activeSessions[s.CGRID] = append(smg.activeSessions[s.CGRID], s)
smg.setSessionTerminator(s)
smg.indexASession(s)
smg.indexSession(s, false)
smg.aSessionsMux.Unlock()
}
@@ -199,15 +199,26 @@ func (smg *SMGeneric) unrecordASession(cgrID string) bool {
if st, found := smg.sessionTerminators[cgrID]; found {
st.endChan <- true
}
smg.unindexASession(cgrID)
smg.unindexSession(cgrID, false)
return true
}
// indexASession explores settings and builds smg.aSessionsIndex based on that
func (smg *SMGeneric) indexASession(s *SMGSession) bool {
smg.aSIMux.Lock()
defer smg.aSIMux.Unlock()
for fieldName := range smg.aSessionsIdxCfg {
// indexSession explores settings and builds SessionsIndex
// uses different tables and mutex-es depending on active/passive session
func (smg *SMGeneric) indexSession(s *SMGSession, passiveSessions bool) bool {
idxMux := smg.aSIMux
idxCfg := smg.aSessionsIdxCfg
ssIndx := smg.aSessionsIndex
ssRIdx := smg.aSessionsRIndex
if passiveSessions {
idxMux = smg.pSIMux
idxCfg = smg.pSessionsIdxCfg
ssIndx = smg.pSessionsIndex
ssRIdx = smg.pSessionsRIndex
}
idxMux.Lock()
defer idxMux.Unlock()
for fieldName := range idxCfg {
fieldVal, err := utils.ReflectFieldAsString(s.EventStart, fieldName, "")
if err != nil {
if err == utils.ErrNotFound {
@@ -220,115 +231,93 @@ func (smg *SMGeneric) indexASession(s *SMGSession) bool {
if fieldVal == "" {
fieldVal = utils.MetaEmpty
}
if _, hasFieldName := smg.aSessionsIndex[fieldName]; !hasFieldName { // Init it here so we can minimize
smg.aSessionsIndex[fieldName] = make(map[string]utils.StringMap)
if _, hasFieldName := ssIndx[fieldName]; !hasFieldName { // Init it here
ssIndx[fieldName] = make(map[string]map[string]utils.StringMap)
}
if _, hasFieldVal := smg.aSessionsIndex[fieldName][fieldVal]; !hasFieldVal {
smg.aSessionsIndex[fieldName][fieldVal] = make(utils.StringMap)
if _, hasFieldVal := ssIndx[fieldName][fieldVal]; !hasFieldVal {
ssIndx[fieldName][fieldVal] = make(map[string]utils.StringMap)
}
smg.aSessionsIndex[fieldName][fieldVal][s.CGRID] = true
if _, hasIt := smg.aSessionsRIndex[s.CGRID]; !hasIt {
smg.aSessionsRIndex[s.CGRID] = make([]*riFieldNameVal, 0)
if _, hasFieldVal := ssIndx[fieldName][fieldVal][s.RunID]; !hasFieldVal {
ssIndx[fieldName][fieldVal][s.RunID] = make(utils.StringMap)
}
smg.aSessionsRIndex[s.CGRID] = append(smg.aSessionsRIndex[s.CGRID], &riFieldNameVal{fieldName: fieldName, fieldValue: fieldVal})
ssIndx[fieldName][fieldVal][s.RunID][s.CGRID] = true
if _, hasIt := ssRIdx[s.CGRID]; !hasIt {
ssRIdx[s.CGRID] = make([]*riFieldNameVal, 0)
}
ssRIdx[s.CGRID] = append(ssRIdx[s.CGRID], &riFieldNameVal{runID: s.RunID, fieldName: fieldName, fieldValue: fieldVal})
}
return true
}
// unindexASession removes a session from indexes
func (smg *SMGeneric) unindexASession(cgrID string) bool {
smg.aSIMux.Lock()
defer smg.aSIMux.Unlock()
if _, hasIt := smg.aSessionsRIndex[cgrID]; !hasIt {
func (smg *SMGeneric) unindexSession(cgrID string, passiveSessions bool) bool {
idxMux := smg.aSIMux
ssRIdx := smg.aSessionsRIndex
ssIndx := smg.aSessionsIndex
if passiveSessions {
idxMux = smg.pSIMux
ssRIdx = smg.pSessionsRIndex
ssIndx = smg.pSessionsIndex
}
if _, hasIt := ssRIdx[cgrID]; !hasIt {
return false
}
for _, riFNV := range smg.aSessionsRIndex[cgrID] {
delete(smg.aSessionsIndex[riFNV.fieldName][riFNV.fieldValue], cgrID)
if len(smg.aSessionsIndex[riFNV.fieldName][riFNV.fieldValue]) == 0 {
delete(smg.aSessionsIndex[riFNV.fieldName], riFNV.fieldValue)
idxMux.Lock()
defer idxMux.Unlock()
for _, riFNV := range ssRIdx[cgrID] {
delete(ssIndx[riFNV.fieldName][riFNV.fieldValue][riFNV.runID], cgrID)
if len(ssIndx[riFNV.fieldName][riFNV.fieldValue][riFNV.runID]) == 0 {
delete(ssIndx[riFNV.fieldName][riFNV.fieldValue], riFNV.runID)
}
if len(smg.aSessionsIndex[riFNV.fieldName]) == 0 {
delete(smg.aSessionsIndex, riFNV.fieldName)
if len(ssIndx[riFNV.fieldName][riFNV.fieldValue]) == 0 {
delete(ssIndx[riFNV.fieldName], riFNV.fieldValue)
}
if len(ssIndx[riFNV.fieldName]) == 0 {
delete(ssIndx, riFNV.fieldName)
}
}
delete(smg.aSessionsRIndex, cgrID)
return true
}
// indexASession explores settings and builds smg.pSessionsIndex based on that
func (smg *SMGeneric) indexPSession(s *SMGSession) bool {
smg.pSIMux.Lock()
defer smg.pSIMux.Unlock()
for fieldName := range smg.pSessionsIdxCfg {
fieldVal, err := utils.ReflectFieldAsString(s.EventStart, fieldName, "")
if err != nil {
if err == utils.ErrNotFound {
fieldVal = utils.NOT_AVAILABLE
} else {
utils.Logger.Err(fmt.Sprintf("<SMGeneric> Error retrieving field: %s from event: %+v", fieldName, s.EventStart))
continue
}
}
if fieldVal == "" {
fieldVal = utils.MetaEmpty
}
if _, hasFieldName := smg.pSessionsIndex[fieldName]; !hasFieldName { // Init it here so we can minimize
smg.pSessionsIndex[fieldName] = make(map[string]utils.StringMap)
}
if _, hasFieldVal := smg.pSessionsIndex[fieldName][fieldVal]; !hasFieldVal {
smg.pSessionsIndex[fieldName][fieldVal] = make(utils.StringMap)
}
smg.pSessionsIndex[fieldName][fieldVal][s.CGRID] = true
smg.pSessionsRIndex[s.CGRID] = append(smg.pSessionsRIndex[s.CGRID], &riFieldNameVal{fieldName: fieldName, fieldValue: fieldVal})
}
return true
}
// unindexASession removes a session from indexes
func (smg *SMGeneric) unindexPSession(cgrID string) bool {
smg.pSIMux.Lock()
defer smg.pSIMux.Unlock()
if _, hasIt := smg.pSessionsRIndex[cgrID]; !hasIt {
return false
}
for _, riFNV := range smg.pSessionsRIndex[cgrID] {
delete(smg.pSessionsIndex[riFNV.fieldName][riFNV.fieldValue], cgrID)
if len(smg.pSessionsIndex[riFNV.fieldName][riFNV.fieldValue]) == 0 {
delete(smg.pSessionsIndex[riFNV.fieldName], riFNV.fieldValue)
}
if len(smg.pSessionsIndex[riFNV.fieldName]) == 0 {
delete(smg.pSessionsIndex, riFNV.fieldName)
}
}
delete(smg.pSessionsRIndex, cgrID)
delete(ssRIdx, cgrID)
return true
}
// getSessionIDsMatchingIndexes will check inside indexes if it can find sessionIDs matching all filters
// matchedIndexes returns map[matchedFieldName]possibleMatchedFieldVal so we optimize further to avoid checking them
func (smg *SMGeneric) getSessionIDsMatchingIndexes(fltrs map[string]string) (utils.StringMap, map[string]string) {
smg.aSIMux.RLock()
defer smg.aSIMux.RUnlock()
sessionIDxes := smg.aSessionsIndex // Clone here and unlock sooner if getting slow
func (smg *SMGeneric) getSessionIDsMatchingIndexes(fltrs map[string]string, passiveSessions bool) (utils.StringMap, map[string]string) {
idxMux := smg.aSIMux
ssIndx := smg.aSessionsIndex
if passiveSessions {
idxMux = smg.pSIMux
ssIndx = smg.pSessionsIndex
}
idxMux.RLock()
defer idxMux.RUnlock()
matchedIndexes := make(map[string]string)
var matchingSessions utils.StringMap
matchingSessions := make(utils.StringMap)
runID := fltrs[utils.MEDI_RUNID]
checkNr := 0
for fltrName, fltrVal := range fltrs {
checkNr += 1
if _, hasFldName := sessionIDxes[fltrName]; !hasFldName {
if _, hasFldName := ssIndx[fltrName]; !hasFldName {
continue
}
if _, hasFldVal := sessionIDxes[fltrName][fltrVal]; !hasFldVal {
if _, hasFldVal := ssIndx[fltrName][fltrVal]; !hasFldVal {
matchedIndexes[fltrName] = utils.META_NONE
continue
}
matchedIndexes[fltrName] = fltrVal
if checkNr == 1 { // First run will init the MatchingSessions
matchingSessions = sessionIDxes[fltrName][fltrVal]
if runID == "" {
for runID := range ssIndx[fltrName][fltrVal] {
matchingSessions.Join(ssIndx[fltrName][fltrVal][runID])
}
} else { // We know the RunID
matchingSessions = ssIndx[fltrName][fltrVal][runID]
}
continue
}
// Higher run, takes out non matching indexes
for cgrID := range sessionIDxes[fltrName][fltrVal] {
for cgrID := range ssIndx[fltrName][fltrVal] {
if _, hasCGRID := matchingSessions[cgrID]; !hasCGRID {
delete(matchingSessions, cgrID)
}
@@ -338,14 +327,20 @@ func (smg *SMGeneric) getSessionIDsMatchingIndexes(fltrs map[string]string) (uti
}
// getSessionIDsForPrefix works with session relocation returning list of sessions with ID matching prefix for OriginID field
func (smg *SMGeneric) getSessionIDsForPrefix(prefix string) (cgrIDs []string) {
smg.aSessionsMux.Lock()
defer smg.aSessionsMux.Unlock()
for originID := range smg.aSessionsIndex[utils.ACCID] {
func (smg *SMGeneric) getSessionIDsForPrefix(prefix string, passiveSessions bool) (cgrIDs []string) {
idxMux := smg.aSIMux
ssIndx := smg.aSessionsIndex
if passiveSessions {
idxMux = smg.pSIMux
ssIndx = smg.pSessionsIndex
}
idxMux.RLock()
for originID := range ssIndx[utils.ACCID][utils.META_DEFAULT] {
if strings.HasPrefix(originID, prefix) {
cgrIDs = append(cgrIDs, smg.aSessionsIndex[utils.ACCID][originID].Slice()...)
cgrIDs = append(cgrIDs, ssIndx[utils.ACCID][originID][utils.META_DEFAULT].Slice()...)
}
}
idxMux.RUnlock()
return
}
@@ -526,10 +521,10 @@ func (smg *SMGeneric) setPassiveSessions(cgrID string, ss []*SMGSession) (err er
smg.unrecordASession(cgrID)
smg.pSessionsMux.Lock()
smg.passiveSessions[cgrID] = ss
for _, s := range ss {
smg.indexPSession(s)
}
smg.pSessionsMux.Unlock()
for _, s := range ss {
smg.indexSession(s, true)
}
return
}
@@ -544,7 +539,7 @@ func (smg *SMGeneric) removePassiveSessions(cgrID string) (err error) {
return ErrActiveSession
}
}
smg.unrecordASession(cgrID)
smg.unrecordASession(cgrID) // just in case there is an active session
smg.deletePassiveSessions(cgrID)
return
}
@@ -552,8 +547,8 @@ func (smg *SMGeneric) removePassiveSessions(cgrID string) (err error) {
// deletePassiveSessions is used to remove a reference from the passiveSessions table
// ToDo: test it
func (smg *SMGeneric) deletePassiveSessions(cgrID string) {
smg.unindexSession(cgrID, true)
smg.pSessionsMux.Lock()
smg.unindexPSession(cgrID)
delete(smg.passiveSessions, cgrID)
smg.pSessionsMux.Unlock()
}
@@ -727,7 +722,12 @@ func (smg *SMGeneric) TerminateSession(gev SMGenericEvent, clnt rpcclient.RpcCli
sessionIDs := []string{cgrID}
if gev.HasField(utils.OriginIDPrefix) { // OriginIDPrefix is present, OriginID will not be anymore considered
if sessionIDPrefix, errPrefix := gev.GetFieldAsString(utils.OriginIDPrefix); errPrefix == nil {
sessionIDs = smg.getSessionIDsForPrefix(sessionIDPrefix)
if sessionIDs = smg.getSessionIDsForPrefix(sessionIDPrefix, false); len(sessionIDs) == 0 {
sessionIDs = smg.getSessionIDsForPrefix(sessionIDPrefix, true)
for _, sessionID := range sessionIDs { // activate sessions for prefix
smg.passiveToActive(sessionID)
}
}
}
}
usage, errUsage := gev.GetUsage(utils.META_DEFAULT)
@@ -905,7 +905,7 @@ func (smg *SMGeneric) getASessions() map[string][]*SMGSession {
func (smg *SMGeneric) ActiveSessions(fltrs map[string]string, count bool) (aSessions []*ActiveSession, counter int, err error) {
aSessions = make([]*ActiveSession, 0) // Make sure we return at least empty list and not nil
// Check first based on indexes so we can downsize the list of matching sessions
matchingSessionIDs, checkedFilters := smg.getSessionIDsMatchingIndexes(fltrs)
matchingSessionIDs, checkedFilters := smg.getSessionIDsMatchingIndexes(fltrs, false)
if len(matchingSessionIDs) == 0 && len(checkedFilters) != 0 {
return
}

View File

@@ -60,40 +60,63 @@ func TestSMGSessionIndexing(t *testing.T) {
"Extra3": "",
}
// Index first session
smgSession := &SMGSession{CGRID: smGev.GetCGRID(utils.META_DEFAULT), EventStart: smGev}
smgSession := &SMGSession{CGRID: smGev.GetCGRID(utils.META_DEFAULT), RunID: utils.META_DEFAULT, EventStart: smGev}
cgrID := smGev.GetCGRID(utils.META_DEFAULT)
smg.indexASession(smgSession)
eIndexes := map[string]map[string]utils.StringMap{
"OriginID": map[string]utils.StringMap{
"12345": utils.StringMap{
cgrID: true,
smg.indexSession(smgSession, false)
eIndexes := map[string]map[string]map[string]utils.StringMap{
"OriginID": map[string]map[string]utils.StringMap{
"12345": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
},
"Tenant": map[string]utils.StringMap{
"cgrates.org": utils.StringMap{
cgrID: true,
"Tenant": map[string]map[string]utils.StringMap{
"cgrates.org": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
},
"Account": map[string]utils.StringMap{
"account1": utils.StringMap{
cgrID: true,
"Account": map[string]map[string]utils.StringMap{
"account1": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
},
"Extra3": map[string]utils.StringMap{
utils.MetaEmpty: utils.StringMap{
cgrID: true,
"Extra3": map[string]map[string]utils.StringMap{
utils.MetaEmpty: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
},
"Extra4": map[string]utils.StringMap{
utils.NOT_AVAILABLE: utils.StringMap{
cgrID: true,
"Extra4": map[string]map[string]utils.StringMap{
utils.NOT_AVAILABLE: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
},
}
if !reflect.DeepEqual(eIndexes, smg.aSessionsIndex) {
t.Errorf("Expecting: %+v, received: %+v", eIndexes, smg.aSessionsIndex)
}
// Index seccond session
eRIdxes := map[string][]*riFieldNameVal{
cgrID: []*riFieldNameVal{
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Tenant", fieldValue: "cgrates.org"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Account", fieldValue: "account1"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra3", fieldValue: utils.MetaEmpty},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra4", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "OriginID", fieldValue: "12345"},
},
}
if len(eRIdxes) != len(smg.aSessionsRIndex) ||
len(eRIdxes[cgrID]) != len(smg.aSessionsRIndex[cgrID]) { // cannot keep order here due to field names coming from map
t.Errorf("Expecting: %+v, received: %+v", eRIdxes, smg.aSessionsRIndex)
}
// Index second session
smGev2 := SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT2",
utils.ACCID: "12346",
@@ -105,83 +128,265 @@ func TestSMGSessionIndexing(t *testing.T) {
"Extra4": "info2",
}
cgrID2 := smGev2.GetCGRID(utils.META_DEFAULT)
smgSession2 := &SMGSession{CGRID: smGev2.GetCGRID(utils.META_DEFAULT), EventStart: smGev2}
smg.indexASession(smgSession2)
eIndexes = map[string]map[string]utils.StringMap{
"OriginID": map[string]utils.StringMap{
"12345": utils.StringMap{
cgrID: true,
smgSession2 := &SMGSession{CGRID: smGev2.GetCGRID(utils.META_DEFAULT), RunID: utils.META_DEFAULT, EventStart: smGev2}
smg.indexSession(smgSession2, false)
smGev3 := SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT3",
utils.TENANT: "cgrates.org",
utils.ACCID: "12347",
utils.ACCOUNT: "account2",
"Extra5": "info5",
}
cgrID3 := smGev3.GetCGRID(utils.META_DEFAULT)
smgSession3 := &SMGSession{CGRID: smGev3.GetCGRID(utils.META_DEFAULT), RunID: "secondRun", EventStart: smGev3}
smg.indexSession(smgSession3, false)
eIndexes = map[string]map[string]map[string]utils.StringMap{
"OriginID": map[string]map[string]utils.StringMap{
"12345": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
"12346": utils.StringMap{
cgrID2: true,
"12346": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
"12347": map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Tenant": map[string]utils.StringMap{
"cgrates.org": utils.StringMap{
cgrID: true,
"Tenant": map[string]map[string]utils.StringMap{
"cgrates.org": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
"secondRun": utils.StringMap{
cgrID3: true,
},
},
"itsyscom.com": utils.StringMap{
cgrID2: true,
"itsyscom.com": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Account": map[string]utils.StringMap{
"account1": utils.StringMap{
cgrID: true,
"Account": map[string]map[string]utils.StringMap{
"account1": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
},
"account2": utils.StringMap{
cgrID2: true,
"account2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Extra3": map[string]utils.StringMap{
utils.MetaEmpty: utils.StringMap{
cgrID: true,
cgrID2: true,
"Extra3": map[string]map[string]utils.StringMap{
utils.MetaEmpty: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
cgrID2: true,
},
},
utils.NOT_AVAILABLE: map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Extra4": map[string]utils.StringMap{
utils.NOT_AVAILABLE: utils.StringMap{
cgrID: true,
"Extra4": map[string]map[string]utils.StringMap{
utils.NOT_AVAILABLE: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID: true,
},
"secondRun": utils.StringMap{
cgrID3: true,
},
},
"info2": utils.StringMap{
cgrID2: true,
"info2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
}
if !reflect.DeepEqual(eIndexes, smg.aSessionsIndex) {
t.Errorf("Expecting: %+v, received: %+v", eIndexes, smg.aSessionsIndex)
}
eRIdxes = map[string][]*riFieldNameVal{
cgrID: []*riFieldNameVal{
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Tenant", fieldValue: "cgrates.org"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Account", fieldValue: "account1"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra3", fieldValue: utils.MetaEmpty},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra4", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "OriginID", fieldValue: "12345"},
},
cgrID2: []*riFieldNameVal{
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Tenant", fieldValue: "itsyscom.com"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Account", fieldValue: "account2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra3", fieldValue: utils.MetaEmpty},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra4", fieldValue: "info2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "OriginID", fieldValue: "12346"},
},
cgrID3: []*riFieldNameVal{
&riFieldNameVal{runID: "secondRun", fieldName: "Tenant", fieldValue: "cgrates.org"},
&riFieldNameVal{runID: "secondRun", fieldName: "Account", fieldValue: "account2"},
&riFieldNameVal{runID: "secondRun", fieldName: "Extra3", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: "secondRun", fieldName: "Extra4", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: "secondRun", fieldName: "OriginID", fieldValue: "12347"},
},
}
if len(eRIdxes) != len(smg.aSessionsRIndex) ||
len(eRIdxes[cgrID]) != len(smg.aSessionsRIndex[cgrID]) ||
len(eRIdxes[cgrID2]) != len(smg.aSessionsRIndex[cgrID2]) { // cannot keep order here due to field names coming from map
t.Errorf("Expecting: %+v, received: %+v", eRIdxes, smg.aSessionsRIndex)
}
// Unidex first session
smg.unindexASession(cgrID)
eIndexes = map[string]map[string]utils.StringMap{
"OriginID": map[string]utils.StringMap{
"12346": utils.StringMap{
cgrID2: true,
smg.unindexSession(cgrID, false)
eIndexes = map[string]map[string]map[string]utils.StringMap{
"OriginID": map[string]map[string]utils.StringMap{
"12346": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
"12347": map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Tenant": map[string]utils.StringMap{
"itsyscom.com": utils.StringMap{
cgrID2: true,
"Tenant": map[string]map[string]utils.StringMap{
"cgrates.org": map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
"itsyscom.com": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Account": map[string]utils.StringMap{
"account2": utils.StringMap{
cgrID2: true,
"Account": map[string]map[string]utils.StringMap{
"account2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Extra3": map[string]utils.StringMap{
utils.MetaEmpty: utils.StringMap{
cgrID2: true,
"Extra3": map[string]map[string]utils.StringMap{
utils.MetaEmpty: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
utils.NOT_AVAILABLE: map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
"Extra4": map[string]utils.StringMap{
"info2": utils.StringMap{
cgrID2: true,
"Extra4": map[string]map[string]utils.StringMap{
"info2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
utils.NOT_AVAILABLE: map[string]utils.StringMap{
"secondRun": utils.StringMap{
cgrID3: true,
},
},
},
}
if !reflect.DeepEqual(eIndexes, smg.aSessionsIndex) {
t.Errorf("Expecting: %+v, received: %+v", eIndexes, smg.aSessionsIndex)
}
eRIdxes = map[string][]*riFieldNameVal{
cgrID2: []*riFieldNameVal{
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Tenant", fieldValue: "itsyscom.com"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Account", fieldValue: "account2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra3", fieldValue: utils.MetaEmpty},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra4", fieldValue: "info2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "OriginID", fieldValue: "12346"},
},
cgrID3: []*riFieldNameVal{
&riFieldNameVal{runID: "secondRun", fieldName: "Tenant", fieldValue: "cgrates.org"},
&riFieldNameVal{runID: "secondRun", fieldName: "Account", fieldValue: "account2"},
&riFieldNameVal{runID: "secondRun", fieldName: "Extra3", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: "secondRun", fieldName: "Extra4", fieldValue: utils.NOT_AVAILABLE},
&riFieldNameVal{runID: "secondRun", fieldName: "OriginID", fieldValue: "12347"},
},
}
if len(eRIdxes) != len(smg.aSessionsRIndex) ||
len(eRIdxes[cgrID2]) != len(smg.aSessionsRIndex[cgrID2]) { // cannot keep order here due to field names coming from map
t.Errorf("Expecting: %+v, received: %+v", eRIdxes, smg.aSessionsRIndex)
}
smg.unindexSession(cgrID3, false)
eIndexes = map[string]map[string]map[string]utils.StringMap{
"OriginID": map[string]map[string]utils.StringMap{
"12346": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Tenant": map[string]map[string]utils.StringMap{
"itsyscom.com": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Account": map[string]map[string]utils.StringMap{
"account2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Extra3": map[string]map[string]utils.StringMap{
utils.MetaEmpty: map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
"Extra4": map[string]map[string]utils.StringMap{
"info2": map[string]utils.StringMap{
utils.META_DEFAULT: utils.StringMap{
cgrID2: true,
},
},
},
}
if !reflect.DeepEqual(eIndexes, smg.aSessionsIndex) {
t.Errorf("Expecting: %+v, received: %+v", eIndexes, smg.aSessionsIndex)
}
eRIdxes = map[string][]*riFieldNameVal{
cgrID2: []*riFieldNameVal{
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Tenant", fieldValue: "itsyscom.com"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Account", fieldValue: "account2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra3", fieldValue: utils.MetaEmpty},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "Extra4", fieldValue: "info2"},
&riFieldNameVal{runID: utils.META_DEFAULT, fieldName: "OriginID", fieldValue: "12346"},
},
}
if len(eRIdxes) != len(smg.aSessionsRIndex) ||
len(eRIdxes[cgrID2]) != len(smg.aSessionsRIndex[cgrID2]) { // cannot keep order here due to field names coming from map
t.Errorf("Expecting: %+v, received: %+v", eRIdxes, smg.aSessionsRIndex)
}
}
func TestSMGActiveSessions(t *testing.T) {
@@ -209,7 +414,7 @@ func TestSMGActiveSessions(t *testing.T) {
"Extra2": 5,
"Extra3": "",
}
smg.recordASession(&SMGSession{CGRID: smGev1.GetCGRID(utils.META_DEFAULT), EventStart: smGev1})
smg.recordASession(&SMGSession{CGRID: smGev1.GetCGRID(utils.META_DEFAULT), RunID: utils.META_DEFAULT, EventStart: smGev1})
smGev2 := SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: "*voice",
@@ -230,21 +435,21 @@ func TestSMGActiveSessions(t *testing.T) {
"Extra1": "Value1",
"Extra3": "extra3",
}
smg.recordASession(&SMGSession{CGRID: smGev2.GetCGRID(utils.META_DEFAULT), EventStart: smGev2})
smg.recordASession(&SMGSession{CGRID: smGev2.GetCGRID(utils.META_DEFAULT), RunID: utils.META_DEFAULT, EventStart: smGev2})
if aSessions, _, err := smg.ActiveSessions(nil, false); err != nil {
t.Error(err)
} else if len(aSessions) != 2 {
t.Errorf("Received sessions: %%+v", aSessions)
t.Errorf("Received sessions: %+v", aSessions)
}
if aSessions, _, err := smg.ActiveSessions(map[string]string{"Tenant": "itsyscom.com"}, false); err != nil {
t.Error(err)
} else if len(aSessions) != 1 {
t.Errorf("Received sessions: %%+v", aSessions)
t.Errorf("Received sessions: %+v", aSessions)
}
if aSessions, _, err := smg.ActiveSessions(map[string]string{utils.TOR: "*voice"}, false); err != nil {
t.Error(err)
} else if len(aSessions) != 2 {
t.Errorf("Received sessions: %%+v", aSessions)
t.Errorf("Received sessions: %+v", aSessions)
}
if aSessions, _, err := smg.ActiveSessions(map[string]string{"Extra3": utils.MetaEmpty}, false); err != nil {
t.Error(err)

View File

@@ -164,6 +164,14 @@ func (sm StringMap) GetOne() string {
return ""
}
func (sm StringMap) Join(mps ...StringMap) {
for _, mp := range mps {
for k, v := range mp {
sm[k] = v
}
}
}
/*
func NoDots(m map[string]struct{}) map[string]struct{} {
return MapKeysReplace(m, ".", "")