~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lock.py

  • Committer: Vincent Ladeuil
  • Date: 2009-05-05 15:31:34 UTC
  • mto: (4343.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4344.
  • Revision ID: v.ladeuil+lp@free.fr-20090505153134-q4bp4is9gywsmzrv
Clean up test for log formats.

* bzrlib/tests/blackbox/test_logformats.py:
Update tests to actual style.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
"""
36
36
 
37
37
import errno
38
 
import os
39
38
import sys
40
 
import warnings
41
39
 
42
40
from bzrlib import (
43
 
    debug,
44
41
    errors,
45
42
    osutils,
46
43
    trace,
58
55
        self.create_hook(HookPoint('lock_released',
59
56
            "Called with a bzrlib.lock.LockResult when a physical lock is "
60
57
            "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))
64
58
 
65
59
 
66
60
class Lock(object):
83
77
    def __eq__(self, other):
84
78
        return self.lock_url == other.lock_url and self.details == other.details
85
79
 
86
 
    def __repr__(self):
87
 
        return '%s(%s%s)' % (self.__class__.__name__,
88
 
                             self.lock_url, self.details)
89
 
 
90
 
 
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
98
 
    # block, so it's useful to have the option not to generate a new error
99
 
    # here.  You can use -Werror to make it fatal.  It should possibly also
100
 
    # raise LockNotHeld.
101
 
    if 'unlock' in debug.debug_flags:
102
 
        warnings.warn("%r is already unlocked" % (locked_object,),
103
 
            stacklevel=3)
104
 
    else:
105
 
        raise errors.LockNotHeld(locked_object)
106
 
 
107
80
 
108
81
try:
109
82
    import fcntl
116
89
if sys.platform == 'win32':
117
90
    import msvcrt
118
91
    try:
119
 
        import win32file, pywintypes, winerror
 
92
        import win32con, win32file, pywintypes, winerror
120
93
        have_pywin32 = True
121
94
    except ImportError:
122
95
        pass
171
144
 
172
145
 
173
146
if have_fcntl:
 
147
    LOCK_SH = fcntl.LOCK_SH
 
148
    LOCK_NB = fcntl.LOCK_NB
 
149
    lock_EX = fcntl.LOCK_EX
 
150
 
174
151
 
175
152
    class _fcntl_FileLock(_OSLock):
176
153
 
320
297
 
321
298
 
322
299
if have_pywin32 and sys.platform == 'win32':
323
 
    if os.path.supports_unicode_filenames:
324
 
        # for Windows NT/2K/XP/etc
325
 
        win32file_CreateFile = win32file.CreateFileW
326
 
    else:
327
 
        # for Windows 98
328
 
        win32file_CreateFile = win32file.CreateFile
 
300
    LOCK_SH = 0 # the default
 
301
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
 
302
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
 
303
 
329
304
 
330
305
    class _w32c_FileLock(_OSLock):
331
306
 
332
 
        def _open(self, filename, access, share, cflags, pymode):
333
 
            self.filename = osutils.realpath(filename)
 
307
        def _lock(self, filename, openmode, lockmode):
 
308
            self._open(filename, openmode)
 
309
 
 
310
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
 
311
            overlapped = pywintypes.OVERLAPPED()
334
312
            try:
335
 
                self._handle = win32file_CreateFile(filename, access, share,
336
 
                    None, win32file.OPEN_ALWAYS,
337
 
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
 
313
                win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
 
314
                                     overlapped)
338
315
            except pywintypes.error, e:
339
 
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
340
 
                    raise errors.LockFailed(filename, e)
341
 
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
342
 
                    raise errors.LockContention(filename, e)
 
316
                self._clear_f()
 
317
                if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
 
318
                    raise errors.LockContention(filename)
 
319
                ## import pdb; pdb.set_trace()
343
320
                raise
344
 
            fd = win32file._open_osfhandle(self._handle, cflags)
345
 
            self.f = os.fdopen(fd, pymode)
346
 
            return self.f
 
321
            except Exception, e:
 
322
                self._clear_f()
 
323
                raise errors.LockContention(filename, e)
347
324
 
348
325
        def unlock(self):
349
 
            self._clear_f()
350
 
            self._handle = None
 
326
            overlapped = pywintypes.OVERLAPPED()
 
327
            try:
 
328
                win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
 
329
                self._clear_f()
 
330
            except Exception, e:
 
331
                raise errors.LockContention(self.filename, e)
351
332
 
352
333
 
353
334
    class _w32c_ReadLock(_w32c_FileLock):
354
335
        def __init__(self, filename):
355
336
            super(_w32c_ReadLock, self).__init__()
356
 
            self._open(filename, win32file.GENERIC_READ,
357
 
                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
 
337
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
358
338
 
359
339
        def temporary_write_lock(self):
360
340
            """Try to grab a write lock on the file.
379
359
    class _w32c_WriteLock(_w32c_FileLock):
380
360
        def __init__(self, filename):
381
361
            super(_w32c_WriteLock, self).__init__()
382
 
            self._open(filename,
383
 
                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
384
 
                os.O_RDWR, "rb+")
 
362
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
385
363
 
386
364
        def restore_read_lock(self):
387
365
            """Restore the original ReadLock."""
395
373
 
396
374
 
397
375
if have_ctypes_win32:
398
 
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
399
 
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
400
 
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
401
 
    if os.path.supports_unicode_filenames:
402
 
        _function_name = "CreateFileW"
403
 
        LPTSTR = LPCWSTR
404
 
    else:
405
 
        _function_name = "CreateFileA"
406
 
        class LPTSTR(LPCSTR):
407
 
            def __new__(cls, obj):
408
 
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
409
 
 
410
 
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
411
 
    _CreateFile = ctypes.WINFUNCTYPE(
412
 
            HANDLE,                # return value
413
 
            LPTSTR,                # lpFileName
414
 
            DWORD,                 # dwDesiredAccess
415
 
            DWORD,                 # dwShareMode
416
 
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
417
 
            DWORD,                 # dwCreationDisposition
418
 
            DWORD,                 # dwFlagsAndAttributes
419
 
            HANDLE                 # hTemplateFile
420
 
        )((_function_name, ctypes.windll.kernel32))
421
 
    
422
 
    INVALID_HANDLE_VALUE = -1
423
 
    
424
 
    GENERIC_READ = 0x80000000
425
 
    GENERIC_WRITE = 0x40000000
426
 
    FILE_SHARE_READ = 1
427
 
    OPEN_ALWAYS = 4
428
 
    FILE_ATTRIBUTE_NORMAL = 128
429
 
    
430
 
    ERROR_ACCESS_DENIED = 5
431
 
    ERROR_SHARING_VIOLATION = 32
 
376
    # These constants were copied from the win32con.py module.
 
377
    LOCKFILE_FAIL_IMMEDIATELY = 1
 
378
    LOCKFILE_EXCLUSIVE_LOCK = 2
 
379
    # Constant taken from winerror.py module
 
380
    ERROR_LOCK_VIOLATION = 33
 
381
 
 
382
    LOCK_SH = 0
 
383
    LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
 
384
    LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
 
385
    _LockFileEx = ctypes.windll.kernel32.LockFileEx
 
386
    _UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
 
387
    _GetLastError = ctypes.windll.kernel32.GetLastError
 
388
 
 
389
    ### Define the OVERLAPPED structure.
 
390
    #   http://msdn2.microsoft.com/en-us/library/ms684342.aspx
 
391
    # typedef struct _OVERLAPPED {
 
392
    #   ULONG_PTR Internal;
 
393
    #   ULONG_PTR InternalHigh;
 
394
    #   union {
 
395
    #     struct {
 
396
    #       DWORD Offset;
 
397
    #       DWORD OffsetHigh;
 
398
    #     };
 
399
    #     PVOID Pointer;
 
400
    #   };
 
401
    #   HANDLE hEvent;
 
402
    # } OVERLAPPED,
 
403
 
 
404
    class _inner_struct(ctypes.Structure):
 
405
        _fields_ = [('Offset', ctypes.c_uint), # DWORD
 
406
                    ('OffsetHigh', ctypes.c_uint), # DWORD
 
407
                   ]
 
408
 
 
409
    class _inner_union(ctypes.Union):
 
410
        _fields_  = [('anon_struct', _inner_struct), # struct
 
411
                     ('Pointer', ctypes.c_void_p), # PVOID
 
412
                    ]
 
413
 
 
414
    class OVERLAPPED(ctypes.Structure):
 
415
        _fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
 
416
                    ('InternalHigh', ctypes.c_void_p), # ULONG_PTR
 
417
                    ('_inner_union', _inner_union),
 
418
                    ('hEvent', ctypes.c_void_p), # HANDLE
 
419
                   ]
