/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
38
import sys
577 by Martin Pool
- merge portable lock module from John
39
2353.3.11 by John Arbash Meinel
Code cleanup
40
from bzrlib import (
41
    errors,
42
    osutils,
43
    trace,
44
    )
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
45
from bzrlib.hooks import HookPoint, Hooks
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
46
47
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
48
class LockHooks(Hooks):
49
50
    def __init__(self):
51
        Hooks.__init__(self)
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
52
        self.create_hook(HookPoint('lock_acquired',
53
            "Called with a bzrlib.lock.LockResult when a physical lock is "
54
            "acquired.", (1, 8), None))
55
        self.create_hook(HookPoint('lock_released',
56
            "Called with a bzrlib.lock.LockResult when a physical lock is "
57
            "released.", (1, 8), None))
4327.1.2 by Vincent Ladeuil
Introduce a new lock_broken hook.
58
        self.create_hook(HookPoint('lock_broken',
59
            "Called with a bzrlib.lock.LockResult when a physical lock is "
60
            "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
61
62
63
class Lock(object):
64
    """Base class for locks.
65
66
    :cvar hooks: Hook dictionary for operations on locks.
67
    """
68
69
    hooks = LockHooks()
70
71
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
72
class LockResult(object):
3331.3.5 by Martin Pool
Move physical lock hooks onto new PhysicalLock class variable
73
    """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
74
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
75
    def __init__(self, lock_url, details=None):
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
76
        """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.
77
        self.lock_url = lock_url
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
78
        self.details = details
79
80
    def __eq__(self, other):
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
81
        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
82
4327.1.1 by Vincent Ladeuil
Start addressing test failing when run with -Dlock.
83
    def __repr__(self):
84
        return '%s(%s%s)' % (self.__class__.__name__,
85
                             self.lock_url, self.details)
86
577 by Martin Pool
- merge portable lock module from John
87
3224.5.32 by Andrew Bennetts
Tidy conditional imports in bzrlib/lock.py as suggested by John's review.
88
try:
89
    import fcntl
90
    have_fcntl = True
91
except ImportError:
92
    have_fcntl = False
93
94
have_pywin32 = False
95
have_ctypes_win32 = False
96
if sys.platform == 'win32':
97
    import msvcrt
98
    try:
99
        import win32con, win32file, pywintypes, winerror
100
        have_pywin32 = True
101
    except ImportError:
102
        pass
103
104
    try:
105
        import ctypes
106
        have_ctypes_win32 = True
107
    except ImportError:
108
        pass
109
110
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
111
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.
112
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
113
    def __init__(self):
114
        self.f = None
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
115
        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.
116
615 by Martin Pool
Major rework of locking code:
117
    def _open(self, filename, filemode):
2353.3.11 by John Arbash Meinel
Code cleanup
118
        self.filename = osutils.realpath(filename)
656 by Martin Pool
- create branch lock files if they don't exist
119
        try:
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
120
            self.f = open(self.filename, filemode)
656 by Martin Pool
- create branch lock files if they don't exist
121
            return self.f
122
        except IOError, e:
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
123
            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).
124
                raise errors.LockFailed(self.filename, str(e))
656 by Martin Pool
- create branch lock files if they don't exist
125
            if e.errno != errno.ENOENT:
126
                raise
127
128
            # maybe this is an old branch (before may 2005)
2353.3.11 by John Arbash Meinel
Code cleanup
129
            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
130
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
131
            self.f = open(self.filename, 'wb+')
656 by Martin Pool
- create branch lock files if they don't exist
132
            return self.f
133
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
134
    def _clear_f(self):
135
        """Clear the self.f attribute cleanly."""
136
        if self.f:
137
            self.f.close()
138
            self.f = None
139
615 by Martin Pool
Major rework of locking code:
140
    def __del__(self):
141
        if self.f:
142
            from warnings import warn
143
            warn("lock on %r not released" % self.f)
144
            self.unlock()
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
145
615 by Martin Pool
Major rework of locking code:
146
    def unlock(self):
147
        raise NotImplementedError()
148
149
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
150
_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.
151
152
153
if have_fcntl:
154
    LOCK_SH = fcntl.LOCK_SH
155
    LOCK_NB = fcntl.LOCK_NB
156
    lock_EX = fcntl.LOCK_EX
157
615 by Martin Pool
Major rework of locking code:
158
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
159
    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.
160
161
        def _unlock(self):
1185.9.2 by Harald Meland
Use fcntl.lockf() rather than fcntl.flock() to support NFS file systems.
162
            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.
163
            self._clear_f()
164
165
615 by Martin Pool
Major rework of locking code:
166
    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.
167
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
168
        _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.
169
615 by Martin Pool
Major rework of locking code:
170
        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.
171
            super(_fcntl_WriteLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
172
            # Check we can grab a lock before we actually open the file.
173
            self.filename = osutils.realpath(filename)
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
174
            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.
175
                self._clear_f()
176
                raise errors.LockContention(self.filename)
177
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
178
            self._open(self.filename, 'rb+')
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
179
            # reserve a slot for this lock - even if the lockf call fails,
180
            # at thisi point unlock() will be called, because self.f is set.
181
            # 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.
182
            _fcntl_WriteLock._open_locks.add(self.filename)
615 by Martin Pool
Major rework of locking code:
183
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
184
                # LOCK_NB will cause IOError to be raised if we can't grab a
185
                # lock right away.
186
                fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
187
            except IOError, e:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
188
                if e.errno in (errno.EAGAIN, errno.EACCES):
189
                    # We couldn't grab the lock
190
                    self.unlock()
1185.65.29 by Robert Collins
Implement final review suggestions.
191
                # we should be more precise about whats a locking
192
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
193
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
194
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
195
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
196
            _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.
197
            self._unlock()
198
199
615 by Martin Pool
Major rework of locking code:
200
    class _fcntl_ReadLock(_fcntl_FileLock):
1185.65.29 by Robert Collins
Implement final review suggestions.
201
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
202
        _open_locks = {}
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
203
2353.4.11 by John Arbash Meinel
Remove the unused _ignore_write_lock parameter.
204
        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.
205
            super(_fcntl_ReadLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
206
            self.filename = osutils.realpath(filename)
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
207
            _fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
208
            _fcntl_ReadLock._open_locks[self.filename] += 1
1185.65.29 by Robert Collins
Implement final review suggestions.
209
            self._open(filename, 'rb')
615 by Martin Pool
Major rework of locking code:
210
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
211
                # LOCK_NB will cause IOError to be raised if we can't grab a
212
                # lock right away.
213
                fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
214
            except IOError, e:
215
                # we should be more precise about whats a locking
216
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
217
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
218
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
219
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
220
            count = _fcntl_ReadLock._open_locks[self.filename]
221
            if count == 1:
222
                del _fcntl_ReadLock._open_locks[self.filename]
223
            else:
224
                _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.
225
            self._unlock()
226
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
227
        def temporary_write_lock(self):
228
            """Try to grab a write lock on the file.
229
230
            On platforms that support it, this will upgrade to a write lock
231
            without unlocking the file.
232
            Otherwise, this will release the read lock, and try to acquire a
233
            write lock.
234
235
            :return: A token which can be used to switch back to a read lock.
236
            """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
237
            if self.filename in _fcntl_WriteLock._open_locks:
238
                raise AssertionError('file already locked: %r'
239
                    % (self.filename,))
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
240
            try:
241
                wlock = _fcntl_TemporaryWriteLock(self)
242
            except errors.LockError:
243
                # We didn't unlock, so we can just return 'self'
244
                return False, self
245
            return True, wlock
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
246
247
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
248
    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.
249
        """A token used when grabbing a temporary_write_lock.
250
251
        Call restore_read_lock() when you are done with the write lock.
252
        """
253
254
        def __init__(self, read_lock):
255
            super(_fcntl_TemporaryWriteLock, self).__init__()
256
            self._read_lock = read_lock
257
            self.filename = read_lock.filename
258
259
            count = _fcntl_ReadLock._open_locks[self.filename]
260
            if count > 1:
261
                # Something else also has a read-lock, so we cannot grab a
262
                # write lock.
263
                raise errors.LockContention(self.filename)
264
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
265
            if self.filename in _fcntl_WriteLock._open_locks:
266
                raise AssertionError('file already locked: %r'
267
                    % (self.filename,))
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
268
269
            # See if we can open the file for writing. Another process might
270
            # have a read lock. We don't use self._open() because we don't want
271
            # to create the file if it exists. That would have already been
272
            # done by _fcntl_ReadLock
273
            try:
274
                new_f = open(self.filename, 'rb+')
275
            except IOError, e:
276
                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).
277
                    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.
278
                raise
279
            try:
280
                # LOCK_NB will cause IOError to be raised if we can't grab a
281
                # lock right away.
2379.3.1 by John Arbash Meinel
Cherry-pick the 2 locking fixes from the 0.15 branch.
282
                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.
283
            except IOError, e:
284
                # 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
285
                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.
286
            _fcntl_WriteLock._open_locks.add(self.filename)
287
288
            self.f = new_f
289
290
        def restore_read_lock(self):
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
291
            """Restore the original ReadLock."""
292
            # For fcntl, since we never released the read lock, just release the
293
            # 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.
294
            fcntl.lockf(self.f, fcntl.LOCK_UN)
295
            self._clear_f()
296
            _fcntl_WriteLock._open_locks.remove(self.filename)
297
            # Avoid reference cycles
298
            read_lock = self._read_lock
299
            self._read_lock = None
300
            return read_lock
301
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
302
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
303
    _lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))
