/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/lock.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
 
17
18
"""Locking using OS file locks or file existence.
18
19
 
19
20
Note: This method of locking is generally deprecated in favour of LockDir, but
33
34
unlock() method.
34
35
"""
35
36
 
36
 
from __future__ import absolute_import
37
 
 
38
 
import contextlib
39
37
import errno
40
38
import os
41
39
import sys
42
40
import warnings
43
41
 
44
 
from . import (
 
42
from bzrlib import (
45
43
    debug,
46
44
    errors,
47
45
    osutils,
48
46
    trace,
49
47
    )
50
 
from .hooks import Hooks
51
 
from .i18n import gettext
 
48
from bzrlib.hooks import HookPoint, Hooks
 
49
 
52
50
 
53
51
class LockHooks(Hooks):
54
52
 
55
53
    def __init__(self):
56
 
        Hooks.__init__(self, "breezy.lock", "Lock.hooks")
57
 
        self.add_hook('lock_acquired',
58
 
            "Called with a breezy.lock.LockResult when a physical lock is "
59
 
            "acquired.", (1, 8))
60
 
        self.add_hook('lock_released',
61
 
            "Called with a breezy.lock.LockResult when a physical lock is "
62
 
            "released.", (1, 8))
63
 
        self.add_hook('lock_broken',
64
 
            "Called with a breezy.lock.LockResult when a physical lock is "
65
 
            "broken.", (1, 15))
 
54
        Hooks.__init__(self)
 
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))
 
61
        self.create_hook(HookPoint('lock_broken',
 
62
            "Called with a bzrlib.lock.LockResult when a physical lock is "
 
63
            "broken.", (1, 15), None))
66
64
 
67
65
 
68
66
class Lock(object):
90
88
                             self.lock_url, self.details)
91
89
 
92
90
 
93
 
class LogicalLockResult(object):
94
 
    """The result of a lock_read/lock_write/lock_tree_write call on lockables.
95
 
 
96
 
    :ivar unlock: A callable which will unlock the lock.
97
 
    """
98
 
 
99
 
    def __init__(self, unlock, token=None):
100
 
        self.unlock = unlock
101
 
        self.token = token
102
 
 
103
 
    def __repr__(self):
104
 
        return "LogicalLockResult(%s)" % (self.unlock)
105
 
 
106
 
    def __enter__(self):
107
 
        return self
108
 
 
109
 
    def __exit__(self, exc_type, exc_val, exc_tb):
110
 
        # If there was an error raised, prefer the original one
111
 
        try:
112
 
            self.unlock()
113
 
        except:
114
 
            if exc_type is None:
115
 
                raise
116
 
        return False
117
 
 
118
 
 
119
91
def cant_unlock_not_held(locked_object):
120
92
    """An attempt to unlock failed because the object was not locked.
121
93
 
167
139
        try:
168
140
            self.f = open(self.filename, filemode)
169
141
            return self.f
170
 
        except IOError as e:
 
142
        except IOError, e:
171
143
            if e.errno in (errno.EACCES, errno.EPERM):
172
144
                raise errors.LockFailed(self.filename, str(e))
173
145
            if e.errno != errno.ENOENT:
185
157
            self.f.close()
186
158
            self.f = None
187
159
 
 
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()
 
165
 
188
166
    def unlock(self):
189
167
        raise NotImplementedError()
190
168
 
229
207
                # LOCK_NB will cause IOError to be raised if we can't grab a
230
208
                # lock right away.
231
209
                fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
232
 
            except IOError as e:
 
210
            except IOError, e:
233
211
                if e.errno in (errno.EAGAIN, errno.EACCES):
234
212
                    # We couldn't grab the lock
235
213
                    self.unlock()
264
242
                # LOCK_NB will cause IOError to be raised if we can't grab a
265
243
                # lock right away.
266
244
                fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
267
 
            except IOError as e:
 
245
            except IOError, e:
268
246
                # we should be more precise about whats a locking
269
247
                # error and whats a random-other error
270
248
                raise errors.LockContention(self.filename, e)
325
303
            # done by _fcntl_ReadLock
326
304
            try:
327
305
                new_f = open(self.filename, 'rb+')
328
 
            except IOError as e:
 
306
            except IOError, e:
329
307
                if e.errno in (errno.EACCES, errno.EPERM):
330
308
                    raise errors.LockFailed(self.filename, str(e))
331
309
                raise
333
311
                # LOCK_NB will cause IOError to be raised if we can't grab a
334
312
                # lock right away.
335
313
                fcntl.lockf(new_f, fcntl.LOCK_EX | fcntl.LOCK_NB)
336
 
            except IOError as e:
 
314
            except IOError, e:
337
315
                # TODO: Raise a more specific error based on the type of error
338
316
                raise errors.LockContention(self.filename, e)
339
317
            _fcntl_WriteLock._open_locks.add(self.filename)
357
335
 
358
336
 
359
337
if have_pywin32 and sys.platform == 'win32':
360
 
    win32file_CreateFile = win32file.CreateFileW
 
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
361
344
 
362
345
    class _w32c_FileLock(_OSLock):
363
346
 
367
350
                self._handle = win32file_CreateFile(filename, access, share,
368
351
                    None, win32file.OPEN_ALWAYS,
369
352
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
370
 
            except pywintypes.error as e:
 
353
            except pywintypes.error, e:
371
354
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
372
355
                    raise errors.LockFailed(filename, e)
373
356
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
430
413
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
431
414
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
432
415
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
433
 
    _function_name = "CreateFileW"
 
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"))
434
424
 
435
425
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
436
426
    _CreateFile = ctypes.WINFUNCTYPE(
437
427
            HANDLE,                # return value
438
 
            LPWSTR,                # lpFileName
 
428
            LPTSTR,                # lpFileName
439
429
            DWORD,                 # dwDesiredAccess
440
430
            DWORD,                 # dwShareMode
441
431
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
537
527
    locked the same way), and -Drelock is set, then this will trace.note a
538
528
    message about it.
539
529
    """
540
 
 
 
530
    
541
531
    _prev_lock = None
542
532
 
543
533
    def _note_lock(self, lock_type):
546
536
                type_name = 'read'
547
537
            else:
548
538
                type_name = 'write'
549
 
            trace.note(gettext('{0!r} was {1} locked again'), self, type_name)
 
539
            trace.note('%r was %s locked again', self, type_name)
550
540
        self._prev_lock = lock_type
551
541
 
552
 
@contextlib.contextmanager
553
 
def write_locked(lockable):
554
 
    lockable.lock_write()
555
 
    try:
556
 
        yield lockable
557
 
    finally:
558
 
        lockable.unlock()