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

  • Committer: Jelmer Vernooij
  • Date: 2010-06-23 19:07:06 UTC
  • mfrom: (0.200.930 trunk)
  • mto: (0.200.951 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20100623190706-t2mqoj2o304ni80f
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
from bzrlib import (
32
32
    btree_index as _mod_btree_index,
33
33
    index as _mod_index,
 
34
    knit,
34
35
    osutils,
35
36
    registry,
36
37
    trace,
55
56
 
56
57
 
57
58
def get_remote_cache_transport():
58
 
    """Retrieve the transport to use when accessing (unwritable) remote 
59
 
    repositories.
60
 
    """
61
59
    return get_transport(get_cache_dir())
62
60
 
63
61
 
101
99
        """Lookup a Git sha in the database.
102
100
        :param sha: Git object sha
103
101
        :return: (type, type_data) with type_data:
104
 
            commit: revid, tree_sha, verifiers
105
 
            blob: fileid, revid
106
 
            tree: fileid, revid
 
102
            revision: revid, tree sha
107
103
        """
108
104
        raise NotImplementedError(self.lookup_git_sha)
109
105
 
148
144
class ContentCache(object):
149
145
    """Object that can cache Git objects."""
150
146
 
151
 
    def add(self, object):
152
 
        """Add an object."""
153
 
        raise NotImplementedError(self.add)
154
 
 
155
 
    def add_multi(self, objects):
156
 
        """Add multiple objects."""
157
 
        for obj in objects:
158
 
            self.add(obj)
159
 
 
160
147
    def __getitem__(self, sha):
161
148
        """Retrieve an item, by SHA."""
162
149
        raise NotImplementedError(self.__getitem__)
163
150
 
164
151
 
165
152
class BzrGitCacheFormat(object):
166
 
    """Bazaar-Git Cache Format."""
167
153
 
168
154
    def get_format_string(self):
169
155
        """Return a single-line unique format string for this cache format."""
174
160
        raise NotImplementedError(self.open)
175
161
 
176
162
    def initialize(self, transport):
177
 
        """Create a new instance of this cache format at transport."""
178
163
        transport.put_bytes('format', self.get_format_string())
179
164
 
180
165
    @classmethod
219
204
 
220
205
 
221
206
class CacheUpdater(object):
222
 
    """Base class for objects that can update a bzr-git cache."""
223
 
 
224
 
    def add_object(self, obj, ie, path):
225
 
        """Add an object.
226
 
 
227
 
        :param obj: Object type ("commit", "blob" or "tree")
228
 
        :param ie: Inventory entry (for blob/tree) or testament_sha in case
229
 
            of commit
230
 
        :param path: Path of the object (optional)
231
 
        """
 
207
 
 
208
    def add_object(self, obj, ie):
232
209
        raise NotImplementedError(self.add_object)
233
210
 
234
211
    def finish(self):
244
221
        self._cache_updater_klass = cache_updater_klass
245
222
 
246
223
    def get_updater(self, rev):
247
 
        """Update an object that implements the CacheUpdater interface for 
248
 
        updating this cache.
249
 
        """
250
224
        return self._cache_updater_klass(self, rev)
251
225
 
252
226
 
254
228
 
255
229
 
256
230
class DictCacheUpdater(CacheUpdater):
257
 
    """Cache updater for dict-based caches."""
258
231
 
259
232
    def __init__(self, cache, rev):
260
233
        self.cache = cache
263
236
        self._commit = None
264
237
        self._entries = []
265
238
 
266
 
    def add_object(self, obj, ie, path):
 
239
    def add_object(self, obj, ie):
267
240
        if obj.type_name == "commit":
268
241
            self._commit = obj
269
 
            assert type(ie) is dict
270
 
            type_data = (self.revid, self._commit.tree, ie)
 
242
            assert ie is None
 
243
            type_data = (self.revid, self._commit.tree)
271
244
            self.cache.idmap._by_revid[self.revid] = obj.id
272
245
        elif obj.type_name in ("blob", "tree"):
273
246
            if ie is not None:
276
249
                else:
277
250
                    revision = self.revid
278
251
                type_data = (ie.file_id, revision)
279
 
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[type_data[0]] = obj.id
 
252
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[type_data[0]] =\
 
253
                    obj.id
280
254
        else:
281
255
            raise AssertionError
282
256
        self.cache.idmap._by_sha[obj.id] = (obj.type_name, type_data)
288
262
 
289
263
 
290
264
class DictGitShaMap(GitShaMap):
291
 
    """Git SHA map that uses a dictionary."""
292
265
 
293
266
    def __init__(self):
294
267
        self._by_sha = {}
326
299
        self._trees = []
327
300
        self._blobs = []
328
301
 
329
 
    def add_object(self, obj, ie, path):
 
302
    def add_object(self, obj, ie):
330
303
        if obj.type_name == "commit":
331
304
            self._commit = obj
332
 
            self._testament3_sha1 = ie["testament3-sha1"]
333
 
            assert type(ie) is dict
 
305
            assert ie is None
334
306
        elif obj.type_name == "tree":
335
307
            if ie is not None:
336
308
                self._trees.append((obj.id, ie.file_id, self.revid))
350
322
            "replace into blobs (sha1, fileid, revid) values (?, ?, ?)",
351
323
            self._blobs)
352
324
        self.db.execute(
353
 
            "replace into commits (sha1, revid, tree_sha, testament3_sha1) values (?, ?, ?, ?)",
354
 
            (self._commit.id, self.revid, self._commit.tree, self._testament3_sha1))
 
325
            "replace into commits (sha1, revid, tree_sha) values (?, ?, ?)",
 
326
            (self._commit.id, self.revid, self._commit.tree))
