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