~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-03-26 07:30:03 UTC
  • mfrom: (2375.1.7 remove-branch-transaction)
  • Revision ID: pqm@pqm.ubuntu.com-20070326073003-37941d0fa5a5a6c4
(Andrew Bennetts) Replace Branch.get_transaction and associated infrastructure with simpler caching of revision history.

Show diffs side-by-side

added added

removed removed

Lines of Context:
98
98
 
99
99
    def __init__(self, *ignored, **ignored_too):
100
100
        self.tags = self._make_tags()
 
101
        self._revision_history_cache = None
101
102
 
102
103
    def break_lock(self):
103
104
        """Break a lock if one is present from another instance.
310
311
    def set_revision_history(self, rev_history):
311
312
        raise NotImplementedError(self.set_revision_history)
312
313
 
 
314
    def _cache_revision_history(self, rev_history):
 
315
        """Set the cached revision history to rev_history.
 
316
 
 
317
        The revision_history method will use this cache to avoid regenerating
 
318
        the revision history.
 
319
 
 
320
        This API is semi-public; it only for use by subclasses, all other code
 
321
        should consider it to be private.
 
322
        """
 
323
        self._revision_history_cache = rev_history
 
324
 
 
325
    def _clear_cached_state(self):
 
326
        """Clear any cached data on this branch, e.g. cached revision history.
 
327
 
 
328
        This means the next call to revision_history will need to call
 
329
        _gen_revision_history.
 
330
 
 
331
        This API is semi-public; it only for use by subclasses, all other code
 
332
        should consider it to be private.
 
333
        """
 
334
        self._revision_history_cache = None
 
335
 
 
336
    def _gen_revision_history(self):
 
337
        """Return sequence of revision hashes on to this branch.
 
338
        
 
339
        Unlike revision_history, this method always regenerates or rereads the
 
340
        revision history, i.e. it does not cache the result, so repeated calls
 
341
        may be expensive.
 
342
 
 
343
        Concrete subclasses should override this instead of revision_history so
 
344
        that subclasses do not need to deal with caching logic.
 
345
        
 
346
        This API is semi-public; it only for use by subclasses, all other code
 
347
        should consider it to be private.
 
348
        """
 
349
        raise NotImplementedError(self._gen_revision_history)
 
350
 
 
351
    @needs_read_lock
313
352
    def revision_history(self):
314
 
        """Return sequence of revision hashes on to this branch."""
315
 
        raise NotImplementedError(self.revision_history)
 
353
        """Return sequence of revision hashes on to this branch.
 
354
        
 
355
        This method will cache the revision history for as long as it is safe to
 
356
        do so.
 
357
        """
 
358
        if self._revision_history_cache is not None:
 
359
            history = self._revision_history_cache
 
360
        else:
 
361
            history = self._gen_revision_history()
 
362
            self._cache_revision_history(history)
 
363
        return list(history)
316
364
 
317
365
    def revno(self):
318
366
        """Return current revision number for this branch.
1252
1300
 
1253
1301
    base = property(_get_base, doc="The URL for the root of this branch.")
1254
1302
 
1255
 
    def _finish_transaction(self):
1256
 
        """Exit the current transaction."""
1257
 
        return self.control_files._finish_transaction()
1258
 
 
1259
 
    def get_transaction(self):
1260
 
        """Return the current active transaction.
1261
 
 
1262
 
        If no transaction is active, this returns a passthrough object
1263
 
        for which all data is immediately flushed and no caching happens.
1264
 
        """
1265
 
        # this is an explicit function so that we can do tricky stuff
1266
 
        # when the storage in rev_storage is elsewhere.
1267
 
        # we probably need to hook the two 'lock a location' and 
1268
 
        # 'have a transaction' together more delicately, so that
1269
 
        # we can have two locks (branch and storage) and one transaction
1270
 
        # ... and finishing the transaction unlocks both, but unlocking
1271
 
        # does not. - RBC 20051121
1272
 
        return self.control_files.get_transaction()
1273
 
 
1274
 
    def _set_transaction(self, transaction):
1275
 
        """Set a new active transaction."""
1276
 
        return self.control_files._set_transaction(transaction)
1277
 
 
1278
1303
    def abspath(self, name):
1279
1304
        """See Branch.abspath."""
1280
1305
        return self.control_files._transport.abspath(name)
1326
1351
            self.control_files.unlock()
1327
1352
        finally:
1328
1353
            self.repository.unlock()
 
1354
        if not self.control_files.is_locked():
 
1355
            # we just released the lock
 
1356
            self._clear_cached_state()
1329
1357
        
1330
1358
    def peek_lock_mode(self):
1331
1359
        if self.control_files._lock_count == 0:
1365
1393
        """See Branch.set_revision_history."""
1366
1394
        rev_history = [osutils.safe_revision_id(r) for r in rev_history]
1367
1395
        self._write_revision_history(rev_history)
1368
 
        transaction = self.get_transaction()
1369
 
        history = transaction.map.find_revision_history()
1370
 
        if history is not None:
1371
 
            # update the revision history in the identity map.
1372
 
            history[:] = list(rev_history)
1373
 
            # this call is disabled because revision_history is 
1374
 
            # not really an object yet, and the transaction is for objects.
1375
 
            # transaction.register_dirty(history)
1376
 
        else:
1377
 
            transaction.map.add_revision_history(rev_history)
1378
 
            # this call is disabled because revision_history is 
1379
 
            # not really an object yet, and the transaction is for objects.
1380
 
            # transaction.register_clean(history)
 
1396
        self._cache_revision_history(rev_history)
1381
1397
        for hook in Branch.hooks['set_rh']:
1382
1398
            hook(self, rev_history)
1383
1399
 
1395
1411
            history.pop()
1396
1412
        return history
1397
1413
 
1398
 
    @needs_read_lock
1399
 
    def revision_history(self):
1400
 
        """See Branch.revision_history."""
1401
 
        transaction = self.get_transaction()
1402
 
        history = transaction.map.find_revision_history()
1403
 
        if history is not None:
1404
 
            # mutter("cache hit for revision-history in %s", self)
1405
 
            return list(history)
1406
 
        history = self._gen_revision_history()
1407
 
        transaction.map.add_revision_history(history)
1408
 
        # this call is disabled because revision_history is 
1409
 
        # not really an object yet, and the transaction is for objects.
1410
 
        # transaction.register_clean(history, precious=True)
1411
 
        return list(history)
1412
 
 
1413
1414
    def _lefthand_history(self, revision_id, last_rev=None,
1414
1415
                          other_branch=None):
1415
1416
        # stop_revision must be a descendant of last_revision
1928
1929
        if self._get_append_revisions_only():
1929
1930
            self._check_history_violation(revision_id)
1930
1931
        self._write_last_revision_info(revno, revision_id)
1931
 
        transaction = self.get_transaction()
1932
 
        cached_history = transaction.map.find_revision_history()
1933
 
        if cached_history is not None:
1934
 
            transaction.map.remove_object(cached_history)
 
1932
        self._clear_cached_state()
1935
1933
 
1936
1934
    def _check_history_violation(self, revision_id):
1937
1935
        last_revision = self.last_revision()