~bzr-pqm/bzr/bzr.dev

4988.10.5 by John Arbash Meinel
Merge bzr.dev 5021 to resolve NEWS
1
# Copyright (C) 2005-2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
577 by Martin Pool
- merge portable lock module from John
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
577 by Martin Pool
- merge portable lock module from John
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
577 by Martin Pool
- merge portable lock module from John
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
577 by Martin Pool
- merge portable lock module from John
16
1553.5.39 by Martin Pool
More lock docs
17
"""Locking using OS file locks or file existence.
577 by Martin Pool
- merge portable lock module from John
18
1553.5.46 by Martin Pool
doc
19
Note: This method of locking is generally deprecated in favour of LockDir, but
20
is used to lock local WorkingTrees, and by some old formats.  It's accessed
21
through Transport.lock_read(), etc.
577 by Martin Pool
- merge portable lock module from John
22
23
This module causes two methods, lock() and unlock() to be defined in
24
any way that works on the current platform.
25
26
It is not specified whether these locks are reentrant (i.e. can be
27
taken repeatedly by a single process) or whether they exclude
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
28
different threads in a single process.  That reentrancy is provided by
1553.5.39 by Martin Pool
More lock docs
29
LockableFiles.
615 by Martin Pool
Major rework of locking code:
30
31
This defines two classes: ReadLock and WriteLock, which can be
32
implemented in different ways on different platforms.  Both have an
33
unlock() method.
614 by Martin Pool
- unify two defintions of LockError
34
"""
577 by Martin Pool
- merge portable lock module from John
35
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
36
from __future__ import absolute_import
37
6538.1.11 by Aaron Bentley
Switch to much simpler implementation of restore_uncommitted.
38
import contextlib
1185.65.29 by Robert Collins
Implement final review suggestions.
39
import errno
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
40
import os
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
41
import sys
4509.3.25 by Martin Pool
Add an option for unlock errors to be non-fatal
42
import warnings
577 by Martin Pool
- merge portable lock module from John
43
2353.3.11 by John Arbash Meinel
Code cleanup
44
from bzrlib import (
4509.3.25 by Martin Pool
Add an option for unlock errors to be non-fatal
45
    debug,
2353.3.11 by John Arbash Meinel
Code cleanup
46
    errors,
47
    osutils,
48
    trace,
49
    )
5622.3.2 by Jelmer Vernooij
Add more lazily usable hook points.
50
from bzrlib.hooks import Hooks
6138.3.4 by Jonathan Riddell
add gettext() to uses of trace.note()
51
from bzrlib.i18n import gettext
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
52
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
53
class LockHooks(Hooks):
54
5622.3.10 by Jelmer Vernooij
Don't require arguments to hooks.
55
    def __init__(self):
56
        Hooks.__init__(self, "bzrlib.lock", "Lock.hooks")
5622.3.2 by Jelmer Vernooij
Add more lazily usable hook points.
57
        self.add_hook('lock_acquired',
58
            "Called with a bzrlib.lock.LockResult when a physical lock is "
59
            "acquired.", (1, 8))
60
        self.add_hook('lock_released',
61
            "Called with a bzrlib.lock.LockResult when a physical lock is "
62
            "released.", (1, 8))
63
        self.add_hook('lock_broken',
64
            "Called with a bzrlib.lock.LockResult when a physical lock is "
65
            "broken.", (1, 15))
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
66
67
68
class Lock(object):
69
    """Base class for locks.
70
71
    :cvar hooks: Hook dictionary for operations on locks.
72
    """
73
5622.3.10 by Jelmer Vernooij
Don't require arguments to hooks.
74
    hooks = LockHooks()
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
75
76
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
77
class LockResult(object):
3331.3.5 by Martin Pool
Move physical lock hooks onto new PhysicalLock class variable
78
    """Result of an operation on a lock; passed to a hook"""
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
79
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
80
    def __init__(self, lock_url, details=None):
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
81
        """Create a lock result for lock with optional details about the lock."""
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
82
        self.lock_url = lock_url
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
83
        self.details = details
84
85
    def __eq__(self, other):
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
86
        return self.lock_url == other.lock_url and self.details == other.details
