~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lock.py

(broken) Change fcntl locks to be properly exclusive within the same process.
This exposes the location where we are opening the same WorkingTree in both read and write
mode, which breaks several tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
113
113
 
114
114
    class _fcntl_WriteLock(_fcntl_FileLock):
115
115
 
116
 
        open_locks = {}
 
116
        _open_locks = set()
117
117
 
118
118
        def __init__(self, filename):
119
119
            # standard IO errors get exposed directly.
120
120
            super(_fcntl_WriteLock, self).__init__()
 
121
            self.filename = realpath(filename)
 
122
            if (self.filename in _fcntl_WriteLock._open_locks
 
123
                or self.filename in _fcntl_ReadLock._open_locks):
 
124
                self._clear_f()
 
125
                raise errors.LockContention(self.filename)
 
126
 
121
127
            self._open(filename, 'rb+')
122
 
            self.filename = realpath(filename)
123
 
            if self.filename in self.open_locks:
124
 
                self._clear_f()
125
 
                raise LockContention(self.filename)
126
128
            # reserve a slot for this lock - even if the lockf call fails,
127
129
            # at thisi point unlock() will be called, because self.f is set.
128
130
            # TODO: make this fully threadsafe, if we decide we care.
129
 
            self.open_locks[self.filename] = self.filename
 
131
            _fcntl_WriteLock._open_locks.add(self.filename)
130
132
            try:
131
133
                # LOCK_NB will cause IOError to be raised if we can't grab a
132
134
                # lock right away.
137
139
                    self.unlock()
138
140
                # we should be more precise about whats a locking
139
141
                # error and whats a random-other error
140
 
                raise LockError(e)
 
142
                raise errors.LockError(e)
141
143
 
142
144
        def unlock(self):
143
 
            del self.open_locks[self.filename]
 
145
            _fcntl_WriteLock._open_locks.remove(self.filename)
144
146
            self._unlock()
145
147
 
146
148
 
147
149
    class _fcntl_ReadLock(_fcntl_FileLock):
148
150
 
149
 
        open_locks = {}
 
151
        _open_locks = {}
150
152
 
151
153
        def __init__(self, filename):
152
154
            super(_fcntl_ReadLock, self).__init__()
 
155
            self.filename = realpath(filename)
 
156
            if self.filename in _fcntl_WriteLock._open_locks:
 
157
                raise errors.LockContention(self.filename)
 
158
            _fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
 
159
            _fcntl_ReadLock._open_locks[self.filename] += 1
153
160
            self._open(filename, 'rb')
154
161
            try:
155
162
                # LOCK_NB will cause IOError to be raised if we can't grab a
158
165
            except IOError, e:
159
166
                # we should be more precise about whats a locking
160
167
                # error and whats a random-other error
161
 
                raise LockError(e)
 
168
                raise errors.LockError(e)
162
169
 
163
170
        def unlock(self):
 
171
            count = _fcntl_ReadLock._open_locks[self.filename]
 
172
            if count == 1:
 
173
                del _fcntl_ReadLock._open_locks[self.filename]
 
174
            else:
 
175
                _fcntl_ReadLock._open_locks[self.filename] = count - 1
164
176
            self._unlock()
165
177
 
166
178