Skip to content
This repository was archived by the owner on Apr 29, 2020. It is now read-only.

fix: make trickle dag importer compatible with go #29

Merged
merged 2 commits into from
May 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 116 additions & 72 deletions src/dag-builder/file/trickle.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,100 +7,144 @@ module.exports = async function * trickleReduceToRoot (source, reduce, options)
}

async function trickleStream (source, reduce, options) {
let root = {
children: []
}
let node = root
let root
let iteration = 0
let maxDepth = 1
let currentDepth = 1
let layerSize = 0
let subTree = root = new Root(options.layerRepeat)

for await (const layer of batch(source, options.maxChildrenPerNode)) {
node.data = layer

let parent = node.parent || root
const nextNode = {
children: []
}
if (subTree.isFull()) {
if (subTree !== root) {
root.addChild(await subTree.reduce(reduce))
}

if (currentDepth < maxDepth) {
// the current layer can't have more children
// but we can descend a layer
node.children.push(nextNode)
nextNode.parent = node
node = nextNode
currentDepth++
} else if (parent.children.length < options.layerRepeat) {
// the current layer can have more children
parent.children.push(nextNode)
nextNode.parent = parent
node = nextNode
} else if (currentDepth === maxDepth) {
// hit the bottom of the current iteration, can we find a sibling?
parent = findNext(root, 0, maxDepth, options)

if (parent) {
nextNode.parent = parent
parent.children.push(nextNode)
node = nextNode
} else {
if (layerSize === 0) {
maxDepth++
}

layerSize++

if (layerSize === options.layerRepeat) {
layerSize = 0
}

nextNode.parent = root
root.children.push(nextNode)
node = nextNode

currentDepth = 1
if (iteration && iteration % options.layerRepeat === 0) {
maxDepth++
}

subTree = new SubTree(maxDepth, options.layerRepeat, iteration)

iteration++
}

subTree.append(layer)
}

// reduce to root
return walk(root, reduce)
if (subTree && subTree !== root) {
root.addChild(await subTree.reduce(reduce))
}

return root.reduce(reduce)
}

const walk = async (node, reduce) => {
let children = []
class SubTree {
constructor (maxDepth, layerRepeat, iteration) {
this.maxDepth = maxDepth
this.layerRepeat = layerRepeat
this.currentDepth = 1
this.iteration = iteration

this.root = this.node = this.parent = {
children: [],
depth: this.currentDepth,
maxDepth,
maxChildren: (this.maxDepth - this.currentDepth) * this.layerRepeat
}
}

isFull () {
if (!this.root.data) {
return false
}

if (this.currentDepth < this.maxDepth && this.node.maxChildren) {
// can descend
this._addNextNodeToParent(this.node)

return false
}

// try to find new node from node.parent
const distantRelative = this._findParent(this.node, this.currentDepth)

if (distantRelative) {
this._addNextNodeToParent(distantRelative)

return false
}

if (node.children.length) {
children = await Promise.all(
node.children
.filter(child => child.data)
.map(child => walk(child, reduce))
)
return true
}

return reduce(node.data.concat(children))
}
_addNextNodeToParent (parent) {
this.parent = parent

// find site for new node
const nextNode = {
children: [],
depth: parent.depth + 1,
parent,
maxDepth: this.maxDepth,
maxChildren: Math.floor(parent.children.length / this.layerRepeat) * this.layerRepeat
}

parent.children.push(nextNode)

const findNext = (node, depth, maxDepth, options) => {
if (depth === maxDepth) {
return
this.currentDepth = nextNode.depth
this.node = nextNode
}

let nodeMatches = false
append (layer) {
this.node.data = layer
}

reduce (reduce) {
return this._reduce(this.root, reduce)
}

async _reduce (node, reduce) {
let children = []

if (node.children.length) {
children = await Promise.all(
node.children
.filter(child => child.data)
.map(child => this._reduce(child, reduce))
)
}

if (node.children.length < options.layerRepeat) {
nodeMatches = true
return reduce(node.data.concat(children))
}

if (node.children.length) {
const childMatches = findNext(node.children[node.children.length - 1], depth + 1, maxDepth, options)
_findParent (node, depth) {
const parent = node.parent

if (!parent || parent.depth === 0) {
return
}

if (childMatches) {
return childMatches
if (parent.children.length === parent.maxChildren || !parent.maxChildren) {
// this layer is full, may be able to traverse to a different branch
return this._findParent(parent, depth)
}

return parent
}
}

class Root extends SubTree {
constructor (layerRepeat) {
super(0, layerRepeat)

this.root.depth = 0
this.currentDepth = 1
}

addChild (child) {
this.root.children.push(child)
}

if (nodeMatches) {
return node
reduce (reduce) {
return reduce(this.root.data.concat(this.root.children))
}
}
Loading