577 by Martin Pool
- merge portable lock module from John
304
2353.3.11 by John Arbash Meinel
Code cleanup
305
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
306
if have_pywin32 and sys.platform == 'win32':
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
307
    LOCK_SH = 0 # the default
308
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
309
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
310
311
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
312
    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.
313
314
        def _lock(self, filename, openmode, lockmode):
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
315
            self._open(filename, openmode)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
316
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
317
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
318
            overlapped = pywintypes.OVERLAPPED()
319
            try:
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
320
                win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
321
                                     overlapped)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
322
            except pywintypes.error, e:
323
                self._clear_f()
324
                if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
325
                    raise errors.LockContention(filename)
326
                ## import pdb; pdb.set_trace()
327
                raise
328
            except Exception, e:
329
                self._clear_f()
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
330
                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.
331
332
        def unlock(self):
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
333
            overlapped = pywintypes.OVERLAPPED()
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
334
            try:
335
                win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
336
                self._clear_f()
337
            except Exception, e:
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
338
                raise errors.LockContention(self.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.
339
340
341
    class _w32c_ReadLock(_w32c_FileLock):
342
        def __init__(self, filename):
343
            super(_w32c_ReadLock, self).__init__()
344
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
345
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
346
        def temporary_write_lock(self):
347
            """Try to grab a write lock on the file.
348
349
            On platforms that support it, this will upgrade to a write lock
350
            without unlocking the file.
351
            Otherwise, this will release the read lock, and try to acquire a
352
            write lock.
353
354
            :return: A token which can be used to switch back to a read lock.
355
            """
356
            # I can't find a way to upgrade a read lock to a write lock without
357
            # unlocking first. So here, we do just that.
358
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
359
            try:
360
                wlock = _w32c_WriteLock(self.filename)
361
            except errors.LockError:
362
                return False, _w32c_ReadLock(self.filename)
363
            return True, wlock
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
364
2353.3.11 by John Arbash Meinel
Code cleanup
365
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
366
    class _w32c_WriteLock(_w32c_FileLock):
367
        def __init__(self, filename):
368
            super(_w32c_WriteLock, self).__init__()
369
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
370
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
371
        def restore_read_lock(self):
372
            """Restore the original ReadLock."""
373
            # For win32 we had to completely let go of the original lock, so we
374
            # just unlock and create a new read lock.
375
            self.unlock()
376
            return _w32c_ReadLock(self.filename)
377
2353.3.11 by John Arbash Meinel
Code cleanup
378
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
379
    _lock_classes.append(('pywin32', _w32c_WriteLock, _w32c_ReadLock))
380
2353.3.11 by John Arbash Meinel
Code cleanup
381
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.
382
if have_ctypes_win32:
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
383
    # These constants were copied from the win32con.py module.
384
    LOCKFILE_FAIL_IMMEDIATELY = 1
385
    LOCKFILE_EXCLUSIVE_LOCK = 2
386
    # Constant taken from winerror.py module
387
    ERROR_LOCK_VIOLATION = 33
388
389
    LOCK_SH = 0
390
    LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
391
    LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
392
    _LockFileEx = ctypes.windll.kernel32.LockFileEx
393
    _UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
394
395
    ### Define the OVERLAPPED structure.
396
    #   http://msdn2.microsoft.com/en-us/library/ms684342.aspx
397
    # typedef struct _OVERLAPPED {
398
    #   ULONG_PTR Internal;
399
    #   ULONG_PTR InternalHigh;
400
    #   union {
401
    #     struct {
402
    #       DWORD Offset;
403
    #       DWORD OffsetHigh;
404
    #     };
405
    #     PVOID Pointer;
406
    #   };
407
    #   HANDLE hEvent;
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
408
    # } OVERLAPPED,
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
409
410
    class _inner_struct(ctypes.Structure):
411
        _fields_ = [('Offset', ctypes.c_uint), # DWORD
412
                    ('OffsetHigh', ctypes.c_uint), # DWORD
413
                   ]
414
415
    class _inner_union(ctypes.Union):
416
        _fields_  = [('anon_struct', _inner_struct), # struct
417
                     ('Pointer', ctypes.c_void_p), # PVOID
418
                    ]
419
420
    class OVERLAPPED(ctypes.Structure):
421
        _fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
422
                    ('InternalHigh', ctypes.c_void_p), # ULONG_PTR
423
                    ('_inner_union', _inner_union),
424
                    ('hEvent', ctypes.c_void_p), # HANDLE
425
                   ]
