From 19c51f3f3cca08ee27e0acd45a1ceeb841af0802 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 19 Oct 2016 18:27:36 +0200 Subject: [PATCH] Added ForceUnlock to namespace-lock (#2990) --- cmd/namespace-lock.go | 23 +++++++++++++++++++++++ cmd/namespace-lock_test.go | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/cmd/namespace-lock.go b/cmd/namespace-lock.go index 4b379f3af..a510f4320 100644 --- a/cmd/namespace-lock.go +++ b/cmd/namespace-lock.go @@ -245,3 +245,26 @@ func (n *nsLockMap) RUnlock(volume, path, opsID string) { readLock := true n.unlock(volume, path, opsID, readLock) } + +// ForceUnlock - forcefully unlock a lock based on name. +func (n *nsLockMap) ForceUnlock(volume, path string) { + n.lockMapMutex.Lock() + defer n.lockMapMutex.Unlock() + + if n.isDist { // For distributed mode, broadcast ForceUnlock message. + dsync.NewDRWMutex(pathutil.Join(volume, path)).ForceUnlock() + } + + param := nsParam{volume, path} + if _, found := n.lockMap[param]; found { + // Remove lock from the map. + delete(n.lockMap, param) + + // delete the lock state entry for given + // pair. + err := n.deleteLockInfoEntryForVolumePath(param) + if err != nil { + errorIf(err, "Failed to delete lock info entry.") + } + } +} diff --git a/cmd/namespace-lock_test.go b/cmd/namespace-lock_test.go index ac53133a5..e41d91512 100644 --- a/cmd/namespace-lock_test.go +++ b/cmd/namespace-lock_test.go @@ -68,7 +68,7 @@ func TestNamespaceLockTest(t *testing.T) { if !ok && testCase.shouldPass { t.Errorf("Lock in map missing.") } - // Validate loced ref count. + // Validate locked ref count. if testCase.lockedRefCount != nsLk.ref && testCase.shouldPass { t.Errorf("Test %d fails, expected to pass. Wanted ref count is %d, got %d", 1, testCase.lockedRefCount, nsLk.ref) } @@ -91,7 +91,7 @@ func TestNamespaceLockTest(t *testing.T) { if !ok && testCase.shouldPass { t.Errorf("Lock in map missing.") } - // Validate loced ref count. + // Validate locked ref count. if testCase.lockedRefCount != nsLk.ref && testCase.shouldPass { t.Errorf("Test %d fails, expected to pass. Wanted ref count is %d, got %d", 1, testCase.lockedRefCount, nsLk.ref) } @@ -114,7 +114,7 @@ func TestNamespaceLockTest(t *testing.T) { if !ok && testCase.shouldPass { t.Errorf("Lock in map missing.") } - // Validate loced ref count. + // Validate locked ref count. if testCase.lockedRefCount != nsLk.ref && testCase.shouldPass { t.Errorf("Test %d fails, expected to pass. Wanted ref count is %d, got %d", 3, testCase.lockedRefCount, nsLk.ref) } @@ -380,5 +380,35 @@ func TestLockStats(t *testing.T) { expectedLockStats = expectedResult[7] // verify the actual lock info with the expected one. verifyGlobalLockStats(expectedLockStats, t, 8) +} + +// Tests functionality to forcefully unlock locks. +func TestNamespaceForceUnlockTest(t *testing.T) { + + // Create lock. + nsMutex.Lock("bucket", "object", "11-11") + // Forcefully unlock lock. + nsMutex.ForceUnlock("bucket", "object") + + ch := make(chan struct{}, 1) + + go func() { + // Try to claim lock again. + nsMutex.Lock("bucket", "object", "22-22") + // And signal succes. + ch <- struct{}{} + }() + + select { + case <-ch: + // Signalled so all is fine. + break + + case <-time.After(100*time.Millisecond): + // In case we hit the time out, the lock has not been cleared. + t.Errorf("Lock not cleared.") + } + // Clean up lock. + nsMutex.ForceUnlock("bucket", "object") }