1711.8.1 by John Arbash Meinel
Branch.lock_read/lock_write/unlock should handle failures
87
4327.1.1 by Vincent Ladeuil
Start addressing test failing when run with -Dlock.
88
    def __repr__(self):
4634.146.9 by Danny van Heumen
Changed representation of LockResult: separate path and nonce with a comma.
89
        return '%s(%s, %s)' % (self.__class__.__name__,
4327.1.1 by Vincent Ladeuil
Start addressing test failing when run with -Dlock.
90
                             self.lock_url, self.details)
91
577 by Martin Pool
- merge portable lock module from John
92
5200.3.6 by Robert Collins
Make all lock methods return Result objects, rather than lock_read returning self, as per John's review.
93
class LogicalLockResult(object):
94
    """The result of a lock_read/lock_write/lock_tree_write call on lockables.
95
96
    :ivar unlock: A callable which will unlock the lock.
97
    """
98
99
    def __init__(self, unlock):
100
        self.unlock = unlock
101
102
    def __repr__(self):
103
        return "LogicalLockResult(%s)" % (self.unlock)
104
105
106
4509.3.25 by Martin Pool
Add an option for unlock errors to be non-fatal
107
def cant_unlock_not_held(locked_object):
108
    """An attempt to unlock failed because the object was not locked.
109
110
    This provides a policy point from which we can generate either a warning 
111
    or an exception.
112
    """
113
    # This is typically masking some other error and called from a finally
4509.3.36 by Martin Pool
Review cleanups of typos and unneeded imports
114
    # block, so it's useful to have the option not to generate a new error
4509.3.25 by Martin Pool
Add an option for unlock errors to be non-fatal
115
    # here.  You can use -Werror to make it fatal.  It should possibly also
116
    # raise LockNotHeld.
4509.3.27 by Martin Pool
Change debug flag to -Dunlock and document it
117
    if 'unlock' in debug.debug_flags:
4509.3.25 by Martin Pool
Add an option for unlock errors to be non-fatal
118
        warnings.warn("%r is already unlocked" % (locked_object,),
119
            stacklevel=3)
120
    else:
121
        raise errors.LockNotHeld(locked_object)
122
123
3224.5.32 by Andrew Bennetts
Tidy conditional imports in bzrlib/lock.py as suggested by John's review.
124
try:
125
    import fcntl
126
    have_fcntl = True
127
except ImportError:
128
    have_fcntl = False
129
130
have_pywin32 = False
131
have_ctypes_win32 = False
132
if sys.platform == 'win32':
133
    import msvcrt
134
    try:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
135
        import win32file, pywintypes, winerror
3224.5.32 by Andrew Bennetts
Tidy conditional imports in bzrlib/lock.py as suggested by John's review.
136
        have_pywin32 = True
137
    except ImportError:
138
        pass
139
140
    try:
141
        import ctypes
142
        have_ctypes_win32 = True
143
    except ImportError:
144
        pass
145
146
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
147
class _OSLock(object):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
148
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
149
    def __init__(self):
150
        self.f = None
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
151
        self.filename = None
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
152
615 by Martin Pool
Major rework of locking code:
153
    def _open(self, filename, filemode):
2353.3.11 by John Arbash Meinel
Code cleanup
154
        self.filename = osutils.realpath(filename)
656 by Martin Pool
- create branch lock files if they don't exist
155
        try:
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
156
            self.f = open(self.filename, filemode)
656 by Martin Pool
- create branch lock files if they don't exist
157
            return self.f
158
        except IOError, e:
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
159
            if e.errno in (errno.EACCES, errno.EPERM):
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
160
                raise errors.LockFailed(self.filename, str(e))
656 by Martin Pool
- create branch lock files if they don't exist
161
            if e.errno != errno.ENOENT:
162
                raise
163
164
            # maybe this is an old branch (before may 2005)
2353.3.11 by John Arbash Meinel
Code cleanup
165
            trace.mutter("trying to create missing lock %r", self.filename)
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
166
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
167
            self.f = open(self.filename, 'wb+')
656 by Martin Pool
- create branch lock files if they don't exist
168
            return self.f
169
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
170
    def _clear_f(self):
171
        """Clear the self.f attribute cleanly."""
172
        if self.f:
173
            self.f.close()
174
            self.f = None
175
615 by Martin Pool
Major rework of locking code:
176
    def unlock(self):
