564
594
yield sha_to_hex(key[4:])
597
class VersionedFilesContentCache(ContentCache):
599
def __init__(self, vf):
603
self._vf.insert_record_stream(
604
[versionedfile.ChunkedContentFactory((obj.id,), [], None,
605
obj.as_legacy_object_chunks())])
607
def __getitem__(self, sha):
608
stream = self._vf.get_record_stream([(sha,)], 'unordered', True)
609
entry = stream.next()
610
if entry.storage_kind == 'absent':
612
return ShaFile._parse_legacy_object(entry.get_bytes_as('fulltext'))
615
class GitObjectStoreContentCache(ContentCache):
617
def __init__(self, store):
620
def add_multi(self, objs):
621
self.store.add_objects(objs)
623
def add(self, obj, path):
624
self.store.add_object(obj)
626
def __getitem__(self, sha):
627
return self.store[sha]
630
class IndexCacheUpdater(CacheUpdater):
632
def __init__(self, cache, rev):
634
self.revid = rev.revision_id
635
self.parent_revids = rev.parent_ids
638
self._cache_objs = set()
640
def add_object(self, obj, ie, path):
641
if obj.type_name == "commit":
644
self.cache.idmap._add_git_sha(obj.id, "commit",
645
(self.revid, obj.tree))
646
self.cache.idmap._add_node(("commit", self.revid, "X"),
647
" ".join((obj.id, obj.tree)))
648
self._cache_objs.add((obj, path))
649
elif obj.type_name == "blob":
650
self.cache.idmap._add_git_sha(obj.id, "blob",
651
(ie.file_id, ie.revision))
652
self.cache.idmap._add_node(("blob", ie.file_id, ie.revision), obj.id)
653
if ie.kind == "symlink":
654
self._cache_objs.add((obj, path))
655
elif obj.type_name == "tree":
656
self.cache.idmap._add_git_sha(obj.id, "tree",
657
(ie.file_id, self.revid))
658
self._cache_objs.add((obj, path))
663
self.cache.content_cache.add_multi(self._cache_objs)
667
class IndexBzrGitCache(BzrGitCache):
669
def __init__(self, transport=None):
670
mapper = versionedfile.ConstantMapper("trees")
671
shamap = IndexGitShaMap(transport.clone('index'))
672
#trees_store = knit.make_file_factory(True, mapper)(transport)
673
#content_cache = VersionedFilesContentCache(trees_store)
674
from bzrlib.plugins.git.transportgit import TransportObjectStore
675
store = TransportObjectStore(transport.clone('objects'))
676
content_cache = GitObjectStoreContentCache(store)
677
super(IndexBzrGitCache, self).__init__(shamap, content_cache,
681
class IndexGitCacheFormat(BzrGitCacheFormat):
683
def get_format_string(self):
684
return 'bzr-git sha map with git object cache version 1\n'
686
def initialize(self, transport):
687
super(IndexGitCacheFormat, self).initialize(transport)
688
transport.mkdir('index')
689
transport.mkdir('objects')
690
from bzrlib.plugins.git.transportgit import TransportObjectStore
691
TransportObjectStore.init(transport.clone('objects'))
693
def open(self, transport):
694
return IndexBzrGitCache(transport)
697
class IndexGitShaMap(GitShaMap):
698
"""SHA Map that uses the Bazaar APIs to store a cache.
700
BTree Index file with the following contents:
702
("git", <sha1>) -> "<type> <type-data1> <type-data2>"
703
("commit", <revid>) -> "<sha1> <tree-id>"
704
("blob", <fileid>, <revid>) -> <sha1>
708
def __init__(self, transport=None):
709
if transport is None:
710
self._transport = None
711
self._index = _mod_index.InMemoryGraphIndex(0, key_elements=3)
712
self._builder = self._index
715
self._transport = transport
716
self._index = _mod_index.CombinedGraphIndex([])
717
for name in self._transport.list_dir("."):
718
if not name.endswith(".rix"):
720
x = _mod_btree_index.BTreeGraphIndex(self._transport, name,
721
self._transport.stat(name).st_size)
722
self._index.insert_index(0, x)
725
def from_repository(cls, repository):
726
transport = getattr(repository, "_transport", None)
727
if transport is not None:
729
transport.mkdir('git')
730
except bzrlib.errors.FileExists:
732
return cls(transport.clone('git'))
733
from bzrlib.transport import get_transport
734
return cls(get_transport(get_cache_dir()))
737
if self._transport is not None:
738
return "%s(%r)" % (self.__class__.__name__, self._transport.base)
740
return "%s()" % (self.__class__.__name__)
743
assert self._builder is None
744
self.start_write_group()
745
for _, key, value in self._index.iter_all_entries():
746
self._builder.add_node(key, value)
748
for name in self._transport.list_dir('.'):
749
if name.endswith('.rix'):
750
to_remove.append(name)
751
self.commit_write_group()
752
del self._index.indices[1:]
753
for name in to_remove:
754
self._transport.rename(name, name + '.old')
756
def start_write_group(self):
757
assert self._builder is None
758
self._builder = _mod_btree_index.BTreeBuilder(0, key_elements=3)
759
self._name = osutils.sha()
761
def commit_write_group(self):
762
assert self._builder is not None
763
stream = self._builder.finish()
764
name = self._name.hexdigest() + ".rix"
765
size = self._transport.put_file(name, stream)
766
index = _mod_btree_index.BTreeGraphIndex(self._transport, name, size)
767
self._index.insert_index(0, index)
771
def abort_write_group(self):
772
assert self._builder is not None
776
def _add_node(self, key, value):
778
self._builder.add_node(key, value)
779
except bzrlib.errors.BadIndexDuplicateKey:
780
# Multiple bzr objects can have the same contents
785
def _get_entry(self, key):
786
entries = self._index.iter_entries([key])
788
return entries.next()[2]
789
except StopIteration:
790
if self._builder is None:
792
entries = self._builder.iter_entries([key])
794
return entries.next()[2]
795
except StopIteration:
798
def _iter_keys_prefix(self, prefix):
799
for entry in self._index.iter_entries_prefix([prefix]):
801
if self._builder is not None:
802
for entry in self._builder.iter_entries_prefix([prefix]):
805
def lookup_commit(self, revid):
806
return self._get_entry(("commit", revid, "X"))[:40]
808
def _add_git_sha(self, hexsha, type, type_data):
809
if hexsha is not None:
810
self._name.update(hexsha)
811
self._add_node(("git", hexsha, "X"),
812
" ".join((type, type_data[0], type_data[1])))
814
# This object is not represented in Git - perhaps an empty
816
self._name.update(type + " ".join(type_data))
818
def lookup_blob_id(self, fileid, revision):
819
return self._get_entry(("blob", fileid, revision))
821
def lookup_git_sha(self, sha):
823
sha = sha_to_hex(sha)
824
data = self._get_entry(("git", sha, "X")).split(" ", 2)
825
return (data[0], (data[1], data[2]))
828
"""List the revision ids known."""
829
for key in self._iter_keys_prefix(("commit", None, None)):
832
def missing_revisions(self, revids):
833
"""Return set of all the revisions that are not present."""
834
missing_revids = set(revids)
835
for _, key, value in self._index.iter_entries((
836
("commit", revid, "X") for revid in revids)):
837
missing_revids.remove(key[1])
838
return missing_revids
841
"""List the SHA1s."""
842
for key in self._iter_keys_prefix(("git", None, None)):
567
846
formats = registry.Registry()
568
847
formats.register(TdbGitCacheFormat().get_format_string(),
569
848
TdbGitCacheFormat())
570
849
formats.register(SqliteGitCacheFormat().get_format_string(),
571
850
SqliteGitCacheFormat())
851
formats.register(IndexGitCacheFormat().get_format_string(),
852
IndexGitCacheFormat())
853
# In the future, this will become the default:
854
# formats.register('default', IndexGitCacheFormat())
574
857
except ImportError: