~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lock.py

  • Committer: John Arbash Meinel
  • Date: 2007-03-14 20:15:52 UTC
  • mto: (2353.4.2 locking)
  • mto: This revision was merged to the branch mainline in revision 2360.
  • Revision ID: john@arbash-meinel.com-20070314201552-bjtfua57456dviep
Update the lock code and test code so that if more than one
lock implementation is available, they will both be tested.

It is quite a bit of overhead, for a case where we are likely to only have 1
real lock implementation per platform, but hey, for now we have 2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
It is not specified whether these locks are reentrant (i.e. can be
28
28
taken repeatedly by a single process) or whether they exclude
29
 
different threads in a single process.  That reentrancy is provided by 
 
29
different threads in a single process.  That reentrancy is provided by
30
30
LockableFiles.
31
31
 
32
32
This defines two classes: ReadLock and WriteLock, which can be
61
61
 
62
62
            # maybe this is an old branch (before may 2005)
63
63
            mutter("trying to create missing branch lock %r", filename)
64
 
            
 
64
 
65
65
            self.f = open(filename, 'wb+')
66
66
            return self.f
67
67
 
76
76
            from warnings import warn
77
77
            warn("lock on %r not released" % self.f)
78
78
            self.unlock()
79
 
            
 
79
 
80
80
    def unlock(self):
81
81
        raise NotImplementedError()
82
82
 
86
86
    import fcntl
87
87
    have_fcntl = True
88
88
except ImportError:
89
 
    try:
90
 
        import win32con, win32file, pywintypes, winerror, msvcrt
91
 
        have_pywin32 = True
92
 
    except ImportError:
93
 
        try:
94
 
            import ctypes, msvcrt
95
 
            have_ctypes = True
96
 
        except ImportError:
97
 
            raise NotImplementedError("please write a locking method "
98
 
                                      "for platform %r" % sys.platform)
 
89
    have_fcntl = False
 
90
try:
 
91
    import win32con, win32file, pywintypes, winerror, msvcrt
 
92
    have_pywin32 = True
 
93
except ImportError:
 
94
    have_pywin32 = False
 
95
try:
 
96
    import ctypes, msvcrt
 
97
    have_ctypes = True
 
98
except ImportError:
 
99
    have_ctypes = False
 
100
 
 
101
 
 
102
_lock_classes = []
99
103
 
100
104
 
101
105
if have_fcntl:
164
168
            self._unlock()
165
169
 
166
170
 
167
 
    WriteLock = _fcntl_WriteLock
168
 
    ReadLock = _fcntl_ReadLock
 
171
    _lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))
169
172
 
170
 
elif have_pywin32:
 
173
if have_pywin32:
171
174
    LOCK_SH = 0 # the default
172
175
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
173
176
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
212
215
            super(_w32c_WriteLock, self).__init__()
213
216
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
214
217
 
215
 
    WriteLock = _w32c_WriteLock
216
 
    ReadLock = _w32c_ReadLock
217
 
else:
218
 
    assert have_ctypes, "We should have ctypes installed"
 
218
    _lock_classes.append(('pywin32', _w32c_WriteLock, _w32c_ReadLock))
 
219
 
 
220
if have_ctypes:
219
221
    # These constants were copied from the win32con.py module.
220
222
    LOCKFILE_FAIL_IMMEDIATELY = 1
221
223
    LOCKFILE_EXCLUSIVE_LOCK = 2
242
244
    #     PVOID Pointer;
243
245
    #   };
244
246
    #   HANDLE hEvent;
245
 
    # } OVERLAPPED, 
 
247
    # } OVERLAPPED,
246
248
 
247
249
    class _inner_struct(ctypes.Structure):
248
250
        _fields_ = [('Offset', ctypes.c_uint), # DWORD
311
313
            super(_ctypes_WriteLock, self).__init__()
312
314
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
313
315
 
314
 
    WriteLock = _ctypes_WriteLock
315
 
    ReadLock = _ctypes_ReadLock
316
 
 
 
316
    _lock_classes.append(('ctypes', _ctypes_WriteLock, _ctypes_ReadLock))
 
317
 
 
318
 
 
319
if len(_lock_classes) == 0:
 
320
    raise NotImplementedError("We only have support for"
 
321
                              " fcntl, pywin32 or ctypes locking."
 
322
                              " If your platform (windows) does not"
 
323
                              " support fcntl locks, you must have"
 
324
                              " either pywin32 or ctypes installed.")
 
325
 
 
326
# We default to using the first available lock class.
 
327
_lock_type, WriteLock, ReadLock = _lock_classes[0]
 
328
 
 
329
 
 
330
class LockTreeTestProviderAdapter(object):
 
331
    """A tool to generate a suite testing multiple lock formats at once.
 
332
 
 
333
    This is done by copying the test once for each lock and injecting the
 
334
    read_lock and write_lock classes.
 
335
    They are also given a new test id.
 
336
    """
 
337
 
 
338
    def __init__(self, lock_classes):
 
339
        self._lock_classes = lock_classes
 
340
 
 
341
    def _clone_test(self, test, write_lock, read_lock, variation):
 
342
        """Clone test for adaption."""
 
343
        new_test = deepcopy(test)
 
344
        new_test.write_lock = write_lock
 
345
        new_test.read_lock = read_lock
 
346
        def make_new_test_id():
 
347
            new_id = "%s(%s)" % (test.id(), variation)
 
348
            return lambda: new_id
 
349
        new_test.id = make_new_test_id()
 
350
        return new_test
 
351
 
 
352
    def adapt(self, test):
 
353
        from bzrlib.tests import TestSuite
 
354
        result = TestSuite()
 
355
        for name, write_lock, read_lock in self._lock_classes:
 
356
            new_test = self._clone_test(test, write_lock, read_lock, name)
 
357
            result.addTest(new_test)
 
358
        return result