diff --git a/content/local/locks.go b/content/local/locks.go index d1d2d564d..077b6241e 100644 --- a/content/local/locks.go +++ b/content/local/locks.go @@ -41,7 +41,13 @@ func tryLock(ref string) error { defer locksMu.Unlock() if v, ok := locks[ref]; ok { - return errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked since %s", ref, v.since) + // Returning the duration may help developers distinguish dead locks (long duration) from + // lock contentions (short duration). + now := time.Now() + return errors.Wrapf( + errdefs.ErrUnavailable, + "ref %s locked for %s (since %s)", ref, now.Sub(v.since), v.since, + ) } locks[ref] = &lock{time.Now()} diff --git a/content/local/locks_test.go b/content/local/locks_test.go index c9d0034cc..3d1912dd5 100644 --- a/content/local/locks_test.go +++ b/content/local/locks_test.go @@ -28,5 +28,5 @@ func TestTryLock(t *testing.T) { defer unlock("testref") err = tryLock("testref") - assert.ErrorContains(t, err, "ref testref locked since ") + assert.ErrorContains(t, err, "ref testref locked for ") }