lock: bug fixes. (#1420)

* release Lock on map before trying to Lock NS
* delete NS lock from map if no more refs.
* refactor to avoid repetition of code.
master
Krishna Srinivas 9 years ago committed by Harshavardhana
parent 984903cce1
commit 39df425b2a
  1. 92
      namespace-lock.go

@ -16,7 +16,11 @@
package main package main
import "sync" import (
"sync"
"github.com/Sirupsen/logrus"
)
// nsParam - carries name space resource. // nsParam - carries name space resource.
type nsParam struct { type nsParam struct {
@ -48,11 +52,9 @@ func initNSLock() {
} }
} }
// Lock - locks the given resource for writes, using a previously // Lock the namespace resource.
// allocated name space lock or initializing a new one. func (n *nsLockMap) lock(volume, path string, readLock bool) {
func (n *nsLockMap) Lock(volume, path string) {
n.mutex.Lock() n.mutex.Lock()
defer n.mutex.Unlock()
param := nsParam{volume, path} param := nsParam{volume, path}
nsLk, found := n.lockMap[param] nsLk, found := n.lockMap[param]
@ -61,68 +63,70 @@ func (n *nsLockMap) Lock(volume, path string) {
RWMutex: &sync.RWMutex{}, RWMutex: &sync.RWMutex{},
ref: 0, ref: 0,
} }
n.lockMap[param] = nsLk
} }
// Acquire a write lock and update reference counter.
nsLk.Lock()
nsLk.ref++ nsLk.ref++
// Unlock map before Locking NS which might block.
n.mutex.Unlock()
n.lockMap[param] = nsLk // Locking here can block.
if readLock {
nsLk.RLock()
} else {
nsLk.Lock()
}
} }
// Unlock - unlocks any previously acquired write locks. // Unlock the namespace resource.
func (n *nsLockMap) Unlock(volume, path string) { func (n *nsLockMap) unlock(volume, path string, readLock bool) {
// nsLk.Unlock() will not block, hence locking the map for the entire function is fine.
n.mutex.Lock() n.mutex.Lock()
defer n.mutex.Unlock() defer n.mutex.Unlock()
param := nsParam{volume, path} param := nsParam{volume, path}
if nsLk, found := n.lockMap[param]; found { if nsLk, found := n.lockMap[param]; found {
// Unlock a write lock and update reference counter. if readLock {
nsLk.RUnlock()
} else {
nsLk.Unlock() nsLk.Unlock()
}
if nsLk.ref == 0 {
log.WithFields(logrus.Fields{
"volume": volume,
"path": path,
}).Error("ref count in NS lock can not be 0.")
}
if nsLk.ref != 0 { if nsLk.ref != 0 {
nsLk.ref-- nsLk.ref--
} }
if nsLk.ref != 0 { if nsLk.ref == 0 {
n.lockMap[param] = nsLk // Remove from the map if there are no more references.
delete(n.lockMap, param)
} }
} }
} }
// RLock - locks any previously acquired read locks. // Lock - locks the given resource for writes, using a previously
func (n *nsLockMap) RLock(volume, path string) { // allocated name space lock or initializing a new one.
n.mutex.Lock() func (n *nsLockMap) Lock(volume, path string) {
defer n.mutex.Unlock() readLock := false
n.lock(volume, path, readLock)
param := nsParam{volume, path}
nsLk, found := n.lockMap[param]
if !found {
nsLk = &nsLock{
RWMutex: &sync.RWMutex{},
ref: 0,
}
} }
// Acquire a read lock and update reference counter. // Unlock - unlocks any previously acquired write locks.
nsLk.RLock() func (n *nsLockMap) Unlock(volume, path string) {
nsLk.ref++ readLock := false
n.unlock(volume, path, readLock)
}
n.lockMap[param] = nsLk // RLock - locks any previously acquired read locks.
func (n *nsLockMap) RLock(volume, path string) {
readLock := true
n.lock(volume, path, readLock)
} }
// RUnlock - unlocks any previously acquired read locks. // RUnlock - unlocks any previously acquired read locks.
func (n *nsLockMap) RUnlock(volume, path string) { func (n *nsLockMap) RUnlock(volume, path string) {
n.mutex.Lock() readLock := true
defer n.mutex.Unlock() n.unlock(volume, path, readLock)
param := nsParam{volume, path}
if nsLk, found := n.lockMap[param]; found {
// Unlock a read lock and update reference counter.
nsLk.RUnlock()
if nsLk.ref != 0 {
nsLk.ref--
}
if nsLk.ref != 0 {
n.lockMap[param] = nsLk
}
}
} }

Loading…
Cancel
Save