177
        raise NotImplementedError()
178
179
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
180
_lock_classes = []
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
181
182
183
if have_fcntl:
615 by Martin Pool
Major rework of locking code:
184
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
185
    class _fcntl_FileLock(_OSLock):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
186
187
        def _unlock(self):
1185.9.2 by Harald Meland
Use fcntl.lockf() rather than fcntl.flock() to support NFS file systems.
188
            fcntl.lockf(self.f, fcntl.LOCK_UN)
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
189
            self._clear_f()
190
191
615 by Martin Pool
Major rework of locking code:
192
    class _fcntl_WriteLock(_fcntl_FileLock):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
193
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
194
        _open_locks = set()
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
195
615 by Martin Pool
Major rework of locking code:
196
        def __init__(self, filename):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
197
            super(_fcntl_WriteLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
198
            # Check we can grab a lock before we actually open the file.
199
            self.filename = osutils.realpath(filename)
4523.4.9 by John Arbash Meinel
Change the flags around a bit.
200
            if self.filename in _fcntl_WriteLock._open_locks:
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
201
                self._clear_f()
202
                raise errors.LockContention(self.filename)
4523.4.9 by John Arbash Meinel
Change the flags around a bit.
203
            if self.filename in _fcntl_ReadLock._open_locks:
4523.4.10 by John Arbash Meinel
Update the various documentation and use strict_locks instead of strict-locks.
204
                if 'strict_locks' in debug.debug_flags:
4523.4.9 by John Arbash Meinel
Change the flags around a bit.
205
                    self._clear_f()
206
                    raise errors.LockContention(self.filename)
207
                else:
208
                    trace.mutter('Write lock taken w/ an open read lock on: %s'
209
                                 % (self.filename,))
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
210
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
211
            self._open(self.filename, 'rb+')
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
212
            # reserve a slot for this lock - even if the lockf call fails,
5009.1.1 by Vincent Ladeuil
(trivial) Fix typos
213
            # at this point unlock() will be called, because self.f is set.
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
214
            # TODO: make this fully threadsafe, if we decide we care.
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
215
            _fcntl_WriteLock._open_locks.add(self.filename)
615 by Martin Pool
Major rework of locking code:
216
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
217
                # LOCK_NB will cause IOError to be raised if we can't grab a
218
                # lock right away.
219
                fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
220
            except IOError, e:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
221
                if e.errno in (errno.EAGAIN, errno.EACCES):
222
                    # We couldn't grab the lock
223
                    self.unlock()
1185.65.29 by Robert Collins
Implement final review suggestions.
224
                # we should be more precise about whats a locking
225
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
226
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
227
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
228
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
229
            _fcntl_WriteLock._open_locks.remove(self.filename)
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
230
            self._unlock()
231
232
615 by Martin Pool
Major rework of locking code:
233
    class _fcntl_ReadLock(_fcntl_FileLock):
1185.65.29 by Robert Collins
Implement final review suggestions.
234
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
235
        _open_locks = {}
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
236
2353.4.11 by John Arbash Meinel
Remove the unused _ignore_write_lock parameter.
237
        def __init__(self, filename):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
238
            super(_fcntl_ReadLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
239
            self.filename = osutils.realpath(filename)
4523.4.9 by John Arbash Meinel
Change the flags around a bit.
240
            if self.filename in _fcntl_WriteLock._open_locks:
4523.4.10 by John Arbash Meinel
Update the various documentation and use strict_locks instead of strict-locks.
241
                if 'strict_locks' in debug.debug_flags:
4523.4.14 by John Arbash Meinel
Fix the direct lock tests.
242
                    # We raise before calling _open so we don't need to
243
                    # _clear_f
4523.4.9 by John Arbash Meinel
Change the flags around a bit.
244
                    raise errors.LockContention(self.filename)
245
                else:
246
                    trace.mutter('Read lock taken w/ an open write lock on: %s'
247
                                 % (self.filename,))
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
248
            _fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
249
            _fcntl_ReadLock._open_locks[self.filename] += 1
1185.65.29 by Robert Collins
Implement final review suggestions.
250
            self._open(filename, 'rb')
615 by Martin Pool
Major rework of locking code:
251
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
252
                # LOCK_NB will cause IOError to be raised if we can't grab a
253
                # lock right away.
254
                fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
255
            except IOError, e:
256
                # we should be more precise about whats a locking
257
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
258
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
259
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
260
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
261
            count = _fcntl_ReadLock._open_locks[self.filename]
262
            if count == 1:
263
                del _fcntl_ReadLock._open_locks[self.filename]
264
            else:
265
                _fcntl_ReadLock._open_locks[self.filename] = count - 1
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
266
            self._unlock()
267
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
268
        def temporary_write_lock(self):
269
            """Try to grab a write lock on the file.
270
271
            On platforms that support it, this will upgrade to a write lock
272
            without unlocking the file.
273
            Otherwise, this will release the read lock, and try to acquire a
274
            write lock.
275
276
            :return: A token which can be used to switch back to a read lock.
277
            """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
278
            if self.filename in _fcntl_WriteLock._open_locks:
279
                raise AssertionError('file already locked: %r'
280
                    % (self.filename,))
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
281
            try:
282
                wlock = _fcntl_TemporaryWriteLock(self)
283
            except errors.LockError:
284
                # We didn't unlock, so we can just return 'self'
285
                return False, self
286
            return True, wlock
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
287
288
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
289
    class _fcntl_TemporaryWriteLock(_OSLock):
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
290
        """A token used when grabbing a temporary_write_lock.
291
292
        Call restore_read_lock() when you are done with the write lock.
293
        """
294
295
        def __init__(self, read_lock):
296
            super(_fcntl_TemporaryWriteLock, self).__init__()
297
            self._read_lock = read_lock
298
            self.filename = read_lock.filename
299
300
            count = _fcntl_ReadLock._open_locks[self.filename]
301
            if count > 1:
302
                # Something else also has a read-lock, so we cannot grab a
303
                # write lock.
304
                raise errors.LockContention(self.filename)
305
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
306
            if self.filename in _fcntl_WriteLock._open_locks:
307
                raise AssertionError('file already locked: %r'
308
                    % (self.filename,))
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
309
310
            # See if we can open the file for writing. Another process might
311
            # have a read lock. We don't use self._open() because we don't want
312
            # to create the file if it exists. That would have already been
313
            # done by _fcntl_ReadLock
314
            try:
315
                new_f = open(self.filename, 'rb+')
316
            except IOError, e:
317
                if e.errno in (errno.EACCES, errno.EPERM):
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
318
                    raise errors.LockFailed(self.filename, str(e))
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
319
                raise
320
            try:
321
                # LOCK_NB will cause IOError to be raised if we can't grab a
322
                # lock right away.
2379.3.1 by John Arbash Meinel
Cherry-pick the 2 locking fixes from the 0.15 branch.
323
                fcntl.lockf(new_f, fcntl.LOCK_EX | fcntl.LOCK_NB)
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
324
            except IOError, e:
325
                # TODO: Raise a more specific error based on the type of error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
326
                raise errors.LockContention(self.filename, e)
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
327
            _fcntl_WriteLock._open_locks.add(self.filename)
328
329
            self.f = new_f
330
331
        def restore_read_lock(self):
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
332
            """Restore the original ReadLock."""
333
            # For fcntl, since we never released the read lock, just release the
334
            # write lock, and return the original lock.
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
335
            fcntl.lockf(self.f, fcntl.LOCK_UN)
336
            self._clear_f()
337
            _fcntl_WriteLock._open_locks.remove(self.filename)
338
            # Avoid reference cycles
339
            read_lock = self._read_lock
340
            self._read_lock = None
341
            return read_lock
342
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
343
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
344
    _lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))
