metadatastore.py
167 lines
| 5.2 KiB
| text/x-python
|
PythonLexer
|
r40530 | from __future__ import absolute_import | ||
|
r47771 | from mercurial.node import ( | ||
hex, | ||||
sha1nodeconstants, | ||||
) | ||||
|
r40530 | from . import ( | ||
basestore, | ||||
shallowutil, | ||||
) | ||||
|
r43346 | |||
|
r40530 | class unionmetadatastore(basestore.baseunionstore): | ||
def __init__(self, *args, **kwargs): | ||||
super(unionmetadatastore, self).__init__(*args, **kwargs) | ||||
self.stores = args | ||||
|
r43906 | self.writestore = kwargs.get('writestore') | ||
|
r40530 | |||
# If allowincomplete==True then the union store can return partial | ||||
# ancestor lists, otherwise it will throw a KeyError if a full | ||||
# history can't be found. | ||||
|
r43906 | self.allowincomplete = kwargs.get('allowincomplete', False) | ||
|
r40530 | |||
def getancestors(self, name, node, known=None): | ||||
"""Returns as many ancestors as we're aware of. | ||||
return value: { | ||||
node: (p1, p2, linknode, copyfrom), | ||||
... | ||||
} | ||||
""" | ||||
if known is None: | ||||
known = set() | ||||
if node in known: | ||||
return [] | ||||
ancestors = {} | ||||
|
r43346 | |||
|
r40530 | def traverse(curname, curnode): | ||
# TODO: this algorithm has the potential to traverse parts of | ||||
# history twice. Ex: with A->B->C->F and A->B->D->F, both D and C | ||||
# may be queued as missing, then B and A are traversed for both. | ||||
queue = [(curname, curnode)] | ||||
missing = [] | ||||
seen = set() | ||||
while queue: | ||||
name, node = queue.pop() | ||||
if (name, node) in seen: | ||||
continue | ||||
seen.add((name, node)) | ||||
value = ancestors.get(node) | ||||
if not value: | ||||
missing.append((name, node)) | ||||
continue | ||||
p1, p2, linknode, copyfrom = value | ||||
|
r47771 | if p1 != sha1nodeconstants.nullid and p1 not in known: | ||
|
r40530 | queue.append((copyfrom or curname, p1)) | ||
|
r47771 | if p2 != sha1nodeconstants.nullid and p2 not in known: | ||
|
r40530 | queue.append((curname, p2)) | ||
return missing | ||||
missing = [(name, node)] | ||||
while missing: | ||||
curname, curnode = missing.pop() | ||||
try: | ||||
|
r43346 | ancestors.update( | ||
self._getpartialancestors(curname, curnode, known=known) | ||||
) | ||||
|
r40530 | newmissing = traverse(curname, curnode) | ||
missing.extend(newmissing) | ||||
except KeyError: | ||||
# If we allow incomplete histories, don't throw. | ||||
if not self.allowincomplete: | ||||
raise | ||||
# If the requested name+node doesn't exist, always throw. | ||||
if (curname, curnode) == (name, node): | ||||
raise | ||||
# TODO: ancestors should probably be (name, node) -> (value) | ||||
return ancestors | ||||
@basestore.baseunionstore.retriable | ||||
def _getpartialancestors(self, name, node, known=None): | ||||
for store in self.stores: | ||||
try: | ||||
return store.getancestors(name, node, known=known) | ||||
except KeyError: | ||||
pass | ||||
raise KeyError((name, hex(node))) | ||||
@basestore.baseunionstore.retriable | ||||
def getnodeinfo(self, name, node): | ||||
for store in self.stores: | ||||
try: | ||||
return store.getnodeinfo(name, node) | ||||
except KeyError: | ||||
pass | ||||
raise KeyError((name, hex(node))) | ||||
def add(self, name, node, data): | ||||
|
r43346 | raise RuntimeError( | ||
|
r43387 | b"cannot add content only to remotefilelog contentstore" | ||
|
r43346 | ) | ||
|
r40530 | |||
def getmissing(self, keys): | ||||
missing = keys | ||||
for store in self.stores: | ||||
if missing: | ||||
missing = store.getmissing(missing) | ||||
return missing | ||||
def markledger(self, ledger, options=None): | ||||
for store in self.stores: | ||||
store.markledger(ledger, options) | ||||
def getmetrics(self): | ||||
metrics = [s.getmetrics() for s in self.stores] | ||||
return shallowutil.sumdicts(*metrics) | ||||
|
r43346 | |||
|
r40530 | class remotefilelogmetadatastore(basestore.basestore): | ||
def getancestors(self, name, node, known=None): | ||||
"""Returns as many ancestors as we're aware of. | ||||
return value: { | ||||
node: (p1, p2, linknode, copyfrom), | ||||
... | ||||
} | ||||
""" | ||||
data = self._getdata(name, node) | ||||
ancestors = shallowutil.ancestormap(data) | ||||
return ancestors | ||||
def getnodeinfo(self, name, node): | ||||
return self.getancestors(name, node)[node] | ||||
def add(self, name, node, parents, linknode): | ||||
|
r43346 | raise RuntimeError( | ||
|
r43387 | b"cannot add metadata only to remotefilelog metadatastore" | ||
|
r43346 | ) | ||
|
r40530 | |||
class remotemetadatastore(object): | ||||
def __init__(self, ui, fileservice, shared): | ||||
self._fileservice = fileservice | ||||
self._shared = shared | ||||
def getancestors(self, name, node, known=None): | ||||
|
r43346 | self._fileservice.prefetch( | ||
[(name, hex(node))], force=True, fetchdata=False, fetchhistory=True | ||||
) | ||||
|
r40530 | return self._shared.getancestors(name, node, known=known) | ||
def getnodeinfo(self, name, node): | ||||
return self.getancestors(name, node)[node] | ||||
def add(self, name, node, data): | ||||
|
r43347 | raise RuntimeError(b"cannot add to a remote store") | ||
|
r40530 | |||
def getmissing(self, keys): | ||||
return keys | ||||
def markledger(self, ledger, options=None): | ||||
pass | ||||