Rev 2563: Add new BrokenRenameTransportDecorator in http://sourcefrog.net/bzr/dlock

Martin Pool mbp at sourcefrog.net
Thu Jun 28 07:00:44 BST 2007


At http://sourcefrog.net/bzr/dlock

------------------------------------------------------------
revno: 2563
revision-id: mbp at sourcefrog.net-20070628060043-oz977l5a4u2od2ri
parent: mbp at sourcefrog.net-20070627093945-36tc2vu397tk1k6a
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: dlock
timestamp: Thu 2007-06-28 16:00:43 +1000
message:
  Add new BrokenRenameTransportDecorator
added:
  bzrlib/transport/brokenrename.py brokenrename.py-20070628050843-mbwebk50srn93rut-1
modified:
  bzrlib/lockdir.py              lockdir.py-20060220222025-98258adf27fbdda3
  bzrlib/tests/test_lockdir.py   test_lockdir.py-20060220222025-33d4221569a3d600
  bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
=== added file 'bzrlib/transport/brokenrename.py'
--- a/bzrlib/transport/brokenrename.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/transport/brokenrename.py	2007-06-28 06:00:43 +0000
@@ -0,0 +1,55 @@
+# Copyright (C) 2007 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Transport implementation that doesn't detect clashing renames.
+"""
+
+from stat import S_ISDIR
+
+import bzrlib.errors as errors
+from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
+
+
+class BrokenRenameTransportDecorator(TransportDecorator):
+    """A transport that fails to detect clashing renames"""
+
+    @classmethod
+    def _get_url_prefix(self):
+        """FakeNFS transports are identified by 'brokenrename+'"""
+        return 'brokenrename+'
+
+    def rename(self, rel_from, rel_to):
+        """See Transport.rename().
+        """
+        try:
+            self._decorated.rename(rel_from, rel_to)
+        except (errors.DirectoryNotEmpty, errors.FileExists), e:
+            # absorb the error
+            return
+
+
+class BrokenRenameServer(DecoratorServer):
+    """Server for the BrokenRenameTransportDecorator for testing with."""
+
+    def get_decorator_class(self):
+        return BrokenRenameTransportDecorator
+
+
+def get_test_permutations():
+    """Return the permutations to be used in testing."""
+    # we don't use this for general testing, only for the tests that
+    # specifically want it
+    return []

=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py	2007-06-27 09:22:40 +0000
+++ b/bzrlib/lockdir.py	2007-06-28 06:00:43 +0000
@@ -194,6 +194,7 @@
         instead.
 
         :return: The lock token.
+        :raises LockContention: if the lock is held by someone else.
         """
         if self._fake_read_lock:
             raise LockContention(self)
@@ -202,7 +203,7 @@
         try:
             self._trace("lock_write...")
             start_time = time.time()
-            tmpname = '%s/pending.%s.tmp' % (self.path, rand_chars(20))
+            tmpname = '%s/%s.tmp' % (self.path, rand_chars(10))
             try:
                 self.transport.mkdir(tmpname)
             except NoSuchFile:
@@ -210,7 +211,6 @@
                 # which is okay, it will be caught later and determined
                 # to be a LockContention.
                 self.create(mode=self._dir_modebits)
-                
                 # After creating the lock directory, try again
                 self.transport.mkdir(tmpname)
 
@@ -224,11 +224,14 @@
                                                 info_bytes)
 
             self.transport.rename(tmpname, self._held_dir)
+            # We must confirm here, because Launchpad's sftp server at one
+            # time had a bug were the rename would successfully move the new
+            # directory into the existing directory, which was incorrect.
+            # It's possible some other servers or filesystems will have a
+            # similar bug allowing someone to think they got the lock when
+            # it's already held.
+            ## self.confirm()
             self._lock_held = True
-            # we used to do self.confirm() at this point, but it's really
-            # unnecessary, we have no substantial chance of having it broken
-            # just as it's acquired, and we believe that this lock design is
-            # safe on all platforms.
             # FIXME: we should remove the pending lock if we fail, 
             # https://bugs.launchpad.net/bzr/+bug/109169
         except errors.PermissionDenied:

=== modified file 'bzrlib/tests/test_lockdir.py'
--- a/bzrlib/tests/test_lockdir.py	2007-06-27 09:17:22 +0000
+++ b/bzrlib/tests/test_lockdir.py	2007-06-28 06:00:43 +0000
@@ -27,6 +27,7 @@
     errors,
     osutils,
     tests,
+    transport,
     )
 from bzrlib.errors import (
         LockBreakMismatch,
@@ -633,3 +634,18 @@
         ld2 = self.get_lock()
         t2 = ld2.lock_write(token)
         self.assertEqual(token, t2)
+
+    def test_lock_with_buggy_rename(self):
+        # test that lock acquisition handles servers which pretend they
+        # renamed correctly but that actually fail
+        t = transport.get_transport('brokenrename+' + self.get_url())
+        ld1 = LockDir(t, 'test_lock')
+        ld1.create()
+        ld1.attempt_lock()
+        ld2 = LockDir(t, 'test_lock')
+        # we should notice that we failed to lock, even though the transport
+        # has the wrong rename behaviour
+        self.assertRaises(errors.LockContention, ld2.attempt_lock)
+        
+
+

=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py	2007-05-08 20:00:50 +0000
+++ b/bzrlib/transport/__init__.py	2007-06-28 06:00:43 +0000
@@ -1304,8 +1304,14 @@
 #              help="This modifier converts any transport to be readonly."
             )
 register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
+
 register_transport_proto('fakenfs+')
 register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
+
+register_transport_proto('brokenrename+')
+register_lazy_transport('brokenrename+', 'bzrlib.transport.brokenrename',
+        'BrokenRenameTransportDecorator')
+
 register_transport_proto('vfat+')
 register_lazy_transport('vfat+',
                         'bzrlib.transport.fakevfat',




More information about the bazaar-commits mailing list