~bzr-pqm/bzr/bzr.dev

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