355
327
        return self._commit
356
328
 
357
329
 
372
344
 
373
345
 
374
346
class SqliteGitShaMap(GitShaMap):
375
 
    """Bazaar GIT Sha map that uses a sqlite database for storage."""
376
347
 
377
348
    def __init__(self, path=None):
378
349
        self.path = path
406
377
        create unique index if not exists trees_sha1 on trees(sha1);
407
378
        create unique index if not exists trees_fileid_revid on trees(fileid, revid);
408
379
""")
409
 
        try:
410
 
            self.db.executescript(
411
 
                "ALTER TABLE commits ADD testament3_sha1 TEXT;")
412
 
        except sqlite3.OperationalError:
413
 
            pass # Column already exists.
414
380
 
415
381
    def __repr__(self):
416
382
        return "%s(%r)" % (self.__class__.__name__, self.path)
417
 
 
 
383
    
418
384
    def lookup_commit(self, revid):
419
 
        cursor = self.db.execute("select sha1 from commits where revid = ?", 
420
 
            (revid,))
421
 
        row = cursor.fetchone()
 
385
        row = self.db.execute("select sha1 from commits where revid = ?", (revid,)).fetchone()
422
386
        if row is not None:
423
387
            return row[0]
424
388
        raise KeyError
443
407
 
444
408
        :param sha: Git object sha
445
409
        :return: (type, type_data) with type_data:
446
 
            commit: revid, tree sha, verifiers
447
 
            tree: fileid, revid
448
 
            blob: fileid, revid
 
410
            revision: revid, tree sha
449
411
        """
450
 
        row = self.db.execute("select revid, tree_sha, testament3_sha1 from commits where sha1 = ?", (sha,)).fetchone()
 
412
        row = self.db.execute("select revid, tree_sha from commits where sha1 = ?", (sha,)).fetchone()
451
413
        if row is not None:
452
 
            return ("commit", (row[0], row[1], {"testament3-sha1": row[2]}))
 
414
            return ("commit", row)
453
415
        row = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,)).fetchone()
454
416
        if row is not None:
455
417
            return ("blob", row)
470
432
 
471
433
 
472
434
class TdbCacheUpdater(CacheUpdater):
473
 
    """Cache updater for tdb-based caches."""
474
435
 
475
436
    def __init__(self, cache, rev):
476
437
        self.cache = cache
480
441
        self._commit = None
481
442
        self._entries = []
482
443
 
483
 
    def add_object(self, obj, ie, path):
 
444
    def add_object(self, obj, ie):
