|
|
@ -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.lockMap[param] = nsLk |
|
|
|
n.mutex.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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.Unlock() |
|
|
|
nsLk.RUnlock() |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|