Rev 2569: Better handling in LockDir of rename that moves one directory within another in http://sourcefrog.net/bzr/dlock
Martin Pool
mbp at sourcefrog.net
Tue Jul 3 08:24:44 BST 2007
At http://sourcefrog.net/bzr/dlock
------------------------------------------------------------
revno: 2569
revision-id: mbp at sourcefrog.net-20070703072442-y3pwex52rrtsa8gg
parent: mbp at sourcefrog.net-20070703070030-vayxt8668a4nappy
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: dlock
timestamp: Tue 2007-07-03 17:24:42 +1000
message:
Better handling in LockDir of rename that moves one directory within another
modified:
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/tests/test_lockdir.py test_lockdir.py-20060220222025-33d4221569a3d600
bzrlib/transport/brokenrename.py brokenrename.py-20070628050843-mbwebk50srn93rut-1
=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py 2007-07-03 07:00:30 +0000
+++ b/bzrlib/lockdir.py 2007-07-03 07:24:42 +0000
@@ -216,7 +216,7 @@
self._trace("lock_write...")
start_time = time.time()
tmpname = self._create_pending_dir()
-
+
self.transport.rename(tmpname, self._held_dir)
# We must check we really got the lock, because Launchpad's sftp
# server at one time had a bug were the rename would successfully
@@ -258,7 +258,6 @@
self.create(mode=self._dir_modebits)
# After creating the lock directory, try again
self.transport.mkdir(tmpname)
-
self.nonce = rand_chars(20)
info_bytes = self._prepare_info()
# We use put_file_non_atomic because we just created a new unique
@@ -291,7 +290,19 @@
self.transport.rename(self._held_dir, tmpname)
self._lock_held = False
self.transport.delete(tmpname + self.__INFO_NAME)
- self.transport.rmdir(tmpname)
+ try:
+ self.transport.rmdir(tmpname)
+ except DirectoryNotEmpty, e:
+ # There might have been junk left over by a rename that moved
+ # another locker within the 'held' directory. do a slower
+ # deletion where we list the directory and remove everything
+ # within it.
+ #
+ # Maybe this should be broader to allow for ftp servers with
+ # non-specific error messages?
+ self._trace("doing recursive deletion of non-empty directory "
+ "%s", tmpname)
+ self.transport.delete_tree(tmpname)
self._trace("... unlock succeeded after %dms",
(time.time() - start_time) * 1000)
=== modified file 'bzrlib/tests/test_lockdir.py'
--- a/bzrlib/tests/test_lockdir.py 2007-06-28 08:09:01 +0000
+++ b/bzrlib/tests/test_lockdir.py 2007-07-03 07:24:42 +0000
@@ -641,13 +641,16 @@
t = transport.get_transport('brokenrename+' + self.get_url())
ld1 = LockDir(t, 'test_lock')
ld1.create()
+
+ import pdb;pdb.set_trace()
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
- e = self.assertRaises(errors.LockError, ld2.attempt_lock)
- self.assertContainsRe(str(e),
- "rename succeeded, but lock is still held by someone else")
+ # we should fail to lock
+ e = self.assertRaises(errors.LockContention, ld2.attempt_lock)
+ # now the original caller should succeed in unlocking
+ ld1.unlock()
+ # and there should be nothing left over
+ self.assertEquals([], t.list_dir('test_lock'))
def test_failed_lock_leaves_no_trash(self):
# if we fail to acquire the lock, we don't leave pending directories
=== modified file 'bzrlib/transport/brokenrename.py'
--- a/bzrlib/transport/brokenrename.py 2007-06-28 06:00:52 +0000
+++ b/bzrlib/transport/brokenrename.py 2007-07-03 07:24:42 +0000
@@ -19,7 +19,10 @@
from stat import S_ISDIR
-import bzrlib.errors as errors
+from bzrlib import (
+ errors,
+ urlutils,
+ )
from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
@@ -35,6 +38,8 @@
"""See Transport.rename().
"""
try:
+ if self._decorated.has(rel_to):
+ rel_to = urlutils.join(rel_to, urlutils.basename(rel_from))
self._decorated.rename(rel_from, rel_to)
except (errors.DirectoryNotEmpty, errors.FileExists), e:
# absorb the error
More information about the bazaar-commits
mailing list