484
445
        sha = obj.sha().digest()
485
446
        if obj.type_name == "commit":
486
447
            self.db["commit\0" + self.revid] = "\0".join((sha, obj.tree))
487
 
            assert type(ie) is dict, "was %r" % ie
488
 
            type_data = (self.revid, obj.tree, ie["testament3-sha1"])
 
448
            type_data = (self.revid, obj.tree)
489
449
            self._commit = obj
 
450
            assert ie is None
490
451
        elif obj.type_name == "blob":
491
452
            if ie is None:
492
453
                return
509
470
TdbBzrGitCache = lambda p: BzrGitCache(TdbGitShaMap(p), None, TdbCacheUpdater)
510
471
 
511
472
class TdbGitCacheFormat(BzrGitCacheFormat):
512
 
    """Cache format for tdb-based caches."""
513
473
 
514
474
    def get_format_string(self):
515
475
        return 'bzr-git sha map version 3 using tdb\n'
580
540
 
581
541
    def lookup_blob_id(self, fileid, revision):
582
542
        return sha_to_hex(self.db["\0".join(("blob", fileid, revision))])
583
 
 
 
543
                
584
544
    def lookup_git_sha(self, sha):
585
545
        """Lookup a Git sha in the database.
586
546
 
587
547
        :param sha: Git object sha
588
548
        :return: (type, type_data) with type_data:
589
 
            commit: revid, tree sha
590
 
            blob: fileid, revid
591
 
            tree: fileid, revid
 
549
            revision: revid, tree sha
592
550
        """
593
551
        if len(sha) == 40:
594
552
            sha = hex_to_sha(sha)
595
553
        data = self.db["git\0" + sha].split("\0")
596
 
        if data[0] == "commit":
597
 
            if len(data) == 3:
598
 
                return (data[0], (data[1], data[2], {}))
599
 
            else:
600
 
                return (data[0], (data[1], data[2], {"testament3-sha1": data[3]}))
601
 
        else:
602
 
            return (data[0], tuple(data[1:]))
 
554
        return (data[0], (data[1], data[2]))
603
555
 
604
556
    def missing_revisions(self, revids):
605
557
        ret = set()
639
591
        return ShaFile._parse_legacy_object(entry.get_bytes_as('fulltext'))
640
592
 
641
593
 
642
 
class GitObjectStoreContentCache(ContentCache):
643
 
 
644
 
    def __init__(self, store):
645
 
        self.store = store
646
 
 
647
 
    def add_multi(self, objs):
648
 
        self.store.add_objects(objs)
649
 
 
650
 
    def add(self, obj, path):
651
 
        self.store.add_object(obj)
652
 
 
653
 
    def __getitem__(self, sha):
654
 
        return self.store[sha]
655
 
 
656
 
 
657
594
class IndexCacheUpdater(CacheUpdater):
658
595
 
659
596
    def __init__(self, cache, rev):
662
599
        self.parent_revids = rev.parent_ids
663
600
        self._commit = None
664
601
        self._entries = []
665
 
        self._cache_objs = set()
666
602
 
667
 
    def add_object(self, obj, ie, path):
 
603
    def add_object(self, obj, ie):
668
604
        if obj.type_name == "commit":
669
605
            self._commit = obj
670
 
            assert type(ie) is dict
 
606
            assert ie is None
671
607
            self.cache.idmap._add_git_sha(obj.id, "commit",
672
 
                (self.revid, obj.tree, ie))
 
608
                (self.revid, obj.tree))
673
609
            self.cache.idmap._add_node(("commit", self.revid, "X"),
674
610
                " ".join((obj.id, obj.tree)))
675
 
            self._cache_objs.add((obj, path))
676
611
        elif obj.type_name == "blob":
677
612
            self.cache.idmap._add_git_sha(obj.id, "blob",
678
613
                (ie.file_id, ie.revision))
679
614
            self.cache.idmap._add_node(("blob", ie.file_id, ie.revision), obj.id)
680
615
            if ie.kind == "symlink":
681
 
                self._cache_objs.add((obj, path))
 
616
                self.cache.content_cache.add(obj)
682
617
        elif obj.type_name == "tree":
