go/store/datas/pull/pulling.md
The approach is to explore the chunk graph of both sink and source in order of decreasing ref-height. As the code walks, it uses the knowledge gained about which chunks are present in the sink to both prune the source-graph-walk and build up a set of hints that can be sent to a remote Database to aid in chunk validation.
let sink be the sink database
let source be the source database
let snkQ and srcQ be priority queues of Ref prioritized by highest Ref.height
let hints be a map of hash => hash
let reachableChunks be a set of hashes
let snkHdRef be the ref (of Commit) of the head of the sink dataset
let srcHdRef be the ref of the source Commit, which must descend from the Commit indicated by snkHdRef
let traverseSource(srcRef, srcQ, sink, source, reachableChunks) be
srcRef from srcQ
!sink.has(srcRef)
c = source.batchStore().Get(srcRef.targetHash)v = types.DecodeValue(c, source)cr, from v into srcQ and into reachableRefssink.batchStore().Put(c, srcRef.height, no hints)
let traverseSink(sinkRef, snkQ, sink, hints) be
snkRef from snkQsnkRef.height > 1
v = sink.readValue(snkRef.targetHash)cr, from v into snkQ and hints[cr] = snkReflet traverseCommon(comRef, snkHdRef, snkQ, srcQ, sink, hints) be
comRef from both snkQ and srcQcomRef.height > 1
comRef is a Ref of Commit
v = sink.readValue(comRef.targetHash)comRef == snkHdRef
cr from v into snkQ only, set hints[cr] = comRefcr from v into both snkQ and srcQ, set hints[cr] = comReflet `pull(source, sink, srcHdRef, sinkHdRef)
snkHdRef into snkQ and srcHdRef into srcQhints and reachableChunkssrcQ is non-empty
srcHt and snkHt be the respective heights of the top Ref in each of srcQ and snkQsrcHt > snkHt, for every srcHdRef in srcQ which is of greater height than snkHt
traverseSource(srcHdRef, srcQ, sink, source)snkHt > srcHt, for every snkHdRef in snkQ which is of greater height than srcHt
traverseSink(snkHdRef, snkQ, sink)comRef in which is common to snkQ and srcQ which is of height srcHt (and snkHt)
traverseCommon(comRef, snkHdRef, snkQ, srcQ, sink, hints)ref in srcQ which is of height srcHt
traverseSource(ref, srcQ, sink, source, reachableChunks)ref in snkQ which is of height snkHt
traverseSink(ref, snkQ, sink, hints)hash in reachableChunks
let all identifiers be as above
let traverseSource, traverseSink, and traverseCommon be as above
let higherThan(refA, refB) be
let `pull(source, sink, srcHdRef, sinkHdRef)
snkHdRef into snkQ and srcHdRef into srcQhints and reachableChunkssrcQ is non-empty
sinkQ is empty
ref from srcQhigherThan(head of srcQ, head of snkQ)
ref from srcQhigherThan(head of snkQ, head of srcQ)
ref from snkQtraverseSink(ref, snkQ, sink, hints)comRef from snkQ and srcQtraverseCommon(comRef, snkHdRef, snkQ, srcQ, sink, hints)hash in reachableChunks