X-Git-Url: http://git.giacomolli.uk/onechat/blobdiff_plain/7b6d0a81e0f3c8e33b1b76d5ecbc5bdb25a87249:/queue.go..503486b8364f07ef44c06bcc1be566f62600b0eb:/build_queue.go?ds=inline diff --git a/queue.go b/build_queue.go similarity index 64% rename from queue.go rename to build_queue.go index c128d61..2458f5a 100644 --- a/queue.go +++ b/build_queue.go @@ -6,16 +6,24 @@ import ( ) const ( - // maxBuilds is the number of model builds that can run at once. - maxBuilds = 8 + // buildMax is the number of model builds that can run at once. + buildMax = 8 - // leafWindow is the number of unbuilt leaves that can be before a leaf - // whose build starts. - leafWindow = 8 + // buildLeafWindow is the number of unbuilt leaves that can be before a + // leaf whose build starts. + buildLeafWindow = 8 ) -// queue holds the nodes that wait for a model build. A leaf joins it when its -// message is too long to be its own node. A merge joins it when both of its +func newBuildQueue() *BuildQueue { + return &BuildQueue{ + queued: make(map[nodeKey]bool), + running: make(map[nodeKey]bool), + failed: make(map[nodeKey]bool), + } +} + +// BuildQueue holds the nodes that wait for a model build. A leaf joins it when +// its message is too long to be its own node. A merge joins it when both of its // children are built and their texts do not fit in one node. So the core never // scans the tree for work. // @@ -23,36 +31,25 @@ const ( // first starts first. The context of leaf i ends before message i, and the // context of a merge ends after its last message. At a tie the merge starts // first. So a backlog of leaves does not stop the merges that the view needs to -// shrink. A leaf can start only when fewer than leafWindow leaves before it are -// unbuilt. A failed build waits until the next message. -type queue struct { +// shrink. A leaf can start only when fewer than buildLeafWindow leaves before +// it are unbuilt. A failed build waits until the next message. +type BuildQueue struct { leaves []int - merges mergeHeap + merges BuildMergeHeap queued map[nodeKey]bool running map[nodeKey]bool failed map[nodeKey]bool retry []nodeKey } -// mergeHeap holds the merges that can start, by the end of their context. -type mergeHeap []nodeKey - -func newQueue() *queue { - return &queue{ - queued: make(map[nodeKey]bool), - running: make(map[nodeKey]bool), - failed: make(map[nodeKey]bool), - } -} - // AddLeaf adds the leaf of message id. The IDs must come in increasing order. -func (q *queue) AddLeaf(id int) { +func (q *BuildQueue) AddLeaf(id int) { q.leaves = append(q.leaves, id) } // AddMerge adds a merge whose children are built. A merge that is in the queue // already stays as it is. -func (q *queue) AddMerge(key nodeKey) { +func (q *BuildQueue) AddMerge(key nodeKey) { if q.queued[key] { return } @@ -62,8 +59,8 @@ func (q *queue) AddMerge(key nodeKey) { } // Next returns the next node that can start, and marks it as running. -func (q *queue) Next() (nodeKey, bool) { - if len(q.running) >= maxBuilds { +func (q *BuildQueue) Next() (nodeKey, bool) { + if len(q.running) >= buildMax { return nodeKey{}, false } @@ -82,20 +79,8 @@ func (q *queue) Next() (nodeKey, bool) { return leaf, found } -// nextLeaf returns the oldest leaf in the window that can start. -func (q *queue) nextLeaf() (nodeKey, bool) { - for _, id := range q.leaves[:min(len(q.leaves), leafWindow)] { - key := nodeKey{0, id} - if !q.running[key] && !q.failed[key] { - return key, true - } - } - - return nodeKey{}, false -} - // Done removes a built node from the queue. -func (q *queue) Done(key nodeKey) { +func (q *BuildQueue) Done(key nodeKey) { delete(q.running, key) if key.level > 0 { delete(q.queued, key) @@ -109,7 +94,7 @@ func (q *queue) Done(key nodeKey) { } // Fail keeps a node in the queue, but it cannot start until Retry. -func (q *queue) Fail(key nodeKey) { +func (q *BuildQueue) Fail(key nodeKey) { delete(q.running, key) if key.level > 0 { q.retry = append(q.retry, key) @@ -120,7 +105,7 @@ func (q *queue) Fail(key nodeKey) { } // Retry lets the failed nodes start again. -func (q *queue) Retry() { +func (q *BuildQueue) Retry() { clear(q.failed) for _, key := range q.retry { heap.Push(&q.merges, key) @@ -130,27 +115,42 @@ func (q *queue) Retry() { } // Running returns the number of builds that run. -func (q *queue) Running() int { +func (q *BuildQueue) Running() int { return len(q.running) } -func (h mergeHeap) Len() int { +// nextLeaf returns the oldest leaf in the window that can start. +func (q *BuildQueue) nextLeaf() (nodeKey, bool) { + for _, id := range q.leaves[:min(len(q.leaves), buildLeafWindow)] { + key := nodeKey{0, id} + if !q.running[key] && !q.failed[key] { + return key, true + } + } + + return nodeKey{}, false +} + +// BuildMergeHeap holds the merges that can start, by the end of their context. +type BuildMergeHeap []nodeKey + +func (h BuildMergeHeap) Len() int { return len(h) } -func (h mergeHeap) Less(a, b int) bool { +func (h BuildMergeHeap) Less(a, b int) bool { return nodeEnd(h[a].level, h[a].index) < nodeEnd(h[b].level, h[b].index) } -func (h mergeHeap) Swap(a, b int) { +func (h BuildMergeHeap) Swap(a, b int) { h[a], h[b] = h[b], h[a] } -func (h *mergeHeap) Push(value any) { +func (h *BuildMergeHeap) Push(value any) { *h = append(*h, value.(nodeKey)) } -func (h *mergeHeap) Pop() any { +func (h *BuildMergeHeap) Pop() any { old := *h key := old[len(old)-1] *h = old[:len(old)-1]