[VOL-4532] Remove duplicate maps in FlowManager and ResourceManager

Change-Id: I0a0fee7dbd3b3a25f2f0eee062bf565ba3212df3
diff --git a/internal/pkg/resourcemanager/resourcemanager.go b/internal/pkg/resourcemanager/resourcemanager.go
index 476bbf5..cfc755e 100755
--- a/internal/pkg/resourcemanager/resourcemanager.go
+++ b/internal/pkg/resourcemanager/resourcemanager.go
@@ -244,7 +244,9 @@
 	}
 
 	ResourceMgr.InitLocalCache()
-
+	if err := ResourceMgr.LoadLocalCacheFromKVStore(ctx, PonIntfID); err != nil {
+		logger.Error(ctx, "failed-to-load-local-cache-from-kvstore")
+	}
 	logger.Info(ctx, "Initialization of  resource manager success!")
 	return &ResourceMgr
 }
@@ -263,6 +265,52 @@
 	rsrcMgr.groupInfo = make(map[string]*GroupInfo)
 }
 
+//LoadLocalCacheFromKVStore loads local maps
+func (rsrcMgr *OpenOltResourceMgr) LoadLocalCacheFromKVStore(ctx context.Context, PonIntfID uint32) error {
+
+	//List all the keys for OnuGemInfo
+	prefixPath := fmt.Sprintf(OnuGemInfoPathPathPrefix, PonIntfID)
+	keys, err := rsrcMgr.KVStore.List(ctx, prefixPath)
+	logger.Debug(ctx, "load-local-cache-from-KV-store-started")
+	if err != nil {
+		logger.Errorf(ctx, "failed-to-list-keys-from-path-%s", prefixPath)
+		return err
+	}
+	for path := range keys {
+		var Val []byte
+		var onugem OnuGemInfo
+		// Get rid of the path prefix
+		stringToBeReplaced := rsrcMgr.KVStore.PathPrefix + "/"
+		replacedWith := ""
+		path = strings.Replace(path, stringToBeReplaced, replacedWith, 1)
+
+		value, err := rsrcMgr.KVStore.Get(ctx, path)
+		if err != nil {
+			logger.Errorw(ctx, "failed-to-get-from-kv-store", log.Fields{"path": path})
+			return err
+		} else if value == nil {
+			logger.Debug(ctx, "no-onugeminfo-for-path", log.Fields{"path": path})
+			continue
+		}
+		if Val, err = kvstore.ToByte(value.Value); err != nil {
+			logger.Error(ctx, "failed-to-covert-to-byte-array")
+			return err
+		}
+		if err = json.Unmarshal(Val, &onugem); err != nil {
+			logger.Error(ctx, "failed-to-unmarshall")
+			return err
+		}
+		logger.Debugw(ctx, "found-onugeminfo-from-path", log.Fields{"path": path, "onuGemInfo": onugem})
+
+		rsrcMgr.onuGemInfoLock.Lock()
+		rsrcMgr.onuGemInfo[path] = &onugem
+		rsrcMgr.onuGemInfoLock.Unlock()
+
+	}
+	logger.Debug(ctx, "load-local-cache-from-KV-store-finished")
+	return nil
+}
+
 // InitializeDeviceResourceRangeAndPool initializes the resource range pool according to the sharing type, then apply
 // device specific information. If KV doesn't exist
 // or is broader than the device, the device's information will
@@ -948,6 +996,36 @@
 	return &onugem, nil
 }
 