432
420
 
433
421
    class _ctypes_FileLock(_OSLock):
434
422
 
435
 
        def _open(self, filename, access, share, cflags, pymode):
436
 
            self.filename = osutils.realpath(filename)
437
 
            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
438
 
                FILE_ATTRIBUTE_NORMAL, 0)
439
 
            if handle in (INVALID_HANDLE_VALUE, 0):
440
 
                e = ctypes.WinError()
441
 
                if e.args[0] == ERROR_ACCESS_DENIED:
442
 
                    raise errors.LockFailed(filename, e)
443
 
                if e.args[0] == ERROR_SHARING_VIOLATION:
444
 
                    raise errors.LockContention(filename, e)
445
 
                raise e
446
 
            fd = msvcrt.open_osfhandle(handle, cflags)
447
 
            self.f = os.fdopen(fd, pymode)
448
 
            return self.f
 
423
        def _lock(self, filename, openmode, lockmode):
 
424
            self._open(filename, openmode)
 
425
 
 
426
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
 
427
            overlapped = OVERLAPPED()
 
428
            result = _LockFileEx(self.hfile, # HANDLE hFile
 
429
                                 lockmode,   # DWORD dwFlags
 
430
                                 0,          # DWORD dwReserved
 
431
                                 0x7fffffff, # DWORD nNumberOfBytesToLockLow
 
432
                                 0x00000000, # DWORD nNumberOfBytesToLockHigh
 
433
                                 ctypes.byref(overlapped), # lpOverlapped
 
434
                                )
 