426
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
427
    class _ctypes_FileLock(_OSLock):
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
428
429
        def _lock(self, filename, openmode, lockmode):
430
            self._open(filename, openmode)
431
432
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
433
            overlapped = OVERLAPPED()
434
            result = _LockFileEx(self.hfile, # HANDLE hFile
435
                                 lockmode,   # DWORD dwFlags
436
                                 0,          # DWORD dwReserved
437
                                 0x7fffffff, # DWORD nNumberOfBytesToLockLow
438
                                 0x00000000, # DWORD nNumberOfBytesToLockHigh
2353.4.9 by John Arbash Meinel
[merge] bzr.dev 2359
439
                                 ctypes.byref(overlapped), # lpOverlapped
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
440
                                )
441
            if result == 0:
4404.1.1 by Martin
Correct use of GetLastError in ctypes windows locking code
442
                last_err = ctypes.GetLastError()
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
443
                self._clear_f()
444
                if last_err in (ERROR_LOCK_VIOLATION,):
445
                    raise errors.LockContention(filename)
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
446
                raise errors.LockContention(filename,
447
                    'Unknown locking error: %s' % (last_err,))
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
448
449
        def unlock(self):
450
            overlapped = OVERLAPPED()
451
            result = _UnlockFileEx(self.hfile, # HANDLE hFile
452
                                   0,          # DWORD dwReserved
453
                                   0x7fffffff, # DWORD nNumberOfBytesToLockLow
454
                                   0x00000000, # DWORD nNumberOfBytesToLockHigh
2353.4.9 by John Arbash Meinel
[merge] bzr.dev 2359
455
                                   ctypes.byref(overlapped), # lpOverlapped
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
456
                                  )