577 by Martin Pool
- merge portable lock module from John
345
2353.3.11 by John Arbash Meinel
Code cleanup
346
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
347
if have_pywin32 and sys.platform == 'win32':
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
348
    if os.path.supports_unicode_filenames:
349
        # for Windows NT/2K/XP/etc
350
        win32file_CreateFile = win32file.CreateFileW
351
    else:
352
        # for Windows 98
353
        win32file_CreateFile = win32file.CreateFile
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
354
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
355
    class _w32c_FileLock(_OSLock):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
356
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
357
        def _open(self, filename, access, share, cflags, pymode):
358
            self.filename = osutils.realpath(filename)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
359
            try:
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
360
                self._handle = win32file_CreateFile(filename, access, share,
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
361
                    None, win32file.OPEN_ALWAYS,
362
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
363
            except pywintypes.error, e:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
364
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
365
                    raise errors.LockFailed(filename, e)
366
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
367
                    raise errors.LockContention(filename, e)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
368
                raise
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
369
            fd = win32file._open_osfhandle(self._handle, cflags)
370
            self.f = os.fdopen(fd, pymode)
371
            return self.f
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
372
373
        def unlock(self):
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
374
            self._clear_f()
375
            self._handle = None
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
376
377
378
    class _w32c_ReadLock(_w32c_FileLock):
379
        def __init__(self, filename):
380
            super(_w32c_ReadLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
381
            self._open(filename, win32file.GENERIC_READ,
382
                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
383
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
384
        def temporary_write_lock(self):
385
            """Try to grab a write lock on the file.
386
387
            On platforms that support it, this will upgrade to a write lock
388
            without unlocking the file.
389
            Otherwise, this will release the read lock, and try to acquire a
390
            write lock.
391
392
            :return: A token which can be used to switch back to a read lock.
393
            """
394
            # I can't find a way to upgrade a read lock to a write lock without
395
            # unlocking first. So here, we do just that.
396
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
397
            try:
398
                wlock = _w32c_WriteLock(self.filename)
399
            except errors.LockError:
400
                return False, _w32c_ReadLock(self.filename)
401
            return True, wlock
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
402
2353.3.11 by John Arbash Meinel
Code cleanup
403
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
404
    class _w32c_WriteLock(_w32c_FileLock):
405
        def __init__(self, filename):
406
            super(_w32c_WriteLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
407
            self._open(filename,
408
                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
409
                os.O_RDWR, "rb+")
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
410
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
411
        def restore_read_lock(self):
412
            """Restore the original ReadLock."""
413
            # For win32 we had to completely let go of the original lock, so we
414
            # just unlock and create a new read lock.
415
            self.unlock()
416
            return _w32c_ReadLock(self.filename)
417
2353.3.11 by John Arbash Meinel
Code cleanup
418
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
419
    _lock_classes.append(('pywin32', _w32c_WriteLock, _w32c_ReadLock))
420
2353.3.11 by John Arbash Meinel
Code cleanup
421
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
422
if have_ctypes_win32:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
423
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
424
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
425
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
426
    if os.path.supports_unicode_filenames:
427
        _function_name = "CreateFileW"
428
        LPTSTR = LPCWSTR
429
    else:
430
        _function_name = "CreateFileA"
431
        class LPTSTR(LPCSTR):
432
            def __new__(cls, obj):
433
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
434
435
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
436
    _CreateFile = ctypes.WINFUNCTYPE(
437
            HANDLE,                # return value
438
            LPTSTR,                # lpFileName
439
            DWORD,                 # dwDesiredAccess
440
            DWORD,                 # dwShareMode
441
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
442
            DWORD,                 # dwCreationDisposition
443
            DWORD,                 # dwFlagsAndAttributes
444
            HANDLE                 # hTemplateFile
445
        )((_function_name, ctypes.windll.kernel32))
4523.4.1 by John Arbash Meinel
Start adding some direct testing for read and write locks.
446
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
447
    INVALID_HANDLE_VALUE = -1
4523.4.1 by John Arbash Meinel
Start adding some direct testing for read and write locks.
448
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
449
    GENERIC_READ = 0x80000000
450
    GENERIC_WRITE = 0x40000000
451
    FILE_SHARE_READ = 1
452
    OPEN_ALWAYS = 4
453
    FILE_ATTRIBUTE_NORMAL = 128
4523.4.1 by John Arbash Meinel
Start adding some direct testing for read and write locks.
454
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
455
    ERROR_ACCESS_DENIED = 5
456
    ERROR_SHARING_VIOLATION = 32
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
457
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
458
    class _ctypes_FileLock(_OSLock):
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
459
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
460
        def _open(self, filename, access, share, cflags, pymode):
461
            self.filename = osutils.realpath(filename)
462
            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
463
                FILE_ATTRIBUTE_NORMAL, 0)
464
            if handle in (INVALID_HANDLE_VALUE, 0):
465
                e = ctypes.WinError()
4459.3.2 by Martin
Fix issue with change of semantics of WindowsError.errno in Python 2.5
466
                if e.args[0] == ERROR_ACCESS_DENIED:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
467
                    raise errors.LockFailed(filename, e)
4459.3.2 by Martin
Fix issue with change of semantics of WindowsError.errno in Python 2.5
468
                if e.args[0] == ERROR_SHARING_VIOLATION:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
469
                    raise errors.LockContention(filename, e)
470
                raise e
471
            fd = msvcrt.open_osfhandle(handle, cflags)
472
            self.f = os.fdopen(fd, pymode)
473
            return self.f
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
474
475
        def unlock(self):
4404.1.1 by Martin
Correct use of GetLastError in ctypes windows locking code
476
            self._clear_f()
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
477
478
479
    class _ctypes_ReadLock(_ctypes_FileLock):
480
        def __init__(self, filename):
481
            super(_ctypes_ReadLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
482
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
483
                "rb")
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
484
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
485
        def temporary_write_lock(self):
486
            """Try to grab a write lock on the file.
487
488
            On platforms that support it, this will upgrade to a write lock
489
            without unlocking the file.
490
            Otherwise, this will release the read lock, and try to acquire a
491
            write lock.
492
493
            :return: A token which can be used to switch back to a read lock.
494
            """
495
            # I can't find a way to upgrade a read lock to a write lock without
496
            # unlocking first. So here, we do just that.
497
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
498
            try:
499
                wlock = _ctypes_WriteLock(self.filename)
500
            except errors.LockError:
501
                return False, _ctypes_ReadLock(self.filename)
502
            return True, wlock
2353.3.11 by John Arbash Meinel
Code cleanup
503
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
504
    class _ctypes_WriteLock(_ctypes_FileLock):
505
        def __init__(self, filename):
506
            super(_ctypes_WriteLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
507
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
508
                "rb+")
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
509
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
510
        def restore_read_lock(self):
511
            """Restore the original ReadLock."""
512
            # For win32 we had to completely let go of the original lock, so we
513
            # just unlock and create a new read lock.
514
            self.unlock()
2353.4.6 by John Arbash Meinel
ctypes locks should return ctypes locks.
515
            return _ctypes_ReadLock(self.filename)
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
516
2353.3.11 by John Arbash Meinel
Code cleanup
517
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
518
    _lock_classes.append(('ctypes', _ctypes_WriteLock, _ctypes_ReadLock))
519
520
521
if len(_lock_classes) == 0:
2353.3.11 by John Arbash Meinel
Code cleanup
522
    raise NotImplementedError(
523
        "We must have one of fcntl, pywin32, or ctypes available"
524
        " to support OS locking."
525
        )
526
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
527
528
# We default to using the first available lock class.
529
_lock_type, WriteLock, ReadLock = _lock_classes[0]
530
4731.1.2 by Andrew Bennetts
Refactor to reduce duplication.
531
532
class _RelockDebugMixin(object):
533
    """Mixin support for -Drelock flag.
534
535
    Add this as a base class then call self._note_lock with 'r' or 'w' when
536
    acquiring a read- or write-lock.  If this object was previously locked (and
537
    locked the same way), and -Drelock is set, then this will trace.note a
538
    message about it.
539
    """
6076.1.1 by Vincent Ladeuil
Add the missing config stacks and store
540
4731.1.2 by Andrew Bennetts
Refactor to reduce duplication.
541
    _prev_lock = None
542
543
    def _note_lock(self, lock_type):
544
        if 'relock' in debug.debug_flags and self._prev_lock == lock_type:
545
            if lock_type == 'r':
546
                type_name = 'read'
547
            else:
548
                type_name = 'write'
6147.1.1 by Jonathan Riddell
use .format() instead of % for string formatting where there are multiple formats in one string to allow for translations
549
            trace.note(gettext('{0!r} was {1} locked again'), self, type_name)
4731.1.2 by Andrew Bennetts
Refactor to reduce duplication.
550
        self._prev_lock = lock_type
551
6538.1.11 by Aaron Bentley
Switch to much simpler implementation of restore_uncommitted.
552
@contextlib.contextmanager
553
def write_locked(lockable):
554
    lockable.lock_write()
555
    try:
556
        yield lockable
557
    finally:
558
        lockable.unlock()