/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/lockdir.py

  • Committer: Andrew Bennetts
  • Date: 2006-10-20 04:02:48 UTC
  • mfrom: (2091 +trunk)
  • mto: (2018.5.1 split-smart)
  • mto: This revision was merged to the branch mainline in revision 2435.
  • Revision ID: andrew.bennetts@canonical.com-20061020040248-80ca63c7e0a13298
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
96
96
 
97
97
import os
98
98
import time
99
 
from StringIO import StringIO
 
99
from cStringIO import StringIO
100
100
 
 
101
from bzrlib import (
 
102
    errors,
 
103
    )
101
104
import bzrlib.config
102
105
from bzrlib.errors import (
103
106
        DirectoryNotEmpty,
111
114
        ResourceBusy,
112
115
        UnlockableTransport,
113
116
        )
114
 
from bzrlib.trace import mutter
 
117
from bzrlib.trace import mutter, note
115
118
from bzrlib.transport import Transport
116
 
from bzrlib.osutils import rand_chars
 
119
from bzrlib.osutils import rand_chars, format_delta
117
120
from bzrlib.rio import read_stanza, Stanza
118
121
 
 
122
 
119
123
# XXX: At the moment there is no consideration of thread safety on LockDir
120
124
# objects.  This should perhaps be updated - e.g. if two threads try to take a
121
125
# lock at the same time they should *both* get it.  But then that's unlikely
130
134
# TODO: Make sure to pass the right file and directory mode bits to all
131
135
# files/dirs created.
132
136
 
 
137
 
133
138
_DEFAULT_TIMEOUT_SECONDS = 300
134
 
_DEFAULT_POLL_SECONDS = 0.5
 
139
_DEFAULT_POLL_SECONDS = 1.0
 
140
 
135
141
 
136
142
class LockDir(object):
137
143
    """Write-lock guarding access to data."""
160
166
        self._dir_modebits = dir_modebits
161
167
        self.nonce = rand_chars(20)
162
168
 
 
169
        self._report_function = note
 
170
 
163
171
    def __repr__(self):
164
172
        return '%s(%s%s)' % (self.__class__.__name__,
165
173
                             self.transport.base,
243
251
        self._check_not_locked()
244
252
        holder_info = self.peek()
245
253
        if holder_info is not None:
246
 
            if bzrlib.ui.ui_factory.get_boolean(
247
 
                "Break lock %s held by %s@%s [process #%s]" % (
248
 
                    self.transport,
249
 
                    holder_info["user"],
250
 
                    holder_info["hostname"],
251
 
                    holder_info["pid"])):
 
254
            lock_info = '\n'.join(self._format_lock_info(holder_info))
 
255
            if bzrlib.ui.ui_factory.get_boolean("Break %s" % lock_info):
252
256
                self.force_break(holder_info)
253
257
        
254
258
    def force_break(self, dead_holder_info):
341
345
        import socket
342
346
        # XXX: is creating this here inefficient?
343
347
        config = bzrlib.config.GlobalConfig()
 
348
        try:
 
349
            user = config.user_email()
 
350
        except errors.NoEmailInUsername:
 
351
            user = config.username()
344
352
        s = Stanza(hostname=socket.gethostname(),
345
353
                   pid=str(os.getpid()),
346
354
                   start_time=str(int(time.time())),
347
355
                   nonce=self.nonce,
348
 
                   user=config.user_email(),
 
356
                   user=user,
349
357
                   )
350
358
        return s.to_string()
351
359
 
352
360
    def _parse_info(self, info_file):
353
361
        return read_stanza(info_file.readlines()).as_dict()
354
362
 
355
 
    def wait_lock(self, timeout=_DEFAULT_TIMEOUT_SECONDS,
356
 
                  poll=_DEFAULT_POLL_SECONDS):
 
363
    def wait_lock(self, timeout=None, poll=None):
357
364
        """Wait a certain period for a lock.
358
365
 
359
366
        If the lock can be acquired within the bounded time, it
362
369
        approximately `timeout` seconds.  (It may be a bit more if
363
370
        a transport operation takes a long time to complete.)
364
371
        """
 
372
        if timeout is None:
 
373
            timeout = _DEFAULT_TIMEOUT_SECONDS
 
374
        if poll is None:
 
375
            poll = _DEFAULT_POLL_SECONDS
 
376
 
365
377
        # XXX: the transport interface doesn't let us guard 
366
378
        # against operations there taking a long time.
367
379
        deadline = time.time() + timeout
 
380
        deadline_str = None
 
381
        last_info = None
368
382
        while True:
369
383
            try:
370
384
                self.attempt_lock()
371
385
                return
372
386
            except LockContention:
373
387
                pass
 
388
            new_info = self.peek()
 
389
            mutter('last_info: %s, new info: %s', last_info, new_info)
 
390
            if new_info is not None and new_info != last_info:
 
391
                if last_info is None:
 
392
                    start = 'Unable to obtain'
 
393
                else:
 
394
                    start = 'Lock owner changed for'
 
395
                last_info = new_info
 
396
                formatted_info = self._format_lock_info(new_info)
 
397
                if deadline_str is None:
 
398
                    deadline_str = time.strftime('%H:%M:%S',
 
399
                                                 time.localtime(deadline))
 
400
                self._report_function('%s %s\n'
 
401
                                      '%s\n' # held by
 
402
                                      '%s\n' # locked ... ago
 
403
                                      'Will continue to try until %s\n',
 
404
                                      start,
 
405
                                      formatted_info[0],
 
406
                                      formatted_info[1],
 
407
                                      formatted_info[2],
 
408
                                      deadline_str)
 
409
 
374
410
            if time.time() + poll < deadline:
375
411
                time.sleep(poll)
376
412
            else:
378
414
 
379
415
    def lock_write(self):
380
416
        """Wait for and acquire the lock."""
381
 
        self.attempt_lock()
 
417
        self.wait_lock()
382
418
 
383
419
    def lock_read(self):
384
420
        """Compatibility-mode shared lock.
408
444
            else:
409
445
                raise LockContention(self)
410
446
 
 
447
    def _format_lock_info(self, info):
 
448
        """Turn the contents of peek() into something for the user"""
 
449
        lock_url = self.transport.abspath(self.path)
 
450
        delta = time.time() - int(info['start_time'])
 
451
        return [
 
452
            'lock %s' % (lock_url,),
 
453
            'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
 
454
            'locked %s' % (format_delta(delta),),
 
455
            ]
 
456