[VOL-2782] Update go.mod of voltha-go,open-olt-adapter,ofagent-go and voltctl to be compatible with latest version of voltha-lig-go

Change-Id: Id412be2c0111fcec147bbcd2e3c92fec52bbe376
diff --git a/VERSION b/VERSION
index 3ec1c88..b668c3b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.16-dev
+1.0.16
diff --git a/go.mod b/go.mod
index e94eb41..b506a7b 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@
 	github.com/imdario/mergo v0.3.7 // indirect
 	github.com/jessevdk/go-flags v1.4.0
 	github.com/jhump/protoreflect v1.5.0
-	github.com/opencord/voltha-lib-go/v3 v3.0.19
+	github.com/opencord/voltha-lib-go/v3 v3.0.23
 	github.com/stretchr/testify v1.4.0
 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
 	golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
diff --git a/go.sum b/go.sum
index ad5dd6e..3d54b91 100644
--- a/go.sum
+++ b/go.sum
@@ -226,8 +226,8 @@
 github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencord/voltha-lib-go/v3 v3.0.19 h1:cU5RXt2CX9wqG6DBzU45VxlQDaXml0XWrcnPYfDJnq8=
-github.com/opencord/voltha-lib-go/v3 v3.0.19/go.mod h1:QuAohPQ+InSw+8XgCFxnp4cpHWcxO2efVTtiBFUmuOY=
+github.com/opencord/voltha-lib-go/v3 v3.0.23 h1:QJkosPdVm85AaLzVEk4umzcL7p2MmwukU9f83rZTIOU=
+github.com/opencord/voltha-lib-go/v3 v3.0.23/go.mod h1:QuAohPQ+InSw+8XgCFxnp4cpHWcxO2efVTtiBFUmuOY=
 github.com/opencord/voltha-protos/v3 v3.2.3 h1:Wv73mw1Ye0bCfyhOk5svgrlE2tLizHq6tQluoDq9Vg8=
 github.com/opencord/voltha-protos/v3 v3.2.3/go.mod h1:RIGHt7b80BHpHh3ceodknh0DxUjUHCWSbYbZqRx7Og0=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/configmanager.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/configmanager.go
index 462b743..441c488 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/configmanager.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/configmanager.go
@@ -33,7 +33,7 @@
 
 const (
 	defaultkvStoreConfigPath = "config"
-	kvStoreDataPathPrefix    = "/service/voltha"
+	kvStoreDataPathPrefix    = "service/voltha"
 	kvStorePathSeparator     = "/"
 )
 
@@ -59,6 +59,10 @@
 	Delete
 )
 
+func (ce ChangeEvent) String() string {
+	return [...]string{"Put", "Delete"}[ce]
+}
+
 // ConfigChangeEvent represents config for the events recieved from watch
 // For example,ChangeType is Put ,ConfigAttribute default
 type ConfigChangeEvent struct {
@@ -207,6 +211,25 @@
 	}
 }
 
