|
|
@ -51,14 +51,6 @@ type RWLocker interface { |
|
|
|
RUnlock() |
|
|
|
RUnlock() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// RWLockerSync - internal locker interface.
|
|
|
|
|
|
|
|
type RWLockerSync interface { |
|
|
|
|
|
|
|
GetLock(id, source string, timeout time.Duration) bool |
|
|
|
|
|
|
|
Unlock() |
|
|
|
|
|
|
|
GetRLock(id, source string, timeout time.Duration) bool |
|
|
|
|
|
|
|
RUnlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize distributed locking only in case of distributed setup.
|
|
|
|
// Initialize distributed locking only in case of distributed setup.
|
|
|
|
// Returns lock clients and the node index for the current server.
|
|
|
|
// Returns lock clients and the node index for the current server.
|
|
|
|
func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int) { |
|
|
|
func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int) { |
|
|
@ -101,8 +93,11 @@ func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int) |
|
|
|
func newNSLock(isDistXL bool) *nsLockMap { |
|
|
|
func newNSLock(isDistXL bool) *nsLockMap { |
|
|
|
nsMutex := nsLockMap{ |
|
|
|
nsMutex := nsLockMap{ |
|
|
|
isDistXL: isDistXL, |
|
|
|
isDistXL: isDistXL, |
|
|
|
lockMap: make(map[nsParam]*nsLock), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if isDistXL { |
|
|
|
|
|
|
|
return &nsMutex |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
nsMutex.lockMap = make(map[nsParam]*nsLock) |
|
|
|
return &nsMutex |
|
|
|
return &nsMutex |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -119,7 +114,7 @@ type nsParam struct { |
|
|
|
|
|
|
|
|
|
|
|
// nsLock - provides primitives for locking critical namespace regions.
|
|
|
|
// nsLock - provides primitives for locking critical namespace regions.
|
|
|
|
type nsLock struct { |
|
|
|
type nsLock struct { |
|
|
|
RWLockerSync |
|
|
|
*lsync.LRWMutex |
|
|
|
ref uint |
|
|
|
ref uint |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -141,13 +136,8 @@ func (n *nsLockMap) lock(volume, path string, lockSource, opsID string, readLock |
|
|
|
nsLk, found := n.lockMap[param] |
|
|
|
nsLk, found := n.lockMap[param] |
|
|
|
if !found { |
|
|
|
if !found { |
|
|
|
n.lockMap[param] = &nsLock{ |
|
|
|
n.lockMap[param] = &nsLock{ |
|
|
|
RWLockerSync: func() RWLockerSync { |
|
|
|
LRWMutex: &lsync.LRWMutex{}, |
|
|
|
if n.isDistXL { |
|
|
|
ref: 1, |
|
|
|
return dsync.NewDRWMutex(pathJoin(volume, path), globalDsync) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return &lsync.LRWMutex{} |
|
|
|
|
|
|
|
}(), |
|
|
|
|
|
|
|
ref: 1, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
nsLk = n.lockMap[param] |
|
|
|
nsLk = n.lockMap[param] |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -259,8 +249,49 @@ func (n *nsLockMap) ForceUnlock(volume, path string) { |
|
|
|
delete(n.lockMap, nsParam{volume, path}) |
|
|
|
delete(n.lockMap, nsParam{volume, path}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// lockInstance - frontend/top-level interface for namespace locks.
|
|
|
|
// dsync's distributed lock instance.
|
|
|
|
type lockInstance struct { |
|
|
|
type distLockInstance struct { |
|
|
|
|
|
|
|
rwMutex *dsync.DRWMutex |
|
|
|
|
|
|
|
volume, path, opsID string |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lock - block until write lock is taken or timeout has occurred.
|
|
|
|
|
|
|
|
func (di *distLockInstance) GetLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
|
|
|
|
lockSource := getSource() |
|
|
|
|
|
|
|
start := UTCNow() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !di.rwMutex.GetLock(di.opsID, lockSource, timeout.Timeout()) { |
|
|
|
|
|
|
|
timeout.LogFailure() |
|
|
|
|
|
|
|
return OperationTimedOut{Path: di.path} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
timeout.LogSuccess(UTCNow().Sub(start)) |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unlock - block until write lock is released.
|
|
|
|
|
|
|
|
func (di *distLockInstance) Unlock() { |
|
|
|
|
|
|
|
di.rwMutex.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RLock - block until read lock is taken or timeout has occurred.
|
|
|
|
|
|
|
|
func (di *distLockInstance) GetRLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
|
|
|
|
lockSource := getSource() |
|
|
|
|
|
|
|
start := UTCNow() |
|
|
|
|
|
|
|
if !di.rwMutex.GetRLock(di.opsID, lockSource, timeout.Timeout()) { |
|
|
|
|
|
|
|
timeout.LogFailure() |
|
|
|
|
|
|
|
return OperationTimedOut{Path: di.path} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
timeout.LogSuccess(UTCNow().Sub(start)) |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RUnlock - block until read lock is released.
|
|
|
|
|
|
|
|
func (di *distLockInstance) RUnlock() { |
|
|
|
|
|
|
|
di.rwMutex.RUnlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// localLockInstance - frontend/top-level interface for namespace locks.
|
|
|
|
|
|
|
|
type localLockInstance struct { |
|
|
|
ns *nsLockMap |
|
|
|
ns *nsLockMap |
|
|
|
volume, path, opsID string |
|
|
|
volume, path, opsID string |
|
|
|
} |
|
|
|
} |
|
|
@ -270,11 +301,14 @@ type lockInstance struct { |
|
|
|
// volume, path and operation ID.
|
|
|
|
// volume, path and operation ID.
|
|
|
|
func (n *nsLockMap) NewNSLock(volume, path string) RWLocker { |
|
|
|
func (n *nsLockMap) NewNSLock(volume, path string) RWLocker { |
|
|
|
opsID := mustGetUUID() |
|
|
|
opsID := mustGetUUID() |
|
|
|
return &lockInstance{n, volume, path, opsID} |
|
|
|
if n.isDistXL { |
|
|
|
|
|
|
|
return &distLockInstance{dsync.NewDRWMutex(pathJoin(volume, path), globalDsync), volume, path, opsID} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return &localLockInstance{n, volume, path, opsID} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Lock - block until write lock is taken or timeout has occurred.
|
|
|
|
// Lock - block until write lock is taken or timeout has occurred.
|
|
|
|
func (li *lockInstance) GetLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
func (li *localLockInstance) GetLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
lockSource := getSource() |
|
|
|
lockSource := getSource() |
|
|
|
start := UTCNow() |
|
|
|
start := UTCNow() |
|
|
|
readLock := false |
|
|
|
readLock := false |
|
|
@ -287,13 +321,13 @@ func (li *lockInstance) GetLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Unlock - block until write lock is released.
|
|
|
|
// Unlock - block until write lock is released.
|
|
|
|
func (li *lockInstance) Unlock() { |
|
|
|
func (li *localLockInstance) Unlock() { |
|
|
|
readLock := false |
|
|
|
readLock := false |
|
|
|
li.ns.unlock(li.volume, li.path, li.opsID, readLock) |
|
|
|
li.ns.unlock(li.volume, li.path, li.opsID, readLock) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// RLock - block until read lock is taken or timeout has occurred.
|
|
|
|
// RLock - block until read lock is taken or timeout has occurred.
|
|
|
|
func (li *lockInstance) GetRLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
func (li *localLockInstance) GetRLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
lockSource := getSource() |
|
|
|
lockSource := getSource() |
|
|
|
start := UTCNow() |
|
|
|
start := UTCNow() |
|
|
|
readLock := true |
|
|
|
readLock := true |
|
|
@ -306,7 +340,7 @@ func (li *lockInstance) GetRLock(timeout *dynamicTimeout) (timedOutErr error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// RUnlock - block until read lock is released.
|
|
|
|
// RUnlock - block until read lock is released.
|
|
|
|
func (li *lockInstance) RUnlock() { |
|
|
|
func (li *localLockInstance) RUnlock() { |
|
|
|
readLock := true |
|
|
|
readLock := true |
|
|
|
li.ns.unlock(li.volume, li.path, li.opsID, readLock) |
|
|
|
li.ns.unlock(li.volume, li.path, li.opsID, readLock) |
|
|
|
} |
|
|
|
} |
|
|
|