LockRoster.modify: no KeyError if element was already gone, fixes #7937

The intention of LockRoster.modify(key, REMOVE) is to remove self.id.

Using set.discard will just ignore it if self.id is not present there anymore.

Previously, using set.remove triggered a KeyError that has been frequently
seen in tracebacks of teardowns involving Repository.__del__ and Repository.__exit__.

I added a REMOVE2 op to serve one caller that needs to get the KeyError if
self.id was not present.

Thanks to @herrmanntom for the workaround!
This commit is contained in:
Thomas Waldmann 2023-11-16 14:40:06 +01:00
parent 7c20bb52d1
commit 046f9fe392
No known key found for this signature in database
GPG Key ID: 243ACFA951F78E01
2 changed files with 8 additions and 3 deletions

View File

@ -8,7 +8,7 @@ from . import platform
from .helpers import Error, ErrorWithTraceback
from .logger import create_logger
ADD, REMOVE = "add", "remove"
ADD, REMOVE, REMOVE2 = "add", "remove", "remove2"
SHARED, EXCLUSIVE = "shared", "exclusive"
logger = create_logger(__name__)
@ -326,6 +326,11 @@ class LockRoster:
if op == ADD:
elements.add(self.id)
elif op == REMOVE:
# note: we ignore it if the element is already not present anymore.
# this has been frequently seen in teardowns involving Repository.__del__ and Repository.__exit__.
elements.discard(self.id)
elif op == REMOVE2:
# needed for callers that do not want to ignore.
elements.remove(self.id)
else:
raise ValueError("Unknown LockRoster op %r" % op)
@ -340,7 +345,7 @@ class LockRoster:
killing, self.kill_stale_locks = self.kill_stale_locks, False
try:
try:
self.modify(key, REMOVE)
self.modify(key, REMOVE2)
except KeyError:
# entry was not there, so no need to add a new one, but still update our id
self.id = new_id

View File

@ -280,7 +280,7 @@ class TestLock:
assert roster.get(SHARED) == {our_id}
assert roster.get(EXCLUSIVE) == set()
assert roster.get(SHARED) == set()
with pytest.raises(KeyError):
with pytest.raises(NotLocked):
dead_lock.release()
with Lock(lockpath, id=cant_know_if_dead_id, exclusive=True):