+//AddNewOnuGemInfoToCacheAndKvStore function adds a new  onu gem info to cache and kvstore
+func (rsrcMgr *OpenOltResourceMgr) AddNewOnuGemInfoToCacheAndKvStore(ctx context.Context, intfID uint32, onuID uint32, serialNum string) error {
+
+	Path := fmt.Sprintf(OnuGemInfoPath, intfID, onuID)
+
+	rsrcMgr.onuGemInfoLock.Lock()
+	_, ok := rsrcMgr.onuGemInfo[Path]
+	rsrcMgr.onuGemInfoLock.Unlock()
+
+	// If the ONU already exists in onuGemInfo list, nothing to do
+	if ok {
+		logger.Debugw(ctx, "onu-id-already-exists-in-cache", log.Fields{"onuID": onuID, "serialNum": serialNum})
+		return nil
+	}
+
+	onuGemInfo := OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
+
+	if err := rsrcMgr.AddOnuGemInfo(ctx, intfID, onuID, onuGemInfo); err != nil {
+		return err
+	}
+	logger.Infow(ctx, "added-onuinfo",
+		log.Fields{
+			"intf-id":    intfID,
+			"onu-id":     onuID,
+			"serial-num": serialNum,
+			"onu":        onuGemInfo,
+			"device-id":  rsrcMgr.DeviceID})
+	return nil
+}
+
 // AddOnuGemInfo adds onu info on to the kvstore per interface
 func (rsrcMgr *OpenOltResourceMgr) AddOnuGemInfo(ctx context.Context, intfID uint32, onuID uint32, onuGem OnuGemInfo) error {
 
@@ -965,7 +1043,7 @@
 		logger.Errorf(ctx, "Failed to update resource %s", Path)
 		return err
 	}
-	logger.Debugw(ctx, "added onu gem info to store", log.Fields{"onuGemInfo": onuGem})
+	logger.Debugw(ctx, "added onu gem info to store", log.Fields{"onuGemInfo": onuGem, "Path": Path})
 
 	//update cache
 	rsrcMgr.onuGemInfoLock.Lock()
@@ -1173,6 +1251,34 @@
 	return flowIDs, nil
 }
 
+// IsGemPortUsedByAnotherFlow returns true if given gem is used by another flow
+func (rsrcMgr *OpenOltResourceMgr) IsGemPortUsedByAnotherFlow(gemPortID uint32, flowID uint64) bool {
+	rsrcMgr.flowIDsForGemLock.RLock()
+	flowIDList := rsrcMgr.flowIDsForGem[gemPortID]
+	rsrcMgr.flowIDsForGemLock.RUnlock()
+	for _, id := range flowIDList {
+		if flowID != id {
+			return true
+		}
+	}
+	return false
+}
+
+// RegisterFlowIDForGem updates both cache and KV store for flowIDsForGem map
+func (rsrcMgr *OpenOltResourceMgr) RegisterFlowIDForGem(ctx context.Context, accessIntfID uint32, gemPortID uint32, flowFromCore *ofp.OfpFlowStats) error {
+	// get from cache
+	rsrcMgr.flowIDsForGemLock.RLock()
+	flowIDs, ok := rsrcMgr.flowIDsForGem[gemPortID]
+	rsrcMgr.flowIDsForGemLock.RUnlock()
+	if !ok {
+		flowIDs = []uint64{flowFromCore.Id}
+	} else {
+		flowIDs = appendUnique64bit(flowIDs, flowFromCore.Id)
+	}
+	// update the flowids for a gem to the KVstore
+	return rsrcMgr.UpdateFlowIDsForGem(ctx, accessIntfID, gemPortID, flowIDs)
+}
+
 //UpdateFlowIDsForGem updates flow id per gemport
 func (rsrcMgr *OpenOltResourceMgr) UpdateFlowIDsForGem(ctx context.Context, intf uint32, gem uint32, flowIDs []uint64) error {
 	var val []byte
@@ -1424,6 +1530,17 @@
 	return false, groupInfo, nil
 }
 
+// GetOnuGemInfoList returns all gems in the onuGemInfo map
+func (rsrcMgr *OpenOltResourceMgr) GetOnuGemInfoList(ctx context.Context) []OnuGemInfo {
+	var onuGemInfoLst []OnuGemInfo
+	rsrcMgr.onuGemInfoLock.RLock()
+	defer rsrcMgr.onuGemInfoLock.RUnlock()
+	for _, v := range rsrcMgr.onuGemInfo {
+		onuGemInfoLst = append(onuGemInfoLst, *v)
+	}
+	return onuGemInfoLst
+}
+
 // toByte converts an interface value to a []byte.  The interface should either be of
 // a string type or []byte.  Otherwise, an error is returned.
 func toByte(value interface{}) ([]byte, error) {
@@ -1436,3 +1553,12 @@
 		return nil, fmt.Errorf("unexpected-type-%T", t)
 	}
 }
+
+func appendUnique64bit(slice []uint64, item uint64) []uint64 {
+	for _, sliceElement := range slice {
+		if sliceElement == item {
+			return slice
+		}
+	}
+	return append(slice, item)
+}