564
585
yield sha_to_hex(key[4:])
588
class VersionedFilesContentCache(ContentCache):
590
def __init__(self, vf):
594
self._vf.insert_record_stream(
595
[versionedfile.ChunkedContentFactory((obj.id,), [], None,
596
obj.as_legacy_object_chunks())])
598
def __getitem__(self, sha):
599
stream = self._vf.get_record_stream([(sha,)], 'unordered', True)
600
entry = stream.next()
601
if entry.storage_kind == 'absent':
603
return ShaFile._parse_legacy_object(entry.get_bytes_as('fulltext'))
606
class GitObjectStoreContentCache(ContentCache):
608
def __init__(self, store):
612
self.store.add_object(obj)
614
def __getitem__(self, sha):
615
return self.store[sha]
618
class IndexCacheUpdater(CacheUpdater):
620
def __init__(self, cache, rev):
622
self.revid = rev.revision_id
623
self.parent_revids = rev.parent_ids
627
def add_object(self, obj, ie):
628
if obj.type_name == "commit":
631
self.cache.idmap._add_git_sha(obj.id, "commit",
632
(self.revid, obj.tree))
633
self.cache.idmap._add_node(("commit", self.revid, "X"),
634
" ".join((obj.id, obj.tree)))
635
self.cache.content_cache.add(obj)
636
elif obj.type_name == "blob":
637
self.cache.idmap._add_git_sha(obj.id, "blob",
638
(ie.file_id, ie.revision))
639
self.cache.idmap._add_node(("blob", ie.file_id, ie.revision), obj.id)
640
if ie.kind == "symlink":
641
self.cache.content_cache.add(obj)
642
elif obj.type_name == "tree":
643
self.cache.idmap._add_git_sha(obj.id, "tree",
644
(ie.file_id, self.revid))
645
self.cache.content_cache.add(obj)
653
class IndexBzrGitCache(BzrGitCache):
655
def __init__(self, transport=None):
656
mapper = versionedfile.ConstantMapper("trees")
657
shamap = IndexGitShaMap(transport.clone('index'))
658
#trees_store = knit.make_file_factory(True, mapper)(transport)
659
#content_cache = VersionedFilesContentCache(trees_store)
660
from bzrlib.plugins.git.transportgit import TransportObjectStore
661
store = TransportObjectStore(transport.clone('objects'))
662
content_cache = GitObjectStoreContentCache(store)
663
super(IndexBzrGitCache, self).__init__(shamap, content_cache,
667
class IndexGitCacheFormat(BzrGitCacheFormat):
669
def get_format_string(self):
670
return 'bzr-git sha map with git object cache version 1\n'
672
def initialize(self, transport):
673
super(IndexGitCacheFormat, self).initialize(transport)
674
transport.mkdir('index')
675
transport.mkdir('objects')
676
from bzrlib.plugins.git.transportgit import TransportObjectStore
677
TransportObjectStore.init(transport.clone('objects'))
679
def open(self, transport):
680
return IndexBzrGitCache(transport)
683
class IndexGitShaMap(GitShaMap):
684
"""SHA Map that uses the Bazaar APIs to store a cache.
686
BTree Index file with the following contents:
688
("git", <sha1>) -> "<type> <type-data1> <type-data2>"
689
("commit", <revid>) -> "<sha1> <tree-id>"
690
("blob", <fileid>, <revid>) -> <sha1>
694
def __init__(self, transport=None):
695
if transport is None:
696
self._transport = None
697
self._index = _mod_index.InMemoryGraphIndex(0, key_elements=3)
698
self._builder = self._index
701
self._transport = transport
702
self._index = _mod_index.CombinedGraphIndex([])
703
for name in self._transport.list_dir("."):
704
if not name.endswith(".rix"):
706
x = _mod_btree_index.BTreeGraphIndex(self._transport, name,
707
self._transport.stat(name).st_size)
708
self._index.insert_index(0, x)
711
def from_repository(cls, repository):
712
transport = getattr(repository, "_transport", None)
713
if transport is not None:
715
transport.mkdir('git')
716
except bzrlib.errors.FileExists:
718
return cls(transport.clone('git'))
719
from bzrlib.transport import get_transport
720
return cls(get_transport(get_cache_dir()))
723
if self._transport is not None:
724
return "%s(%r)" % (self.__class__.__name__, self._transport.base)
726
return "%s()" % (self.__class__.__name__)
729
assert self._builder is None
730
self.start_write_group()
731
for _, key, value in self._index.iter_all_entries():
732
self._builder.add_node(key, value)
734
for name in self._transport.list_dir('.'):
735
if name.endswith('.rix'):
736
to_remove.append(name)
737
self.commit_write_group()
738
del self._index.indices[1:]
739
for name in to_remove:
740
self._transport.rename(name, name + '.old')
742
def start_write_group(self):
743
assert self._builder is None
744
self._builder = _mod_btree_index.BTreeBuilder(0, key_elements=3)
745
self._name = osutils.sha()
747
def commit_write_group(self):
748
assert self._builder is not None
749
stream = self._builder.finish()
750
name = self._name.hexdigest() + ".rix"
751
size = self._transport.put_file(name, stream)
752
index = _mod_btree_index.BTreeGraphIndex(self._transport, name, size)
753
self._index.insert_index(0, index)
757
def abort_write_group(self):
758
assert self._builder is not None
762
def _add_node(self, key, value):
764
self._builder.add_node(key, value)
765
except bzrlib.errors.BadIndexDuplicateKey:
766
# Multiple bzr objects can have the same contents
771
def _get_entry(self, key):
772
entries = self._index.iter_entries([key])
774
return entries.next()[2]
775
except StopIteration:
776
if self._builder is None:
778
entries = self._builder.iter_entries([key])
780
return entries.next()[2]
781
except StopIteration:
784
def _iter_keys_prefix(self, prefix):
785
for entry in self._index.iter_entries_prefix([prefix]):
787
if self._builder is not None:
788
for entry in self._builder.iter_entries_prefix([prefix]):
791
def lookup_commit(self, revid):
792
return self._get_entry(("commit", revid, "X"))[:40]
794
def _add_git_sha(self, hexsha, type, type_data):
795
if hexsha is not None:
796
self._name.update(hexsha)
797
self._add_node(("git", hexsha, "X"),
798
" ".join((type, type_data[0], type_data[1])))
800
# This object is not represented in Git - perhaps an empty
802
self._name.update(type + " ".join(type_data))
804
def lookup_blob_id(self, fileid, revision):
805
return self._get_entry(("blob", fileid, revision))
807
def lookup_git_sha(self, sha):
809
sha = sha_to_hex(sha)
810
data = self._get_entry(("git", sha, "X")).split(" ", 2)
811
return (data[0], (data[1], data[2]))
814
"""List the revision ids known."""
815
for key in self._iter_keys_prefix(("commit", None, None)):
818
def missing_revisions(self, revids):
819
"""Return set of all the revisions that are not present."""
820
missing_revids = set(revids)
821
for _, key, value in self._index.iter_entries((
822
("commit", revid, "X") for revid in revids)):
823
missing_revids.remove(key[1])
824
return missing_revids
827
"""List the SHA1s."""
828
for key in self._iter_keys_prefix(("git", None, None)):
567
832
formats = registry.Registry()
568
833
formats.register(TdbGitCacheFormat().get_format_string(),
569
834
TdbGitCacheFormat())
570
835
formats.register(SqliteGitCacheFormat().get_format_string(),
571
836
SqliteGitCacheFormat())
837
formats.register(IndexGitCacheFormat().get_format_string(),
838
IndexGitCacheFormat())
839
# In the future, this will become the default:
840
# formats.register('default', IndexGitCacheFormat())
574
843
except ImportError: