mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 01:07:15 +03:00
12ec6ebcb4
Summary: In a remotecontent/metadatastore a `get` request first runs prefetch, then reads the resulting data from the shared cache store. Before this patch, the prefetch would not download a value if it existed in the local data store, which means nothing would be added to the shared cache store, and the `get` would fail. This patch changes the remote stores to always prefetch based only on the contents of the shared cache, so data will always be written. This issue showed up when attempting to repack pack files that contained references to nodes that were in the local store (which it didn't have access to) but not the shared cache. Test Plan: Manually verified my issue disappeared. This isn't actually an issue anymore, since future patches refactor the way repack works to not rely on the remote stores, so this shouldn't be hit again. But it's a safe change regardless. Reviewers: #mercurial, ttung, mitrandir Reviewed By: mitrandir Differential Revision: https://phabricator.intern.facebook.com/D3278362 Signature: t1:3278362:1463086099:987d2fdd1c75e518f815c3159473e8cb22a15ba0
109 lines
3.5 KiB
Python
109 lines
3.5 KiB
Python
import os
|
|
import basestore, shallowutil
|
|
from mercurial import error, util
|
|
from mercurial.i18n import _
|
|
from mercurial.node import hex, nullid
|
|
|
|
class unionmetadatastore(object):
|
|
def __init__(self, *args, **kwargs):
|
|
self.stores = args
|
|
self.writestore = kwargs.get('writestore')
|
|
|
|
def getancestors(self, name, node):
|
|
"""Returns as many ancestors as we're aware of.
|
|
|
|
return value: {
|
|
node: (p1, p2, linknode, copyfrom),
|
|
...
|
|
}
|
|
"""
|
|
ancestors = {}
|
|
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 = []
|
|
while queue:
|
|
name, node = queue.pop()
|
|
value = ancestors.get(node)
|
|
if not value:
|
|
missing.append((name, node))
|
|
continue
|
|
p1, p2, linknode, copyfrom = value
|
|
if p1 != nullid:
|
|
queue.append((copyfrom or curname, p1))
|
|
if p2 != nullid:
|
|
queue.append((curname, p2))
|
|
return missing
|
|
|
|
missing = [(name, node)]
|
|
while missing:
|
|
curname, curnode = missing.pop()
|
|
ancestors.update(self._getpartialancestors(curname, curnode))
|
|
newmissing = traverse(curname, curnode)
|
|
missing.extend(newmissing)
|
|
|
|
# TODO: ancestors should probably be (name, node) -> (value)
|
|
return ancestors
|
|
|
|
def _getpartialancestors(self, name, node):
|
|
for store in self.stores:
|
|
try:
|
|
return store.getancestors(name, node)
|
|
except KeyError:
|
|
pass
|
|
|
|
raise error.LookupError(node, name, _('no valid file history'))
|
|
|
|
def add(self, name, node, data):
|
|
raise RuntimeError("cannot add content only to remotefilelog "
|
|
"contentstore")
|
|
|
|
def getmissing(self, keys):
|
|
missing = keys
|
|
for store in self.stores:
|
|
if missing:
|
|
missing = store.getmissing(missing)
|
|
return missing
|
|
|
|
def markledger(self, ledger):
|
|
for store in self.stores:
|
|
store.markledger(ledger)
|
|
|
|
class remotefilelogmetadatastore(basestore.basestore):
|
|
def getancestors(self, name, node):
|
|
"""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 add(self, name, node, parents, linknode):
|
|
raise RuntimeError("cannot add metadata only to remotefilelog "
|
|
"metadatastore")
|
|
|
|
class remotemetadatastore(object):
|
|
def __init__(self, ui, fileservice, shared):
|
|
self._fileservice = fileservice
|
|
self._shared = shared
|
|
|
|
def getancestors(self, name, node):
|
|
self._fileservice.prefetch([(name, hex(node))], force=True,
|
|
fetchdata=False, fetchhistory=True)
|
|
return self._shared.getancestors(name, node)
|
|
|
|
def add(self, name, node, data):
|
|
raise RuntimeError("cannot add to a remote store")
|
|
|
|
def getmissing(self, keys):
|
|
return keys
|
|
|
|
def markledger(self, ledger):
|
|
pass
|