]> git.giacomolli.uk - onechat/blobdiff - build_queue.go
Name and order the build queue code
[onechat] / build_queue.go
similarity index 64%
rename from queue.go
rename to build_queue.go
index c128d6173fd408e669332e0d1106bb2d8019314a..2458f5a185100cfd43a8a33c0db42e0716030f28 100644 (file)
--- a/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]