457
            if result == 0:
4404.1.1 by Martin
Correct use of GetLastError in ctypes windows locking code
458
                last_err = ctypes.GetLastError()
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
459
                self._clear_f()
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
460
                raise errors.LockContention(self.filename,
461
                    'Unknown unlocking error: %s' % (last_err,))
4404.1.1 by Martin
Correct use of GetLastError in ctypes windows locking code
462
            self._clear_f()
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
463
464
465
    class _ctypes_ReadLock(_ctypes_FileLock):
466
        def __init__(self, filename):
467
            super(_ctypes_ReadLock, self).__init__()
468
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
469
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
470
        def temporary_write_lock(self):
471
            """Try to grab a write lock on the file.
472
473
            On platforms that support it, this will upgrade to a write lock
474
            without unlocking the file.
475
            Otherwise, this will release the read lock, and try to acquire a
476
            write lock.
477
478
            :return: A token which can be used to switch back to a read lock.
479
            """
480
            # I can't find a way to upgrade a read lock to a write lock without
481
            # unlocking first. So here, we do just that.
482
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
483
            try:
484
                wlock = _ctypes_WriteLock(self.filename)
485
            except errors.LockError:
486
                return False, _ctypes_ReadLock(self.filename)
487
            return True, wlock
2353.3.11 by John Arbash Meinel
Code cleanup
488
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
489
    class _ctypes_WriteLock(_ctypes_FileLock):
490
        def __init__(self, filename):
491
            super(_ctypes_WriteLock, self).__init__()
492
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
493
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
494
        def restore_read_lock(self):
495
            """Restore the original ReadLock."""
496
            # For win32 we had to completely let go of the original lock, so we
497
            # just unlock and create a new read lock.
498
            self.unlock()
2353.4.6 by John Arbash Meinel
ctypes locks should return ctypes locks.
499
            return _ctypes_ReadLock(self.filename)
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
500
2353.3.11 by John Arbash Meinel
Code cleanup
501
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
502
    _lock_classes.append(('ctypes', _ctypes_WriteLock, _ctypes_ReadLock))
503
504
505
if len(_lock_classes) == 0:
2353.3.11 by John Arbash Meinel
Code cleanup
506
    raise NotImplementedError(
507
        "We must have one of fcntl, pywin32, or ctypes available"
508
        " to support OS locking."
509
        )
510
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
511
512
# We default to using the first available lock class.
513
_lock_type, WriteLock, ReadLock = _lock_classes[0]
514