+// Retrieves value of a specific config key. Value of key is returned in String format
+func (c *ComponentConfig) Retrieve(ctx context.Context, configKey string) (string, error) {
+	key := c.makeConfigPath() + "/" + configKey
+
+	log.Debugw("retrieving-config", log.Fields{"key": key})
+
+	if kvpair, err := c.cManager.backend.Get(ctx, key); err != nil {
+		return "", err
+	} else {
+		if kvpair == nil {
+			return "", fmt.Errorf("config-key-does-not-exist : %s", key)
+		}
+
+		value := strings.Trim(fmt.Sprintf("%s", kvpair.Value), "\"")
+		log.Debugw("retrieved-config", log.Fields{"key": key, "value": value})
+		return value, nil
+	}
+}
+
 func (c *ComponentConfig) RetrieveAll(ctx context.Context) (map[string]string, error) {
 	key := c.makeConfigPath()
 
@@ -233,7 +256,7 @@
 func (c *ComponentConfig) Save(ctx context.Context, configKey string, configValue string) error {
 	key := c.makeConfigPath() + "/" + configKey
 
-	log.Debugw("saving-key", log.Fields{"key": key, "value": configValue})
+	log.Debugw("saving-config", log.Fields{"key": key, "value": configValue})
 
 	//save the data for update config
 	if err := c.cManager.backend.Put(ctx, key, configValue); err != nil {
@@ -246,7 +269,7 @@
 	//construct key using makeConfigPath
 	key := c.makeConfigPath() + "/" + configKey
 
-	log.Debugw("deleting-key", log.Fields{"key": key})
+	log.Debugw("deleting-config", log.Fields{"key": key})
 	//delete the config
 	if err := c.cManager.backend.Delete(ctx, key); err != nil {
 		return err
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/logcontroller.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/logcontroller.go
index b45c2c8..65927e6 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/logcontroller.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/config/logcontroller.go
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-// Package Config provides dynamic logging configuration for specific Voltha component type implemented using backend.The package can be used in following manner
-// Any Voltha component type can start dynamic logging by starting goroutine of ProcessLogConfigChange after starting kvClient for the component.
+// Package Config provides dynamic logging configuration for specific Voltha component with loglevel lookup
+// from etcd kvstore implemented using backend.
+// Any Voltha component can start utilizing dynamic logging by starting goroutine of StartLogLevelConfigProcessing after
+// starting kvClient for the component.
 
 package config
 
@@ -29,6 +31,12 @@
 	"strings"
 )
 
+const (
+	defaultLogLevelKey                = "default" // kvstore key containing default loglevel
+	globalConfigRootNode              = "global"  // Root Node in kvstore containing global config
+	initialGlobalDefaultLogLevelValue = "WARN"    // Hard-coded Global Default loglevel pushed at PoD startup
+)
+
 // ComponentLogController represents a Configuration for Logging Config of specific Voltha component type
 // It stores ComponentConfig and GlobalConfig of loglevel config of specific Voltha component type
 // For example,ComponentLogController instance will be created for rw-core component
@@ -38,6 +46,7 @@
 	GlobalConfig        *ComponentConfig
 	configManager       *ConfigManager
 	logHash             [16]byte
+	initialLogLevel     string // Initial default log level set by helm chart
 }
 
 func NewComponentLogController(cm *ConfigManager) (*ComponentLogController, error) {
@@ -48,40 +57,85 @@
 		return nil, errors.New("Unable to retrieve PoD Component Name from Runtime env")
 	}
 
+	var defaultLogLevel string
+	var err error
+	// Retrieve and save default log level; used for fallback if all loglevel config is cleared in etcd
+	if defaultLogLevel, err = log.LogLevelToString(log.GetDefaultLogLevel()); err != nil {
+		defaultLogLevel = "DEBUG"
+	}
+
 	return &ComponentLogController{
 		ComponentName:       componentName,
 		componentNameConfig: nil,
 		GlobalConfig:        nil,
 		configManager:       cm,
+		initialLogLevel:     defaultLogLevel,
 	}, nil
 
 }
 
-// ProcessLogConfigChange initialize component config and global config
-func ProcessLogConfigChange(cm *ConfigManager, ctx context.Context) {
+// StartLogLevelConfigProcessing initialize component config and global config
+// Then, it persists initial default Loglevels into Config Store before
+// starting the loading and processing of all Log Configuration
+func StartLogLevelConfigProcessing(cm *ConfigManager, ctx context.Context) {
 	cc, err := NewComponentLogController(cm)
 	if err != nil {
 		log.Errorw("unable-to-construct-component-log-controller-instance-for-log-config-monitoring", log.Fields{"error": err})
 		return
 	}
 
-	log.Debugw("processing-log-config-change", log.Fields{"cc": cc})
-
-	cc.GlobalConfig = cm.InitComponentConfig("global", ConfigTypeLogLevel)
+	cc.GlobalConfig = cm.InitComponentConfig(globalConfigRootNode, ConfigTypeLogLevel)
 	log.Debugw("global-log-config", log.Fields{"cc-global-config": cc.GlobalConfig})
 
 	cc.componentNameConfig = cm.InitComponentConfig(cc.ComponentName, ConfigTypeLogLevel)
 	log.Debugw("component-log-config", log.Fields{"cc-component-name-config": cc.componentNameConfig})
 
+	cc.persistInitialDefaultLogConfigs(ctx)
+
 	cc.processLogConfig(ctx)
 }
 
-// ProcessLogConfig wait on componentn config and global config channel for any changes
-// Event channel will be recieved from backend for valid change type
+// Method to persist Global default loglevel into etcd, if not set yet
+// It also checks and set Component default loglevel into etcd with initial loglevel set from command line
+func (c *ComponentLogController) persistInitialDefaultLogConfigs(ctx context.Context) {
+
+	_, err := c.GlobalConfig.Retrieve(ctx, defaultLogLevelKey)
+	if err != nil {
+		log.Debugw("failed-to-retrieve-global-default-log-config-at-startup", log.Fields{"error": err})
+
+		err = c.GlobalConfig.Save(ctx, defaultLogLevelKey, initialGlobalDefaultLogLevelValue)
+		if err != nil {
+			log.Errorw("failed-to-persist-global-default-log-config-at-startup", log.Fields{"error": err, "loglevel": initialGlobalDefaultLogLevelValue})
+		}
+	}
+
+	_, err = c.componentNameConfig.Retrieve(ctx, defaultLogLevelKey)
+	if err != nil {
+		log.Debugw("failed-to-retrieve-component-default-log-config-at-startup", log.Fields{"error": err})
+
+		err = c.componentNameConfig.Save(ctx, defaultLogLevelKey, c.initialLogLevel)
+		if err != nil {
+			log.Errorw("failed-to-persist-component-default-log-config-at-startup", log.Fields{"error": err, "loglevel": c.initialLogLevel})
+		}
+	}
+}
+
+// ProcessLogConfig will first load and apply log config and then start waiting on component config and global config
+// channels for any changes. Event channel will be recieved from backend for valid change type
 // Then data for componentn log config and global log config will be retrieved from backend and stored in updatedLogConfig in precedence order
 // If any changes in updatedLogConfig will be applied on component
 func (c *ComponentLogController) processLogConfig(ctx context.Context) {
 
+	// Load and apply Log Config for first time
+	initialLogConfig, err := c.buildUpdatedLogConfig(ctx)
+	if err != nil {
+		log.Warnw("unable-to-load-log-config-at-startup", log.Fields{"error": err})
+	} else {
+		if err := c.loadAndApplyLogConfig(initialLogConfig); err != nil {
+			log.Warnw("unable-to-apply-log-config-at-startup", log.Fields{"error": err})
+		}
+	}
+
 	componentConfigEventChan := c.componentNameConfig.MonitorForConfigChange(ctx)
 
 	globalConfigEventChan := c.GlobalConfig.MonitorForConfigChange(ctx)
@@ -94,7 +148,7 @@
 		case configEvent = <-componentConfigEventChan:
 
 		}
-		log.Debugw("processing-log-config-change", log.Fields{"config-event": configEvent})
+		log.Debugw("processing-log-config-change", log.Fields{"ChangeType": configEvent.ChangeType, "Package": configEvent.ConfigAttribute})
 
 		updatedLogConfig, err := c.buildUpdatedLogConfig(ctx)
 		if err != nil {
@@ -112,12 +166,12 @@
 }
 
 // get active loglevel from the zap logger
-func getActiveLogLevel() map[string]string {
-	loglevel := make(map[string]string)
+func getActiveLogLevels() map[string]string {
+	loglevels := make(map[string]string)
 
 	// now do the default log level
 	if level, err := log.LogLevelToString(log.GetDefaultLogLevel()); err == nil {
-		loglevel["default"] = level
+		loglevels[defaultLogLevelKey] = level
 	}
 
 	// do the per-package log levels
@@ -125,61 +179,69 @@
 		level, err := log.GetPackageLogLevel(packageName)
 		if err != nil {
 			log.Warnw("unable-to-fetch-current-active-loglevel-for-package-name", log.Fields{"package-name": packageName, "error": err})
+			continue
 		}
 
-		packagename := strings.ReplaceAll(packageName, "/", "#")
 		if l, err := log.LogLevelToString(level); err == nil {
-			loglevel[packagename] = l
+			loglevels[packageName] = l
 		}
-
 	}
-	log.Debugw("getting-log-levels-from-zap-logger", log.Fields{"log-level": loglevel})
 
-	return loglevel
+	log.Debugw("retreived-log-levels-from-zap-logger", log.Fields{"loglevels": loglevels})
+
+	return loglevels
 }
 
 func (c *ComponentLogController) getGlobalLogConfig(ctx context.Context) (string, error) {
 
-	globalDefaultLogLevel := ""
-	globalLogConfig, err := c.GlobalConfig.RetrieveAll(ctx)
+	globalDefaultLogLevel, err := c.GlobalConfig.Retrieve(ctx, defaultLogLevelKey)
 	if err != nil {
 		return "", err
 	}
 
-	if globalLevel, ok := globalLogConfig["default"]; ok {
-		if _, err := log.StringToLogLevel(globalLevel); err != nil {
-			log.Warnw("unsupported-loglevel-config-defined-at-global-context-pacakge-name", log.Fields{"log-level": globalLevel})
-		} else {
-			globalDefaultLogLevel = globalLevel
-		}
+	// Handle edge cases when global default loglevel is deleted directly from etcd or set to a invalid value
+	// We should use hard-coded initial default value in such cases
+	if globalDefaultLogLevel == "" {
+		log.Warn("global-default-loglevel-not-found-in-config-store")
+		globalDefaultLogLevel = initialGlobalDefaultLogLevelValue
 	}
-	log.Debugw("retrieved-global-log-config", log.Fields{"global-log-config": globalLogConfig})
+
+	if _, err := log.StringToLogLevel(globalDefaultLogLevel); err != nil {
+		log.Warnw("unsupported-loglevel-config-defined-at-global-default", log.Fields{"log-level": globalDefaultLogLevel})
+		globalDefaultLogLevel = initialGlobalDefaultLogLevelValue
+	}
+
+	log.Debugw("retrieved-global-default-loglevel", log.Fields{"level": globalDefaultLogLevel})
 
 	return globalDefaultLogLevel, nil
 }
 
-func (c *ComponentLogController) getComponentLogConfig(globalDefaultLogLevel string, ctx context.Context) (map[string]string, error) {
-	var defaultPresent bool
+func (c *ComponentLogController) getComponentLogConfig(ctx context.Context, globalDefaultLogLevel string) (map[string]string, error) {
 	componentLogConfig, err := c.componentNameConfig.RetrieveAll(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	for componentKey, componentLevel := range componentLogConfig {
-		if _, err := log.StringToLogLevel(componentLevel); err != nil || componentKey == "" {
-			log.Warnw("unsupported-loglevel-config-defined-at-component-context", log.Fields{"package-name": componentKey, "log-level": componentLevel})
-			delete(componentLogConfig, componentKey)
+	effectiveDefaultLogLevel := ""
+	for logConfigKey, logConfigValue := range componentLogConfig {
+		if _, err := log.StringToLogLevel(logConfigValue); err != nil || logConfigKey == "" {
+			log.Warnw("unsupported-loglevel-config-defined-at-component-context", log.Fields{"package-name": logConfigKey, "log-level": logConfigValue})
+			delete(componentLogConfig, logConfigKey)
 		} else {
-			if componentKey == "default" {
-				defaultPresent = true
+			if logConfigKey == defaultLogLevelKey {
+				effectiveDefaultLogLevel = componentLogConfig[defaultLogLevelKey]
 			}
 		}
 	}
-	if !defaultPresent {
-		if globalDefaultLogLevel != "" {
-			componentLogConfig["default"] = globalDefaultLogLevel
-		}
+
+	// if default loglevel is not configured for the component, component should use
+	// default loglevel configured at global level
+	if effectiveDefaultLogLevel == "" {
+		effectiveDefaultLogLevel = globalDefaultLogLevel
 	}
+
+	componentLogConfig[defaultLogLevelKey] = effectiveDefaultLogLevel
+
 	log.Debugw("retrieved-component-log-config", log.Fields{"component-log-level": componentLogConfig})
 
 	return componentLogConfig, nil
@@ -194,16 +256,20 @@
 func (c *ComponentLogController) buildUpdatedLogConfig(ctx context.Context) (map[string]string, error) {
 	globalLogLevel, err := c.getGlobalLogConfig(ctx)
 	if err != nil {
-		return nil, err
+		log.Errorw("unable-to-retrieve-global-log-config", log.Fields{"err": err})
 	}
 
-	componentLogConfig, err := c.getComponentLogConfig(globalLogLevel, ctx)
+	componentLogConfig, err := c.getComponentLogConfig(ctx, globalLogLevel)
 	if err != nil {
 		return nil, err
 	}
 
-	log.Debugw("building-and-updating-log-config", log.Fields{"component-log-config": componentLogConfig})
-	return componentLogConfig, nil
+	finalLogConfig := make(map[string]string)
+	for packageName, logLevel := range componentLogConfig {
+		finalLogConfig[strings.ReplaceAll(packageName, "#", "/")] = logLevel
+	}
+
+	return finalLogConfig, nil
 }
 
 // load and apply the current configuration for component name
@@ -216,64 +282,70 @@
 		return err
 	}
 
-	log.Debugw("loading-and-applying-log-config", log.Fields{"log-config": logConfig})
 	if c.logHash != currentLogHash {
 		UpdateLogLevels(logConfig)
 		c.logHash = currentLogHash
+	} else {
+		log.Debug("effective-loglevel-config-same-as-currently-active")
 	}
+
 	return nil
 }
 
-// getDefaultLogLevel to return active default log level
-func getDefaultLogLevel(logConfig map[string]string) string {
+// createModifiedLogLevels loops through the activeLogLevels recieved from zap logger and updatedLogLevels recieved from buildUpdatedLogConfig
+// to identify and create map of modified Log Levels of 2 types:
+// - Packages for which log level has been changed
+// - Packages for which log level config has been cleared - set to default log level
+func createModifiedLogLevels(activeLogLevels, updatedLogLevels map[string]string) map[string]string {
+	defaultLevel := updatedLogLevels[defaultLogLevelKey]
 
-	for key, level := range logConfig {
-		if key == "default" {
-			return level
-		}
-	}
-	return ""
-}
-
-// createCurrentLogLevel loop through the activeLogLevels recieved from zap logger and updatedLogLevels recieved from buildUpdatedLogConfig
-// The packageName is present or not will be checked in updatedLogLevels ,if the package name is not present then updatedLogLevels will be updated with
-// the packageName and loglevel with  default log level
-func createCurrentLogLevel(activeLogLevels, updatedLogLevels map[string]string) map[string]string {
-	level := getDefaultLogLevel(updatedLogLevels)
+	modifiedLogLevels := make(map[string]string)
 	for activeKey, activeLevel := range activeLogLevels {
 		if _, exist := updatedLogLevels[activeKey]; !exist {
-			if level != "" {
-				activeLevel = level
+			if activeLevel != defaultLevel {
+				modifiedLogLevels[activeKey] = defaultLevel
 			}
-			updatedLogLevels[activeKey] = activeLevel
+		} else if activeLevel != updatedLogLevels[activeKey] {
+			modifiedLogLevels[activeKey] = updatedLogLevels[activeKey]
 		}
 	}
-	return updatedLogLevels
+
+	// Log warnings for all invalid packages for which log config has been set
+	for key, value := range updatedLogLevels {
+		if _, exist := activeLogLevels[key]; !exist {
+			log.Warnw("ignoring-loglevel-set-for-invalid-package", log.Fields{"package": key, "log-level": value})
+		}
+	}
+
+	return modifiedLogLevels
 }
 
 // updateLogLevels update the loglevels for the component
 // retrieve active confguration from logger
 // compare with entries one by one and apply
-func UpdateLogLevels(logLevel map[string]string) {
+func UpdateLogLevels(updatedLogConfig map[string]string) {
 
-	activeLogLevels := getActiveLogLevel()
-	currentLogLevel := createCurrentLogLevel(activeLogLevels, logLevel)
-	for key, level := range currentLogLevel {
-		if key == "default" {
+	activeLogLevels := getActiveLogLevels()
+	changedLogLevels := createModifiedLogLevels(activeLogLevels, updatedLogConfig)
+
+	// If no changed log levels are found, just return. It may happen on configuration of a invalid package
+	if len(changedLogLevels) == 0 {
+		log.Debug("no-change-in-effective-loglevel-config")
+		return
+	}
+
+	log.Debugw("applying-log-level-for-modified-packages", log.Fields{"changed-log-levels": changedLogLevels})
+	for key, level := range changedLogLevels {
+		if key == defaultLogLevelKey {
 			if l, err := log.StringToLogLevel(level); err == nil {
 				log.SetDefaultLogLevel(l)
 			}
 		} else {
-			pname := strings.ReplaceAll(key, "#", "/")
-			if _, err := log.AddPackage(log.JSON, log.DebugLevel, nil, pname); err != nil {
-				log.Warnw("unable-to-add-log-package", log.Fields{"package-name": pname, "error": err})
-			}
 			if l, err := log.StringToLogLevel(level); err == nil {
-				log.SetPackageLogLevel(pname, l)
+				log.SetPackageLogLevel(key, l)
 			}
 		}
 	}
-	log.Debugw("updated-log-level", log.Fields{"current-log-level": currentLogLevel})
 }
 
 // generate md5 hash of key value pairs appended into a single string
diff --git a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore/etcdclient.go b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore/etcdclient.go
index 1014ada..d38f0f6 100644
--- a/vendor/github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore/etcdclient.go
+++ b/vendor/github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore/etcdclient.go
@@ -29,13 +29,13 @@
 
 // EtcdClient represents the Etcd KV store client
 type EtcdClient struct {
-	ectdAPI          *v3Client.Client
-	keyReservations  map[string]*v3Client.LeaseID
-	watchedChannels  sync.Map
-	writeLock        sync.Mutex
-	lockToMutexMap   map[string]*v3Concurrency.Mutex
-	lockToSessionMap map[string]*v3Concurrency.Session
-	lockToMutexLock  sync.Mutex
+	ectdAPI             *v3Client.Client
+	keyReservations     map[string]*v3Client.LeaseID
+	watchedChannels     sync.Map
+	keyReservationsLock sync.RWMutex
+	lockToMutexMap      map[string]*v3Concurrency.Mutex
+	lockToSessionMap    map[string]*v3Concurrency.Session
+	lockToMutexLock     sync.Mutex
 }
 
 // NewEtcdClient returns a new client for the Etcd KV store
@@ -114,13 +114,13 @@
 		return fmt.Errorf("unexpected-type-%T", value)
 	}
 
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
-
 	var err error
 	// Check if there is already a lease for this key - if there is then use it, otherwise a PUT will make
 	// that KV key permanent instead of automatically removing it after a lease expiration
-	if leaseID, ok := c.keyReservations[key]; ok {
+	c.keyReservationsLock.RLock()
+	leaseID, ok := c.keyReservations[key]
+	c.keyReservationsLock.RUnlock()
+	if ok {
 		_, err = c.ectdAPI.Put(ctx, key, val, v3Client.WithLease(*leaseID))
 	} else {
 		_, err = c.ectdAPI.Put(ctx, key, val)
@@ -146,9 +146,6 @@
 // wait for a response
 func (c *EtcdClient) Delete(ctx context.Context, key string) error {
 
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
-
 	// delete the key
 	if _, err := c.ectdAPI.Delete(ctx, key); err != nil {
 		logger.Errorw("failed-to-delete-key", log.Fields{"key": key, "error": err})
@@ -177,9 +174,9 @@
 		return nil, err
 	}
 	// Register the lease id
-	c.writeLock.Lock()
+	c.keyReservationsLock.Lock()
 	c.keyReservations[key] = &resp.ID
-	c.writeLock.Unlock()
+	c.keyReservationsLock.Unlock()
 
 	// Revoke lease if reservation is not successful
 	reservationSuccessful := false
@@ -235,8 +232,8 @@
 
 // ReleaseAllReservations releases all key reservations previously made (using Reserve API)
 func (c *EtcdClient) ReleaseAllReservations(ctx context.Context) error {
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
+	c.keyReservationsLock.Lock()
+	defer c.keyReservationsLock.Unlock()
 
 	for key, leaseID := range c.keyReservations {
 		_, err := c.ectdAPI.Revoke(ctx, *leaseID)
@@ -255,8 +252,8 @@
 	logger.Debugw("Release-reservation", log.Fields{"key": key})
 	var ok bool
 	var leaseID *v3Client.LeaseID
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
+	c.keyReservationsLock.Lock()
+	defer c.keyReservationsLock.Unlock()
 	if leaseID, ok = c.keyReservations[key]; !ok {
 		return nil
 	}
@@ -278,9 +275,11 @@
 	// Get the leaseid using the key
 	var ok bool
 	var leaseID *v3Client.LeaseID
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
-	if leaseID, ok = c.keyReservations[key]; !ok {
+	c.keyReservationsLock.RLock()
+	leaseID, ok = c.keyReservations[key]
+	c.keyReservationsLock.RUnlock()
+
+	if !ok {
 		return errors.New("key-not-reserved")
 	}
 
@@ -372,8 +371,6 @@
 	// Get the array of channels mapping
 	var watchedChannels []map[chan *Event]v3Client.Watcher
 	var ok bool
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
 
 	if watchedChannels, ok = c.getChannelMaps(key); !ok {
 		logger.Warnw("key-has-no-watched-channels", log.Fields{"key": key})
@@ -425,8 +422,6 @@
 
 // Close closes the KV store client
 func (c *EtcdClient) Close() {
-	c.writeLock.Lock()
-	defer c.writeLock.Unlock()
 	if err := c.ectdAPI.Close(); err != nil {
 		logger.Errorw("error-closing-client", log.Fields{"error": err})
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b95636d..6ed5711 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -90,7 +90,7 @@
 github.com/modern-go/concurrent
 # github.com/modern-go/reflect2 v1.0.1
 github.com/modern-go/reflect2
-# github.com/opencord/voltha-lib-go/v3 v3.0.19
+# github.com/opencord/voltha-lib-go/v3 v3.0.23
 github.com/opencord/voltha-lib-go/v3/pkg/config
 github.com/opencord/voltha-lib-go/v3/pkg/db
 github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore