浏览代码

repository: fix spurious, empty lock.roster on InvalidRepository exception

Marian Beermann 8 年之前
父节点
当前提交
928f6e0ca4
共有 2 个文件被更改,包括 11 次插入0 次删除
  1. 7 0
      borg/locking.py
  2. 4 0
      borg/testsuite/locking.py

+ 7 - 0
borg/locking.py

@@ -201,6 +201,9 @@ class LockRoster:
         roster = self.load()
         roster = self.load()
         return set(tuple(e) for e in roster.get(key, []))
         return set(tuple(e) for e in roster.get(key, []))
 
 
+    def empty(self, *keys):
+        return all(not self.get(key) for key in keys)
+
     def modify(self, key, op):
     def modify(self, key, op):
         roster = self.load()
         roster = self.load()
         try:
         try:
@@ -293,10 +296,14 @@ class Lock:
     def release(self):
     def release(self):
         if self.is_exclusive:
         if self.is_exclusive:
             self._roster.modify(EXCLUSIVE, REMOVE)
             self._roster.modify(EXCLUSIVE, REMOVE)
+            if self._roster.empty(EXCLUSIVE, SHARED):
+                self._roster.remove()
             self._lock.release()
             self._lock.release()
         else:
         else:
             with self._lock:
             with self._lock:
                 self._roster.modify(SHARED, REMOVE)
                 self._roster.modify(SHARED, REMOVE)
+                if self._roster.empty(EXCLUSIVE, SHARED):
+                    self._roster.remove()
 
 
     def upgrade(self):
     def upgrade(self):
         # WARNING: if multiple read-lockers want to upgrade, it will deadlock because they
         # WARNING: if multiple read-lockers want to upgrade, it will deadlock because they

+ 4 - 0
borg/testsuite/locking.py

@@ -64,6 +64,8 @@ class TestLock:
         lock2 = Lock(lockpath, exclusive=False, id=ID2).acquire()
         lock2 = Lock(lockpath, exclusive=False, id=ID2).acquire()
         assert len(lock1._roster.get(SHARED)) == 2
         assert len(lock1._roster.get(SHARED)) == 2
         assert len(lock1._roster.get(EXCLUSIVE)) == 0
         assert len(lock1._roster.get(EXCLUSIVE)) == 0
+        assert not lock1._roster.empty(SHARED, EXCLUSIVE)
+        assert lock1._roster.empty(EXCLUSIVE)
         lock1.release()
         lock1.release()
         lock2.release()
         lock2.release()
 
 
@@ -71,6 +73,7 @@ class TestLock:
         with Lock(lockpath, exclusive=True, id=ID1) as lock:
         with Lock(lockpath, exclusive=True, id=ID1) as lock:
             assert len(lock._roster.get(SHARED)) == 0
             assert len(lock._roster.get(SHARED)) == 0
             assert len(lock._roster.get(EXCLUSIVE)) == 1
             assert len(lock._roster.get(EXCLUSIVE)) == 1
+            assert not lock._roster.empty(SHARED, EXCLUSIVE)
 
 
     def test_upgrade(self, lockpath):
     def test_upgrade(self, lockpath):
         with Lock(lockpath, exclusive=False) as lock:
         with Lock(lockpath, exclusive=False) as lock:
@@ -78,6 +81,7 @@ class TestLock:
             lock.upgrade()  # NOP
             lock.upgrade()  # NOP
             assert len(lock._roster.get(SHARED)) == 0
             assert len(lock._roster.get(SHARED)) == 0
             assert len(lock._roster.get(EXCLUSIVE)) == 1
             assert len(lock._roster.get(EXCLUSIVE)) == 1
+            assert not lock._roster.empty(SHARED, EXCLUSIVE)
 
 
     def test_downgrade(self, lockpath):
     def test_downgrade(self, lockpath):
         with Lock(lockpath, exclusive=True) as lock:
         with Lock(lockpath, exclusive=True) as lock: