~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Andrew Bennetts
  • Date: 2009-06-09 03:14:05 UTC
  • mfrom: (4416 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4420.
  • Revision ID: andrew.bennetts@canonical.com-20090609031405-wak9yogzzpx9o172
Merge bzr.dev, resolving NEWS conflict.

Show diffs side-by-side

added added

removed removed

Lines of Context:
969
969
        """
970
970
        if not self._format.supports_external_lookups:
971
971
            raise errors.UnstackableRepositoryFormat(self._format, self.base)
 
972
        if self.is_locked():
 
973
            # This repository will call fallback.unlock() when we transition to
 
974
            # the unlocked state, so we make sure to increment the lock count
 
975
            repository.lock_read()
972
976
        self._check_fallback_repository(repository)
973
977
        self._fallback_repositories.append(repository)
974
978
        self.texts.add_fallback_versioned_files(repository.texts)
1240
1244
        """
1241
1245
        locked = self.is_locked()
1242
1246
        result = self.control_files.lock_write(token=token)
1243
 
        for repo in self._fallback_repositories:
1244
 
            # Writes don't affect fallback repos
1245
 
            repo.lock_read()
1246
1247
        if not locked:
 
1248
            for repo in self._fallback_repositories:
 
1249
                # Writes don't affect fallback repos
 
1250
                repo.lock_read()
1247
1251
            self._refresh_data()
1248
1252
        return result
1249
1253
 
1250
1254
    def lock_read(self):
1251
1255
        locked = self.is_locked()
1252
1256
        self.control_files.lock_read()
1253
 
        for repo in self._fallback_repositories:
1254
 
            repo.lock_read()
1255
1257
        if not locked:
 
1258
            for repo in self._fallback_repositories:
 
1259
                repo.lock_read()
1256
1260
            self._refresh_data()
1257
1261
 
1258
1262
    def get_physical_lock_status(self):
1424
1428
    def suspend_write_group(self):
1425
1429
        raise errors.UnsuspendableWriteGroup(self)
1426
1430
 
1427
 
    def get_missing_parent_inventories(self):
 
1431
    def get_missing_parent_inventories(self, check_for_missing_texts=True):
1428
1432
        """Return the keys of missing inventory parents for revisions added in
1429
1433
        this write group.
1430
1434
 
1439
1443
            return set()
1440
1444
        if not self.is_in_write_group():
1441
1445
            raise AssertionError('not in a write group')
1442
 
                
 
1446
 
1443
1447
        # XXX: We assume that every added revision already has its
1444
1448
        # corresponding inventory, so we only check for parent inventories that
1445
1449
        # might be missing, rather than all inventories.
1448
1452
        unstacked_inventories = self.inventories._index
1449
1453
        present_inventories = unstacked_inventories.get_parent_map(
1450
1454
            key[-1:] for key in parents)
1451
 
        if len(parents.difference(present_inventories)) == 0:
 
1455
        parents.difference_update(present_inventories)
 
1456
        if len(parents) == 0:
1452
1457
            # No missing parent inventories.
1453
1458
            return set()
 
1459
        if not check_for_missing_texts:
 
1460
            return set(('inventories', rev_id) for (rev_id,) in parents)
1454
1461
        # Ok, now we have a list of missing inventories.  But these only matter
1455
1462
        # if the inventories that reference them are missing some texts they
1456
1463
        # appear to introduce.
1577
1584
        self.control_files.unlock()
1578
1585
        if self.control_files._lock_count == 0:
1579
1586
            self._inventory_entry_cache.clear()
1580
 
        for repo in self._fallback_repositories:
1581
 
            repo.unlock()
 
1587
            for repo in self._fallback_repositories:
 
1588
                repo.unlock()
1582
1589
 
1583
1590
    @needs_read_lock
1584
1591
    def clone(self, a_bzrdir, revision_id=None):
2238
2245
        while True:
2239
2246
            if next_id in (None, _mod_revision.NULL_REVISION):
2240
2247
                return
 
2248
            try:
 
2249
                parents = graph.get_parent_map([next_id])[next_id]
 
2250
            except KeyError:
 
2251
                raise errors.RevisionNotPresent(next_id, self)
2241
2252
            yield next_id
2242
 
            # Note: The following line may raise KeyError in the event of
2243
 
            # truncated history. We decided not to have a try:except:raise
2244
 
            # RevisionNotPresent here until we see a use for it, because of the
2245
 
            # cost in an inner loop that is by its very nature O(history).
2246
 
            # Robert Collins 20080326
2247
 
            parents = graph.get_parent_map([next_id])[next_id]
2248
2253
            if len(parents) == 0:
2249
2254
                return
2250
2255
            else:
3055
3060
    'RepositoryFormatCHK1',
3056
3061
    )
3057
3062
 
 
3063
format_registry.register_lazy(
 
3064
    'Bazaar development format - chk repository with bencode revision '
 
3065
        'serialization (needs bzr.dev from 1.15)\n',
 
3066
    'bzrlib.repofmt.groupcompress_repo',
 
3067
    'RepositoryFormatCHK2',
 
3068
    )
 
3069
 
3058
3070
 
3059
3071
class InterRepository(InterObject):
3060
3072
    """This class represents operations taking place between two repositories.
4003
4015
        try:
4004
4016
            if resume_tokens:
4005
4017
                self.target_repo.resume_write_group(resume_tokens)
 
4018
                is_resume = True
4006
4019
            else:
4007
4020
                self.target_repo.start_write_group()
 
4021
                is_resume = False
4008
4022
            try:
4009
4023
                # locked_insert_stream performs a commit|suspend.
4010
 
                return self._locked_insert_stream(stream, src_format)
 
4024
                return self._locked_insert_stream(stream, src_format, is_resume)
4011
4025
            except:
4012
4026
                self.target_repo.abort_write_group(suppress_errors=True)
4013
4027
                raise
4014
4028
        finally:
4015
4029
            self.target_repo.unlock()
4016
4030
 
4017
 
    def _locked_insert_stream(self, stream, src_format):
 
4031
    def _locked_insert_stream(self, stream, src_format, is_resume):
4018
4032
        to_serializer = self.target_repo._format._serializer
4019
4033
        src_serializer = src_format._serializer
4020
4034
        new_pack = None
4070
4084
        if new_pack is not None:
4071
4085
            new_pack._write_data('', flush=True)
4072
4086
        # Find all the new revisions (including ones from resume_tokens)
4073
 
        missing_keys = self.target_repo.get_missing_parent_inventories()
 
4087
        missing_keys = self.target_repo.get_missing_parent_inventories(
 
4088
            check_for_missing_texts=is_resume)
4074
4089
        try:
4075
4090
            for prefix, versioned_file in (
4076
4091
                ('texts', self.target_repo.texts),
4077
4092
                ('inventories', self.target_repo.inventories),
4078
4093
                ('revisions', self.target_repo.revisions),
4079
4094
                ('signatures', self.target_repo.signatures),
 
4095
                ('chk_bytes', self.target_repo.chk_bytes),
4080
4096
                ):
 
4097
                if versioned_file is None:
 
4098
                    continue
4081
4099
                missing_keys.update((prefix,) + key for key in
4082
4100
                    versioned_file.get_missing_compression_parent_keys())
4083
4101
        except NotImplementedError:
4230
4248
        keys['texts'] = set()
4231
4249
        keys['revisions'] = set()
4232
4250
        keys['inventories'] = set()
 
4251
        keys['chk_bytes'] = set()
4233
4252
        keys['signatures'] = set()
4234
4253
        for key in missing_keys:
4235
4254
            keys[key[0]].add(key[1:])
4242
4261
                    keys['revisions'],))
4243
4262
        for substream_kind, keys in keys.iteritems():
4244
4263
            vf = getattr(self.from_repository, substream_kind)
 
4264
            if vf is None and keys:
 
4265
                    raise AssertionError(
 
4266
                        "cannot fill in keys for a versioned file we don't"
 
4267
                        " have: %s needs %s" % (substream_kind, keys))
 
4268
            if not keys:
 
4269
                # No need to stream something we don't have
 
4270
                continue
4245
4271
            # Ask for full texts always so that we don't need more round trips
4246
4272
            # after this stream.
4247
 
            stream = vf.get_record_stream(keys,
4248
 
                self.to_format._fetch_order, True)
 
4273
            # Some of the missing keys are genuinely ghosts, so filter absent
 
4274
            # records. The Sink is responsible for doing another check to
 
4275
            # ensure that ghosts don't introduce missing data for future
 
4276
            # fetches.
 
4277
            stream = versionedfile.filter_absent(vf.get_record_stream(keys,
 
4278
                self.to_format._fetch_order, True))
4249
4279
            yield substream_kind, stream
4250
4280
 
4251
4281
    def inventory_fetch_order(self):