diff --git a/cache/caches.go b/cache/caches.go new file mode 100644 index 000000000..9f403ba77 --- /dev/null +++ b/cache/caches.go @@ -0,0 +1,22 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package cache + +// CacheService is a central point of management for cache related tasks +type CacheService struct { +} diff --git a/cache/ficache.go b/cache/ficache.go new file mode 100644 index 000000000..b599d59cd --- /dev/null +++ b/cache/ficache.go @@ -0,0 +1,95 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package cache + +import ( + "sync" + + "github.com/cgrates/cgrates/utils" +) + +type filtersIndexer interface { + Index(itemIDs []string) (map[string]map[string]utils.StringMap, error) // Index items based on ID, nil for all +} + +func newFiCache() *fiCache { + return &fiCache{cache: make(map[string]map[string]map[string]utils.StringMap)} +} + +// FiCache is a cache handling filter indexing for various services +type fiCache struct { + cache map[string]map[string]map[string]utils.StringMap // map[serviceID]map[fieldName]map[fieldValue]utils.StringMap[itemID] + sync.RWMutex // protects cache + indexers map[string]filtersIndexer + indxrsMux sync.RWMutex // protects indexers +} + +func (fiCh *fiCache) registerIndexer(id string, idxr filtersIndexer) { // Not protected but also should + fiCh.indxrsMux.Lock() + fiCh.indexers[id] = idxr + fiCh.indxrsMux.Unlock() +} + +func (fiCh *fiCache) indexForIndexer(indxrID string, itemIDs []string) error { + fiCh.indxrsMux.RLock() + idxr, hasIt := fiCh.indexers[indxrID] + fiCh.indxrsMux.RUnlock() + if !hasIt { + return utils.ErrNotFound + } + newIndxMp, err := idxr.Index(itemIDs) + if err != nil { + return err + } + fiCh.Lock() + if _, hasIt := fiCh.indexers[indxrID]; !hasIt { + fiCh.cache[indxrID] = newIndxMp + return nil + } + // Merge old index cache with new one + for fldNameKey, mpFldName := range newIndxMp { + if _, hasIt := fiCh.cache[indxrID][fldNameKey]; !hasIt { + fiCh.cache[indxrID][fldNameKey] = mpFldName + } else { + for fldValKey, strMap := range mpFldName { + if _, hasIt := fiCh.cache[indxrID][fldNameKey][fldValKey]; !hasIt { + fiCh.cache[indxrID][fldNameKey][fldValKey] = strMap + } else { + for resIDKey := range strMap { + fiCh.cache[indxrID][fldNameKey][fldValKey][resIDKey] = true + } + } + } + } + } + fiCh.Unlock() + return nil +} + +// Empty the cache for specific indexers +func (fiCh *fiCache) flushForIndexers(indxrIDs []string) { + fiCh.Lock() + defer fiCh.Unlock() + if indxrIDs == nil { + fiCh.cache = make(map[string]map[string]map[string]utils.StringMap) + return + } + for _, indxID := range indxrIDs { + delete(fiCh.cache, indxID) + } +}