683
618
            self.cache.idmap._add_git_sha(obj.id, "tree",
684
619
                (ie.file_id, self.revid))
685
 
            self._cache_objs.add((obj, path))
 
620
            self.cache.content_cache.add(obj)
686
621
        else:
687
622
            raise AssertionError
688
623
 
689
624
    def finish(self):
690
 
        self.cache.content_cache.add_multi(self._cache_objs)
691
625
        return self._commit
692
626
 
693
627
 
695
629
 
696
630
    def __init__(self, transport=None):
697
631
        mapper = versionedfile.ConstantMapper("trees")
698
 
        shamap = IndexGitShaMap(transport.clone('index'))
699
 
        #trees_store = knit.make_file_factory(True, mapper)(transport)
700
 
        #content_cache = VersionedFilesContentCache(trees_store)
701
 
        from bzrlib.plugins.git.transportgit import TransportObjectStore
702
 
        store = TransportObjectStore(transport.clone('objects'))
703
 
        content_cache = GitObjectStoreContentCache(store)
704
 
        super(IndexBzrGitCache, self).__init__(shamap, content_cache,
 
632
        trees_store = knit.make_file_factory(True, mapper)(transport)
 
633
        super(IndexBzrGitCache, self).__init__(
 
634
                IndexGitShaMap(transport.clone('index')),
 
635
                VersionedFilesContentCache(trees_store),
705
636
                IndexCacheUpdater)
706
637
 
707
638
 
708
639
class IndexGitCacheFormat(BzrGitCacheFormat):
709
640
 
710
641
    def get_format_string(self):
711
 
        return 'bzr-git sha map with git object cache version 1\n'
 
642
        return 'bzr-git sha map version 1\n'
712
643
 
713
644
    def initialize(self, transport):
714
645
        super(IndexGitCacheFormat, self).initialize(transport)
715
646
        transport.mkdir('index')
716
 
        transport.mkdir('objects')
717
 
        from bzrlib.plugins.git.transportgit import TransportObjectStore
718
 
        TransportObjectStore.init(transport.clone('objects'))
719
647
 
720
648
    def open(self, transport):
721
649
        return IndexBzrGitCache(transport)
835
763
    def _add_git_sha(self, hexsha, type, type_data):
836
764
        if hexsha is not None:
837
765
            self._name.update(hexsha)
838
 
            if type == "commit":
839
 
                td = (type_data[0], type_data[1], type_data[2]["testament3-sha1"])
840
 
            else:
841
 
                td = type_data
842
 
            self._add_node(("git", hexsha, "X"), " ".join((type,) + td))
 
766
            self._add_node(("git", hexsha, "X"),
 
767
                " ".join((type, type_data[0], type_data[1])))
843
768
        else:
844
769
            # This object is not represented in Git - perhaps an empty
845
770
            # directory?
851
776
    def lookup_git_sha(self, sha):
852
777
        if len(sha) == 20:
853
778
            sha = sha_to_hex(sha)
854
 
        data = self._get_entry(("git", sha, "X")).split(" ", 3)
855
 
        if data[0] == "commit":
856
 
            return ("commit", (data[1], data[2], {"testament3-sha1": data[3]}))
857
 
        else:
858
 
            return (data[0], tuple(data[1:]))
 
779
        data = self._get_entry(("git", sha, "X")).split(" ", 2)
 
780
        return (data[0], (data[1], data[2]))
859
781
 
860
782
    def revids(self):
861
783
        """List the revision ids known."""
883
805
    SqliteGitCacheFormat())
884
806
formats.register(IndexGitCacheFormat().get_format_string(),
885
807
    IndexGitCacheFormat())
886
 
# In the future, this will become the default:
887
 
# formats.register('default', IndexGitCacheFormat())
888
 
try:
889
 
    import tdb
890
 
except ImportError:
891
 
    formats.register('default', SqliteGitCacheFormat())
892
 
else:
893
 
    formats.register('default', TdbGitCacheFormat())
894
 
 
 
808
formats.register('default', IndexGitCacheFormat())
895
809
 
896
810
 
897
811
def migrate_ancient_formats(repo_transport):