[VOL-3930] Using a shared lock for Resource acquisition and release

Change-Id: Ic93588ab944ef912d417e9334d56b833b46a3f26
diff --git a/VERSION b/VERSION
index ee74734..627a3f4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.1.0
+4.1.1
diff --git a/pkg/ponresourcemanager/ponresourcemanager.go b/pkg/ponresourcemanager/ponresourcemanager.go
index 415ce21..70ed8e6 100755
--- a/pkg/ponresourcemanager/ponresourcemanager.go
+++ b/pkg/ponresourcemanager/ponresourcemanager.go
@@ -703,6 +703,13 @@
 	   :return list/uint32/None: list, uint32 or None if resource type is
 	    alloc_id/gemport_id, onu_id or invalid type respectively
 	*/
+
+	logger.Debugw(ctx, "getting-resource-id", log.Fields{
+		"intf-id":       IntfID,
+		"resource-type": ResourceType,
+		"num":           NumIDs,
+	})
+
 	if NumIDs < 1 {
 		logger.Error(ctx, "Invalid number of resources requested")
 		return nil, fmt.Errorf("Invalid number of resources requested %d", NumIDs)
@@ -771,21 +778,30 @@
 	return false
 }
 
-func (PONRMgr *PONResourceManager) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) bool {
+func (PONRMgr *PONResourceManager) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error {
 	/*
-	   Release alloc/gemport/onu/flow id for given OLT PON interface.
-	   :param pon_intf_id: OLT PON interface id
-	   :param resource_type: String to identify type of resource
-	   :param release_content: required number of ids
-	   :return boolean: True if all IDs in given release_content release else False
+	  Release alloc/gemport/onu/flow id for given OLT PON interface.
+	  :param pon_intf_id: OLT PON interface id
+	  :param resource_type: String to identify type of resource
+	  :param release_content: required number of ids
+	  :return boolean: True if all IDs in given release_content release else False
 	*/
+
+	logger.Debugw(ctx, "freeing-resource-id", log.Fields{
+		"intf-id":         IntfID,
+		"resource-type":   ResourceType,
+		"release-content": ReleaseContent,
+	})
+
 	if !checkValidResourceType(ResourceType) {
-		logger.Error(ctx, "Invalid resource type")
-		return false
+		err := fmt.Errorf("Invalid resource type: %s", ResourceType)
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	if ReleaseContent == nil {
-		logger.Debug(ctx, "Nothing to release")
-		return true
+		err := fmt.Errorf("Nothing to release")
+		logger.Debug(ctx, err.Error())
+		return err
 	}
 	// delegate to the master instance if sharing enabled across instances
 	SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
@@ -794,22 +810,24 @@
 	}
 	Path := PONRMgr.GetPath(ctx, IntfID, ResourceType)
 	if Path == "" {
-		logger.Error(ctx, "Failed to get path")
-		return false
+		err := fmt.Errorf("Failed to get path for IntfId %d and ResourceType %s", IntfID, ResourceType)
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	Resource, err := PONRMgr.GetResource(ctx, Path)
 	if err != nil {
-		logger.Error(ctx, "Failed to get resource")
-		return false
+		logger.Error(ctx, err.Error())
+		return err
 	}
 	for _, Val := range ReleaseContent {
 		PONRMgr.ReleaseID(ctx, Resource, Val)
 	}
 	if PONRMgr.UpdateResource(ctx, Path, Resource) != nil {
-		logger.Errorf(ctx, "Free resource for %s failed", Path)
-		return false
+		err := fmt.Errorf("Free resource for %s failed", Path)
+		logger.Errorf(ctx, err.Error())
+		return err
 	}
-	return true
+	return nil
 }
 
 func (PONRMgr *PONResourceManager) UpdateResource(ctx context.Context, Path string, Resource map[string]interface{}) error {
@@ -1258,6 +1276,10 @@
 	return GEMPORT_ID
 }
 
+func (PONRMgr *PONResourceManager) GetResourceTypeOnuID() string {
+	return ONU_ID
+}
+
 // 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) {
diff --git a/pkg/techprofile/tech_profile.go b/pkg/techprofile/tech_profile.go
index 5cb5a2e..0f2741f 100644
--- a/pkg/techprofile/tech_profile.go
+++ b/pkg/techprofile/tech_profile.go
@@ -36,8 +36,10 @@
 // Interface to pon resource manager APIs
 type iPonResourceMgr interface {
 	GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error)
+	FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error
 	GetResourceTypeAllocID() string
 	GetResourceTypeGemPortID() string
+	GetResourceTypeOnuID() string
 	GetTechnology() string
 }
 
@@ -221,6 +223,7 @@
 type TechProfileMgr struct {
 	config            *TechProfileFlags
 	resourceMgr       iPonResourceMgr
+	OnuIDMgmtLock     sync.RWMutex
 	GemPortIDMgmtLock sync.RWMutex
 	AllocIDMgmtLock   sync.RWMutex
 }
@@ -659,9 +662,7 @@
 	logger.Infow(ctx, "Allocating TechProfileMgr instance from techprofile template", log.Fields{"uniPortName": uniPortName, "intfId": intfId, "numGem": tp.NumGemPorts})
 
 	if tp.InstanceCtrl.Onu == "multi-instance" {
-		t.AllocIDMgmtLock.Lock()
-		tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
-		t.AllocIDMgmtLock.Unlock()
+		tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
 		if err != nil {
 			logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 			return nil
@@ -673,9 +674,7 @@
 		} else if tpInst == nil {
 			// No "single-instance" tp found on one any uni port for the given TP ID
 			// Allocate a new TcontID or AllocID
-			t.AllocIDMgmtLock.Lock()
-			tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
-			t.AllocIDMgmtLock.Unlock()
+			tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1)
 			if err != nil {
 				logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 				return nil
@@ -686,9 +685,7 @@
 		}
 	}
 	logger.Debugw(ctx, "Num GEM ports in TP:", log.Fields{"NumGemPorts": tp.NumGemPorts})
-	t.GemPortIDMgmtLock.Lock()
-	gemPorts, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts)
-	t.GemPortIDMgmtLock.Unlock()
+	gemPorts, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts)
 	if err != nil {
 		logger.Errorw(ctx, "Error getting gemport ids from rsrcrMgr", log.Fields{"intfId": intfId, "numGemports": tp.NumGemPorts})
 		return nil
@@ -793,7 +790,7 @@
 	logger.Infow(ctx, "Allocating TechProfileMgr instance from techprofile template", log.Fields{"uniPortName": uniPortName, "intfId": intfId, "numGem": tp.NumGemPorts})
 
 	if tp.InstanceCtrl.Onu == "multi-instance" {
-		if tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
+		if tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
 			logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 			return nil
 		}
@@ -804,7 +801,7 @@
 		} else if tpInst == nil {
 			// No "single-instance" tp found on one any uni port for the given TP ID
 			// Allocate a new TcontID or AllocID
-			if tcontIDs, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
+			if tcontIDs, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeAllocID(), 1); err != nil {
 				logger.Errorw(ctx, "Error getting alloc id from rsrcrMgr", log.Fields{"intfId": intfId})
 				return nil
 			}