435
            if result == 0:
 
436
                self._clear_f()
 
437
                last_err = _GetLastError()
 
438
                if last_err in (ERROR_LOCK_VIOLATION,):
 
439
                    raise errors.LockContention(filename)
 
440
                raise errors.LockContention(filename,
 
441
                    'Unknown locking error: %s' % (last_err,))
449
442
 
450
443
        def unlock(self):
 
444
            overlapped = OVERLAPPED()
 
445
            result = _UnlockFileEx(self.hfile, # HANDLE hFile
 
446
                                   0,          # DWORD dwReserved
 
447
                                   0x7fffffff, # DWORD nNumberOfBytesToLockLow
 
448
                                   0x00000000, # DWORD nNumberOfBytesToLockHigh
 
449
                                   ctypes.byref(overlapped), # lpOverlapped
 
450
                                  )
451
451
            self._clear_f()
 
452
            if result == 0:
 
453
                self._clear_f()
 
454
                last_err = _GetLastError()
 
455
                raise errors.LockContention(self.filename,
 
456
                    'Unknown unlocking error: %s' % (last_err,))
452
457
 
453
458
 
454
459
    class _ctypes_ReadLock(_ctypes_FileLock):
455
460
        def __init__(self, filename):
456
461
            super(_ctypes_ReadLock, self).__init__()
457
 
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
458
 
                "rb")
 
462
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
459
463
 
460
464
        def temporary_write_lock(self):
461
465
            """Try to grab a write lock on the file.
479
483
    class _ctypes_WriteLock(_ctypes_FileLock):
480
484
        def __init__(self, filename):
481
485
            super(_ctypes_WriteLock, self).__init__()
482
 
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
483
 
                "rb+")
 
486
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
484
487
 
485
488
        def restore_read_lock(self):
486
489
            """Restore the original ReadLock."""