Rev 4736: (mbp) cope with empty lockdir info files in file:///home/pqm/archives/thelove/bzr/2.0/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Feb 26 08:00:47 GMT 2010


At file:///home/pqm/archives/thelove/bzr/2.0/

------------------------------------------------------------
revno: 4736 [merge]
revision-id: pqm at pqm.ubuntu.com-20100226080046-0y4iuyq2skuzq19m
parent: pqm at pqm.ubuntu.com-20100219092738-4kfhdlnl9ff36cwg
parent: mbp at canonical.com-20100226065151-ayrxy1hd1et5f89y
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: 2.0
timestamp: Fri 2010-02-26 08:00:46 +0000
message:
  (mbp) cope with empty lockdir info files
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/lockdir.py              lockdir.py-20060220222025-98258adf27fbdda3
  bzrlib/tests/test_lockdir.py   test_lockdir.py-20060220222025-33d4221569a3d600
=== modified file 'NEWS'
--- a/NEWS	2010-02-19 07:13:45 +0000
+++ b/NEWS	2010-02-25 07:34:06 +0000
@@ -17,6 +17,11 @@
 * Avoid ``malloc(0)`` in ``patiencediff``, which is non-portable.
   (Martin Pool, #331095)
 
+* Cope with the lockdir ``held/info`` file being empty, which seems to
+  happen fairly often if the process is suddenly interrupted while taking
+  a lock.
+  (Martin Pool, #185103)
+
 * Handle renames correctly when there are files or directories that 
   differ only in case.  (Chris Jones, Martin Pool, #368931)
 

=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py	2009-12-21 06:17:05 +0000
+++ b/bzrlib/lockdir.py	2010-02-26 06:51:51 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006, 2007, 2008 Canonical Ltd
+# Copyright (C) 2006, 2007, 2008, 2010 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -250,7 +250,7 @@
         if info is None:
             raise LockFailed(self, "lock was renamed into place, but "
                 "now is missing!")
-        if info['nonce'] != self.nonce:
+        if info.get('nonce') != self.nonce:
             self._trace("rename succeeded, "
                 "but lock is still held by someone else")
             raise LockContention(self)
@@ -427,7 +427,7 @@
     def peek(self):
         """Check if the lock is held by anyone.
 
-        If it is held, this returns the lock info structure as a rio Stanza,
+        If it is held, this returns the lock info structure as a dict
         which contains some information about the current lock holder.
         Otherwise returns None.
         """
@@ -456,7 +456,14 @@
         return s.to_string()
 
     def _parse_info(self, info_file):
-        return rio.read_stanza(info_file.readlines()).as_dict()
+        stanza = rio.read_stanza(info_file.readlines())
+        if stanza is None:
+            # see bug 185013; we fairly often end up with the info file being
+            # empty after an interruption; we could log a message here but
+            # there may not be much we can say
+            return {}
+        else:
+            return stanza.as_dict()
 
     def attempt_lock(self):
         """Take the lock; fail if it's already held.
@@ -604,11 +611,16 @@
     def _format_lock_info(self, info):
         """Turn the contents of peek() into something for the user"""
         lock_url = self.transport.abspath(self.path)
-        delta = time.time() - int(info['start_time'])
+        start_time = info.get('start_time')
+        if start_time is None:
+            time_ago = '(unknown)'
+        else:
+            time_ago = format_delta(time.time() - int(info['start_time']))
         return [
             'lock %s' % (lock_url,),
-            'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
-            'locked %s' % (format_delta(delta),),
+            'held by %s on host %s [process #%s]' %
+                tuple([info.get(x, '<unknown>') for x in ['user', 'hostname', 'pid']]),
+            'locked %s' % (time_ago,),
             ]
 
     def validate_token(self, token):

=== modified file 'bzrlib/tests/test_lockdir.py'
--- a/bzrlib/tests/test_lockdir.py	2009-06-23 08:43:05 +0000
+++ b/bzrlib/tests/test_lockdir.py	2010-02-26 06:51:51 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006, 2007, 2008 Canonical Ltd
+# Copyright (C) 2006, 2007, 2008, 2010 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -669,6 +669,25 @@
         # no kibble
         check_dir(['held'])
 
+    def test_no_lockdir_info(self):
+        """We can cope with empty info files."""
+        # This seems like a fairly common failure case - see
+        # <https://bugs.edge.launchpad.net/bzr/+bug/185103> and all its dupes.
+        # Processes are often interrupted after opening the file
+        # before the actual contents are committed.
+        t = self.get_transport()
+        t.mkdir('test_lock')
+        t.mkdir('test_lock/held')
+        t.put_bytes('test_lock/held/info', '')
+        lf = LockDir(t, 'test_lock')
+        info = lf.peek()
+        formatted_info = lf._format_lock_info(info)
+        self.assertEquals(
+            ['lock %s' % t.abspath('test_lock'),
+             'held by <unknown> on host <unknown> [process #<unknown>]',
+             'locked (unknown)'],
+            formatted_info)
+
 
 class TestLockDirHooks(TestCaseWithTransport):
 




More information about the bazaar-commits mailing list