@@ -814,7 +811,7 @@
 		}
 	}
 	logger.Debugw(ctx, "Num GEM ports in TP:", log.Fields{"NumGemPorts": tp.NumGemPorts})
-	if gemPorts, err = t.resourceMgr.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts); err != nil {
+	if gemPorts, err = t.GetResourceID(ctx, intfId, t.resourceMgr.GetResourceTypeGemPortID(), tp.NumGemPorts); err != nil {
 		logger.Errorw(ctx, "Error getting gemport ids from rsrcrMgr", log.Fields{"intfId": intfId, "numGemports": tp.NumGemPorts})
 		return nil
 	}
@@ -1397,3 +1394,62 @@
 	}
 	return nil
 }
+
+func (t *TechProfileMgr) GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error) {
+	logger.Debugw(ctx, "getting-resource-id", log.Fields{
+		"intf-id":       IntfID,
+		"resource-type": ResourceType,
+		"num":           NumIDs,
+	})
+	var err error
+	var ids []uint32
+	switch ResourceType {
+	case t.resourceMgr.GetResourceTypeAllocID():
+		t.AllocIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.AllocIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeGemPortID():
+		t.GemPortIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.GemPortIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeOnuID():
+		t.OnuIDMgmtLock.Lock()
+		ids, err = t.resourceMgr.GetResourceID(ctx, IntfID, ResourceType, NumIDs)
+		t.OnuIDMgmtLock.Unlock()
+	default:
+		return nil, fmt.Errorf("ResourceType %s not supported", ResourceType)
+	}
+	if err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+func (t *TechProfileMgr) FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error {
+	logger.Debugw(ctx, "freeing-resource-id", log.Fields{
+		"intf-id":         IntfID,
+		"resource-type":   ResourceType,
+		"release-content": ReleaseContent,
+	})
+	var err error
+	switch ResourceType {
+	case t.resourceMgr.GetResourceTypeAllocID():
+		t.AllocIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.AllocIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeGemPortID():
+		t.GemPortIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.GemPortIDMgmtLock.Unlock()
+	case t.resourceMgr.GetResourceTypeOnuID():
+		t.OnuIDMgmtLock.Lock()
+		err = t.resourceMgr.FreeResourceID(ctx, IntfID, ResourceType, ReleaseContent)
+		t.OnuIDMgmtLock.Unlock()
+	default:
+		return fmt.Errorf("ResourceType %s not supported", ResourceType)
+	}
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/pkg/techprofile/tech_profile_if.go b/pkg/techprofile/tech_profile_if.go
index d3a79ce..84d84ee 100644
--- a/pkg/techprofile/tech_profile_if.go
+++ b/pkg/techprofile/tech_profile_if.go
@@ -38,4 +38,6 @@
 	GetMulticastTrafficQueues(ctx context.Context, tp *TechProfile) []*tp_pb.TrafficQueue
 	GetGemportForPbit(ctx context.Context, tp interface{}, Dir tp_pb.Direction, pbit uint32) interface{}
 	FindAllTpInstances(ctx context.Context, techProfiletblID uint32, ponIntf uint32, onuID uint32) interface{}
+	GetResourceID(ctx context.Context, IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error)
+	FreeResourceID(ctx context.Context, IntfID uint32, ResourceType string, ReleaseContent []uint32) error
 }