[VOL-5594] Reduce the number of kvstore clients

Change-Id: I8e8aafd5a613a65d919e7284ab563af0a0b1d942
Signed-off-by: Abhay Kumar <abhay.kumar@radisys.com>
diff --git a/VERSION b/VERSION
index bd8d6d4..3fe624e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.8.7
+7.9.1
diff --git a/pkg/ponresourcemanager/ponresourcemanager.go b/pkg/ponresourcemanager/ponresourcemanager.go
index 0eec452..0008e00 100755
--- a/pkg/ponresourcemanager/ponresourcemanager.go
+++ b/pkg/ponresourcemanager/ponresourcemanager.go
@@ -192,6 +192,10 @@
 	return kvbackend
 }
 
+// CloseKVClient closes the KV store connections held by this manager.
+// Note: The KV backends may be shared with other managers (e.g., TechProfileMgr).
+// The nil check and nil assignment ensure that duplicate close calls are safe —
+// once closed by one manager, the other will see nil and skip closing.
 func (PONRMgr *PONResourceManager) CloseKVClient(ctx context.Context) {
 	if PONRMgr.KVStore != nil {
 		PONRMgr.KVStore.Client.Close(ctx)
@@ -204,20 +208,20 @@
 }
 
 // NewPONResourceManager creates a new PON resource manager.
-func NewPONResourceManager(ctx context.Context, Technology string, DeviceType string, DeviceID string, Backend string, Address string, basePathKvStore string) (*PONResourceManager, error) {
+func NewPONResourceManager(ctx context.Context, Technology string, DeviceType string, DeviceID string, Backend string, Address string, basePathKvStore string, ponrsrcmgr *db.Backend, ponmgrTech *db.Backend) (*PONResourceManager, error) {
 	var PONMgr PONResourceManager
 	PONMgr.Technology = Technology
 	PONMgr.DeviceType = DeviceType
 	PONMgr.DeviceID = DeviceID
 	PONMgr.Backend = Backend
 	PONMgr.Address = Address
-	PONMgr.KVStore = SetKVClient(ctx, Technology, Backend, Address, false, basePathKvStore)
+	PONMgr.KVStore = ponrsrcmgr
 	if PONMgr.KVStore == nil {
 		logger.Error(ctx, "KV Client initilization failed")
 		return nil, errors.New("failed to init KV client")
 	}
 	// init kv client to read from the config path
-	PONMgr.KVStoreForConfig = SetKVClient(ctx, Technology, Backend, Address, true, basePathKvStore)
+	PONMgr.KVStoreForConfig = ponmgrTech
 	if PONMgr.KVStoreForConfig == nil {
 		logger.Error(ctx, "KV Config Client initilization failed")
 		return nil, errors.New("failed to init KV Config client")
@@ -990,7 +994,7 @@
 	}
 
 	FlowIDPath := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
-	if FlowIDs, err := PONRMgr.KVStore.List(ctx, FlowIDPath); err != nil {
+	if FlowIDs, err := PONRMgr.KVStore.List(ctx, FlowIDPath); err == nil {
 		for _, Flow := range FlowIDs {
 			FlowIDInfoPath := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, PONIntfONUID, Flow.Value)
 			if err = PONRMgr.KVStore.Delete(ctx, FlowIDInfoPath); err != nil {
diff --git a/pkg/ponresourcemanager/ponresourcemanager_test.go b/pkg/ponresourcemanager/ponresourcemanager_test.go
index 7d9c85d..7a748a3 100644
--- a/pkg/ponresourcemanager/ponresourcemanager_test.go
+++ b/pkg/ponresourcemanager/ponresourcemanager_test.go
@@ -188,7 +188,7 @@
 func TestExcludeReservedGemPortIdFromThePool(t *testing.T) {
 	ctx := context.Background()
 	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
-		"etcd", "1:1", "service/voltha")
+		"etcd", "1:1", "service/voltha", nil, nil)
 	if err != nil {
 		return
 	}
@@ -251,7 +251,7 @@
 func TestResourcePoolOverflow(t *testing.T) {
 	ctx := context.Background()
 	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
-		"etcd", "1:1", "service/voltha")
+		"etcd", "1:1", "service/voltha", nil, nil)
 	if err != nil {
 		return
 	}
@@ -310,7 +310,7 @@
 func TestPONResourceManager_ReleaseInvalidID(t *testing.T) {
 	ctx := context.Background()
 	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
-		"etcd", "1:1", "service/voltha")
+		"etcd", "1:1", "service/voltha", nil, nil)
 	if err != nil {
 		return
 	}
@@ -352,7 +352,7 @@
 func TestPONResourceManager_ReserveInvalidID(t *testing.T) {
 	ctx := context.Background()
 	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
-		"etcd", "1:1", "service/voltha")
+		"etcd", "1:1", "service/voltha", nil, nil)
 	if err != nil {
 		return
 	}
diff --git a/pkg/techprofile/tech_profile.go b/pkg/techprofile/tech_profile.go
index 51f40d8..089988d 100644
--- a/pkg/techprofile/tech_profile.go
+++ b/pkg/techprofile/tech_profile.go
@@ -178,6 +178,10 @@
 	*/
 }
 
+// CloseKVClient closes the KV store connections held by this manager.
+// Note: The KV backends may be shared with other managers (e.g., PONResourceManager).
+// The nil check and nil assignment ensure that duplicate close calls are safe —
+// once closed by one manager, the other will see nil and skip closing.
 func (t *TechProfileMgr) CloseKVClient(ctx context.Context) {
 	if t.config.KVBackend != nil {
 		t.config.KVBackend.Client.Close(ctx)
@@ -193,17 +197,17 @@
 	}
 }
 
-func NewTechProfile(ctx context.Context, IntfId uint32, deviceId string, resourceMgr iPonResourceMgr, kvStoreType string, kvStoreAddress string, basePathKvStore string) (*TechProfileMgr, error) {
+func NewTechProfile(ctx context.Context, IntfId uint32, deviceId string, resourceMgr iPonResourceMgr, kvStoreType string, kvStoreAddress string, basePathKvStore string, TpDefault *db.Backend, Tprofiles *db.Backend, TpInstances *db.Backend) (*TechProfileMgr, error) {
 	var techprofileObj TechProfileMgr
 	logger.Debug(ctx, "initializing-techprofile-mananger ", log.Fields{"IntId": IntfId, "device-id": deviceId})
 	techprofileObj.config = NewTechProfileFlags(kvStoreType, kvStoreAddress, basePathKvStore)
-	techprofileObj.config.KVBackend = techprofileObj.SetKVClient(ctx, techprofileObj.config.TPKVPathPrefix)
-	techprofileObj.config.DefaultTpKVBackend = techprofileObj.SetKVClient(ctx, techprofileObj.config.defaultTpKvPathPrefix)
+	techprofileObj.config.KVBackend = Tprofiles
+	techprofileObj.config.DefaultTpKVBackend = TpDefault
 	if techprofileObj.config.KVBackend == nil {
 		logger.Error(ctx, "failed-to-initialize-backend")
 		return nil, errors.New("kv-backend-init-failed")
 	}
-	techprofileObj.config.ResourceInstanceKVBacked = techprofileObj.SetKVClient(ctx, techprofileObj.config.ResourceInstanceKVPathPrefix)
+	techprofileObj.config.ResourceInstanceKVBacked = TpInstances
 	if techprofileObj.config.ResourceInstanceKVBacked == nil {
 		logger.Error(ctx, "failed-to-initialize-resource-instance-kv-backend")
 		return nil, errors.New("resource-instance-kv-backend-init-failed")
@@ -213,12 +217,12 @@
 	techprofileObj.eponTpInstanceMap = make(map[string]*tp_pb.EponTechProfileInstance)
 	techprofileObj.tpMap = make(map[uint32]*tp_pb.TechProfile)
 	techprofileObj.eponTpMap = make(map[uint32]*tp_pb.EponTechProfile)
-	logger.Debug(ctx, "reconcile-tp-instance-cache-start")
+	logger.Debugw(ctx, "reconcile-tp-instance-cache-start", log.Fields{"IntId": IntfId, "device-id": deviceId})
 	if err := techprofileObj.reconcileTpInstancesToCache(ctx, IntfId, deviceId); err != nil {
 		logger.Errorw(ctx, "failed-to-reconcile-tp-instances", log.Fields{"err": err})
 		return nil, err
 	}
-	logger.Debug(ctx, "reconcile-tp-instance-cache-end")
+	logger.Debugw(ctx, "reconcile-tp-instance-cache-end", log.Fields{"IntId": IntfId, "device-id": deviceId})
 	logger.Debug(ctx, "initializing-tech-profile-manager-object-success")
 	return &techprofileObj, nil
 }
@@ -1388,6 +1392,7 @@
 
 	//Fetching the techprofile Keys  from the KV Store.
 	tpkeys, _ := t.config.DefaultTpKVBackend.GetWithPrefixKeysOnly(ctx, tech)
+	logger.Debugw(ctx, "get-all-tech-profile-keys", log.Fields{"len(tpkeys)": len(tpkeys), "tech": tech, "deviceId": deviceId, "IntfId": IntfId})
 
 	// Extract the techprofile Ids from the keys
 	// The tpkeys will be of the format "service/voltha/technology_profiles/GPON/65"
@@ -1414,6 +1419,7 @@
 	for _, tpId := range tpIds {
 		prefix := fmt.Sprintf("%s/%d/olt-{%s}/pon-{%d}", tech, tpId, deviceId, IntfId)
 		kvPairs, _ := t.config.ResourceInstanceKVBacked.GetWithPrefix(newCtx, prefix)
+		logger.Debugw(ctx, "get-resource-instances-with-prefix", log.Fields{"prefix": prefix, "len(kvPairs)": len(kvPairs), "tech": tech, "deviceId": deviceId, "IntfId": IntfId})
 		//check if KvPairs is empty and if not then reconcile the techprofile instance
 		if len(kvPairs) > 0 {
 			for keyPath, kvPair := range kvPairs {