Fast implementation of Git in pure Go codeberg.org/lindenii/furgit
git go
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

commitquery: Make a reusable engine thingy

Runxi Yu 06583274 7654ba81

+161 -44
+2 -2
commitquery/ancestor.go
··· 6 6 // commit parent edges. 7 7 // 8 8 // Both inputs are peeled through annotated tags before commit traversal. 9 - func (query *Query) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, error) { 9 + func (query *query) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, error) { 10 10 ancestorIdx, err := query.resolveCommitish(ancestor) 11 11 if err != nil { 12 12 return false, err ··· 20 20 return query.isAncestor(ancestorIdx, descendantIdx) 21 21 } 22 22 23 - func (query *Query) isAncestor(ancestor, descendant nodeIndex) (bool, error) { 23 + func (query *query) isAncestor(ancestor, descendant nodeIndex) (bool, error) { 24 24 if ancestor == descendant { 25 25 return true, nil 26 26 }
+1 -1
commitquery/compare.go
··· 3 3 import objectid "codeberg.org/lindenii/furgit/object/id" 4 4 5 5 // Compare compares two internal nodes using merge-base queue ordering. 6 - func (query *Query) compare(left, right nodeIndex) int { 6 + func (query *query) compare(left, right nodeIndex) int { 7 7 leftGeneration := query.effectiveGeneration(left) 8 8 rightGeneration := query.effectiveGeneration(right) 9 9
+11 -7
commitquery/context.go
··· 7 7 objectstore "codeberg.org/lindenii/furgit/object/store" 8 8 ) 9 9 10 - // Query owns the mutable node arena for commit-domain queries over one object 11 - // store. 12 - type Query struct { 10 + type query struct { 13 11 store objectstore.ReadingStore 14 12 graph *commitgraphread.Reader 15 13 ··· 22 20 touched []nodeIndex 23 21 } 24 22 25 - // New builds one reusable commit query arena over one object store and optional 26 - // commit-graph reader. 27 - func New(store objectstore.ReadingStore, graph *commitgraphread.Reader) *Query { 28 - return &Query{ 23 + func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *query { 24 + return &query{ 29 25 store: store, 30 26 graph: graph, 31 27 byOID: make(map[objectid.ObjectID]nodeIndex), 32 28 byGraphPos: make(map[commitgraphread.Position]nodeIndex), 33 29 } 34 30 } 31 + 32 + func (query *query) resetForReuse() { 33 + for _, idx := range query.touched { 34 + query.nodes[idx].marks = 0 35 + } 36 + 37 + query.touched = query.touched[:0] 38 + }
+2 -2
commitquery/generation.go
··· 7 7 ) 8 8 9 9 // EffectiveGeneration returns one node's generation value. 10 - func (query *Query) effectiveGeneration(idx nodeIndex) uint64 { 10 + func (query *query) effectiveGeneration(idx nodeIndex) uint64 { 11 11 if !query.nodes[idx].hasGeneration { 12 12 return generationInfinity 13 13 } ··· 19 19 generationInfinity = uint64(math.MaxUint64) 20 20 ) 21 21 22 - func compareByGeneration(query *Query) func(nodeIndex, nodeIndex) int { 22 + func compareByGeneration(query *query) func(nodeIndex, nodeIndex) int { 23 23 return func(left, right nodeIndex) int { 24 24 leftGeneration := query.effectiveGeneration(left) 25 25 rightGeneration := query.effectiveGeneration(right)
+3 -3
commitquery/graph_pos.go
··· 3 3 import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 4 4 5 5 // resolveGraphPos resolves one commit-graph position to one internal query node. 6 - func (query *Query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { 6 + func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { 7 7 idx, ok := query.byGraphPos[pos] 8 8 if ok { 9 9 err := query.ensureLoaded(idx) ··· 40 40 } 41 41 42 42 // loadByGraphPos populates one node from a commit-graph position. 43 - func (query *Query) loadByGraphPos(idx nodeIndex) error { 43 + func (query *query) loadByGraphPos(idx nodeIndex) error { 44 44 pos := query.nodes[idx].graphPos 45 45 46 46 return query.loadCommitAtGraphPos(idx, pos) 47 47 } 48 48 49 - func (query *Query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error { 49 + func (query *query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error { 50 50 commit, err := query.graph.CommitAt(pos) 51 51 if err != nil { 52 52 return err
+1 -1
commitquery/load.go
··· 1 1 package commitquery 2 2 3 3 // ensureLoaded completes one node's metadata load if it has not been loaded yet. 4 - func (query *Query) ensureLoaded(idx nodeIndex) error { 4 + func (query *query) ensureLoaded(idx nodeIndex) error { 5 5 if query.nodes[idx].loaded { 6 6 return nil 7 7 }
+9 -9
commitquery/marks.go
··· 1 1 package commitquery 2 2 3 3 // Marks returns the mark bits of one internal node. 4 - func (query *Query) marks(idx nodeIndex) markBits { 4 + func (query *query) marks(idx nodeIndex) markBits { 5 5 return query.nodes[idx].marks 6 6 } 7 7 8 8 // HasAnyMarks reports whether one internal node has any requested bit. 9 - func (query *Query) hasAnyMarks(idx nodeIndex, bits markBits) bool { 9 + func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool { 10 10 return query.nodes[idx].marks&bits != 0 11 11 } 12 12 13 13 // HasAllMarks reports whether one internal node already has all requested bits. 14 - func (query *Query) hasAllMarks(idx nodeIndex, bits markBits) bool { 14 + func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool { 15 15 return query.nodes[idx].marks&bits == bits 16 16 } 17 17 18 18 // SetMarks ORs one set of mark bits into one internal node. 19 - func (query *Query) setMarks(idx nodeIndex, bits markBits) { 19 + func (query *query) setMarks(idx nodeIndex, bits markBits) { 20 20 newBits := bits &^ query.nodes[idx].marks 21 21 if newBits == 0 { 22 22 return ··· 27 27 } 28 28 29 29 // ClearMarks removes one set of mark bits from one internal node. 30 - func (query *Query) clearMarks(idx nodeIndex, bits markBits) { 30 + func (query *query) clearMarks(idx nodeIndex, bits markBits) { 31 31 if query.nodes[idx].marks&bits == 0 { 32 32 return 33 33 } ··· 37 37 } 38 38 39 39 // BeginMarkPhase starts one tracked mark-mutation phase. 40 - func (query *Query) beginMarkPhase() { 40 + func (query *query) beginMarkPhase() { 41 41 for _, idx := range query.touched { 42 42 query.nodes[idx].marks = 0 43 43 } ··· 55 55 56 56 // ClearTouchedMarks clears the provided bits from all nodes touched in the 57 57 // current mark phase. 58 - func (query *Query) clearTouchedMarks(bits markBits) { 58 + func (query *query) clearTouchedMarks(bits markBits) { 59 59 for _, idx := range query.touched { 60 60 query.nodes[idx].marks &^= bits 61 61 } 62 62 } 63 63 64 - func (query *Query) trackTouched(idx nodeIndex) { 64 + func (query *query) trackTouched(idx nodeIndex) { 65 65 if query.nodes[idx].touchedPhase == query.markPhase { 66 66 return 67 67 } ··· 70 70 query.touched = append(query.touched, idx) 71 71 } 72 72 73 - func (query *Query) collectMarkedResults() []nodeIndex { 73 + func (query *query) collectMarkedResults() []nodeIndex { 74 74 out := make([]nodeIndex, 0, 4) 75 75 76 76 for _, idx := range query.touched {
+3 -3
commitquery/merge_bases.go
··· 9 9 // MergeBases reports all merge bases in Git's merge-base --all order. 10 10 // 11 11 // Both inputs are peeled through annotated tags before commit traversal. 12 - func (query *Query) MergeBases(left, right objectid.ObjectID) ([]objectid.ObjectID, error) { 12 + func (query *query) MergeBases(left, right objectid.ObjectID) ([]objectid.ObjectID, error) { 13 13 leftIdx, err := query.resolveCommitish(left) 14 14 if err != nil { 15 15 return nil, err ··· 45 45 } 46 46 47 47 // MergeBase reports one merge base between left and right, if any. 48 - func (query *Query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { 48 + func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { 49 49 bases, err := query.MergeBases(left, right) 50 50 if err != nil { 51 51 return objectid.ObjectID{}, false, err ··· 58 58 return bases[0], true, nil 59 59 } 60 60 61 - func (query *Query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { 61 + func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { 62 62 if left == right { 63 63 return []nodeIndex{left}, nil 64 64 }
+1 -1
commitquery/node.go
··· 28 28 } 29 29 30 30 // newNode allocates one empty internal node. 31 - func (query *Query) newNode(id objectid.ObjectID) nodeIndex { 31 + func (query *query) newNode(id objectid.ObjectID) nodeIndex { 32 32 count := len(query.nodes) 33 33 34 34 idx := nodeIndex(count)
+5 -5
commitquery/oid.go
··· 12 12 objecttype "codeberg.org/lindenii/furgit/object/type" 13 13 ) 14 14 15 - func (query *Query) id(idx nodeIndex) objectid.ObjectID { 15 + func (query *query) id(idx nodeIndex) objectid.ObjectID { 16 16 return query.nodes[idx].id 17 17 } 18 18 19 - func (query *Query) commitTime(idx nodeIndex) int64 { 19 + func (query *query) commitTime(idx nodeIndex) int64 { 20 20 return query.nodes[idx].commitTime 21 21 } 22 22 23 - func (query *Query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { 23 + func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { 24 24 idx, ok := query.byOID[id] 25 25 if ok { 26 26 err := query.ensureLoaded(idx) ··· 44 44 return idx, nil 45 45 } 46 46 47 - func (query *Query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { 47 + func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { 48 48 commitID, err := peel.ToCommit(query.store, id) 49 49 if err != nil { 50 50 return 0, err ··· 54 54 } 55 55 56 56 // loadByOID populates one node from an object ID. 57 - func (query *Query) loadByOID(idx nodeIndex) error { 57 + func (query *query) loadByOID(idx nodeIndex) error { 58 58 id := query.nodes[idx].id 59 59 60 60 if query.graph != nil {
+1 -1
commitquery/paint.go
··· 1 1 package commitquery 2 2 3 - func (query *Query) paintDownToCommon(left nodeIndex, rights []nodeIndex, minGeneration uint64) error { 3 + func (query *query) paintDownToCommon(left nodeIndex, rights []nodeIndex, minGeneration uint64) error { 4 4 query.beginMarkPhase() 5 5 6 6 query.setMarks(left, markLeft)
+2 -2
commitquery/parent.go
··· 13 13 } 14 14 15 15 // Parents returns resolved parent node indices for one internal node. 16 - func (query *Query) parents(idx nodeIndex) []nodeIndex { 16 + func (query *query) parents(idx nodeIndex) []nodeIndex { 17 17 return query.nodes[idx].parents 18 18 } 19 19 20 20 // resolveParent resolves one parent descriptor to one internal node. 21 - func (query *Query) resolveParent(parent parentRef) (nodeIndex, error) { 21 + func (query *query) resolveParent(parent parentRef) (nodeIndex, error) { 22 22 if parent.HasGraphPos { 23 23 return query.resolveGraphPos(parent.GraphPos) 24 24 }
+1 -1
commitquery/populate.go
··· 3 3 import "fmt" 4 4 5 5 // populateNode fills one node's metadata and resolves its parents. 6 - func (query *Query) populateNode(idx nodeIndex, commit commitData) error { 6 + func (query *query) populateNode(idx nodeIndex, commit commitData) error { 7 7 if query.nodes[idx].loaded { 8 8 if query.nodes[idx].id != commit.ID { 9 9 return fmt.Errorf("commitquery: node identity mismatch: have %s, got %s", query.nodes[idx].id, commit.ID)
+3 -3
commitquery/priority_queue.go
··· 4 4 5 5 // priorityQueue orders internal nodes using one query context's comparator. 6 6 type priorityQueue struct { 7 - query *Query 7 + query *query 8 8 items []nodeIndex 9 9 } 10 10 11 11 // newPriorityQueue builds one empty priority queue over one query context. 12 - func newPriorityQueue(query *Query) *priorityQueue { 12 + func newPriorityQueue(query *query) *priorityQueue { 13 13 queue := &priorityQueue{query: query} 14 14 heap.Init(queue) 15 15 ··· 67 67 return idx 68 68 } 69 69 70 - func (query *Query) queueHasNonStale(queue *priorityQueue) bool { 70 + func (query *query) queueHasNonStale(queue *priorityQueue) bool { 71 71 // TODO 72 72 for _, idx := range queue.items { 73 73 if !query.hasAnyMarks(idx, markStale) {
+23
commitquery/queries.go
··· 1 + package commitquery 2 + 3 + import ( 4 + "sync" 5 + 6 + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 7 + objectstore "codeberg.org/lindenii/furgit/object/store" 8 + ) 9 + 10 + // Queries provides commit-domain queries over one object store 11 + // and optional commit-graph reader. 12 + // 13 + // Queries reuses internal mutable query workers across operations. 14 + // 15 + // Labels: MT-Safe. 16 + type Queries struct { 17 + store objectstore.ReadingStore 18 + graph *commitgraphread.Reader 19 + 20 + mu sync.Mutex 21 + idle []*query 22 + maxIdle int 23 + }
+16
commitquery/queries_acquire.go
··· 1 + package commitquery 2 + 3 + func (queries *Queries) acquire() *query { 4 + queries.mu.Lock() 5 + defer queries.mu.Unlock() 6 + 7 + count := len(queries.idle) 8 + if count == 0 { 9 + return newQuery(queries.store, queries.graph) 10 + } 11 + 12 + q := queries.idle[count-1] 13 + queries.idle = queries.idle[:count-1] 14 + 15 + return q 16 + }
+14
commitquery/queries_ancestor.go
··· 1 + package commitquery 2 + 3 + import objectid "codeberg.org/lindenii/furgit/object/id" 4 + 5 + // IsAncestor reports whether ancestor is reachable from descendant through 6 + // commit parent edges. 7 + // 8 + // Both inputs are peeled through annotated tags before commit traversal. 9 + func (queries *Queries) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, error) { 10 + query := queries.acquire() 11 + defer queries.release(query) 12 + 13 + return query.IsAncestor(ancestor, descendant) 14 + }
+21
commitquery/queries_mergebase.go
··· 1 + package commitquery 2 + 3 + import objectid "codeberg.org/lindenii/furgit/object/id" 4 + 5 + // MergeBases reports all merge bases in Git's merge-base --all order. 6 + // 7 + // Both inputs are peeled through annotated tags before commit traversal. 8 + func (queries *Queries) MergeBases(left, right objectid.ObjectID) ([]objectid.ObjectID, error) { 9 + query := queries.acquire() 10 + defer queries.release(query) 11 + 12 + return query.MergeBases(left, right) 13 + } 14 + 15 + // MergeBase reports one merge base between left and right, if any. 16 + func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { 17 + query := queries.acquire() 18 + defer queries.release(query) 19 + 20 + return query.MergeBase(left, right) 21 + }
+25
commitquery/queries_new.go
··· 1 + package commitquery 2 + 3 + import ( 4 + "runtime" 5 + 6 + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 7 + objectstore "codeberg.org/lindenii/furgit/object/store" 8 + ) 9 + 10 + // New builds one concurrent-safe commit query service over one object store 11 + // and optional commit-graph reader. 12 + // 13 + // Labels: Deps-Borrowed. 14 + func New(store objectstore.ReadingStore, graph *commitgraphread.Reader) *Queries { 15 + maxIdle := runtime.GOMAXPROCS(0) 16 + if maxIdle < 1 { 17 + maxIdle = 1 18 + } 19 + 20 + return &Queries{ 21 + store: store, 22 + graph: graph, 23 + maxIdle: maxIdle, 24 + } 25 + }
+14
commitquery/queries_release.go
··· 1 + package commitquery 2 + 3 + func (queries *Queries) release(q *query) { 4 + q.resetForReuse() 5 + 6 + queries.mu.Lock() 7 + defer queries.mu.Unlock() 8 + 9 + if len(queries.idle) >= queries.maxIdle { 10 + return 11 + } 12 + 13 + queries.idle = append(queries.idle, q) 14 + }
+3 -3
commitquery/reduce.go
··· 5 5 ) 6 6 7 7 // removeRedundant removes redundant merge-base candidates. 8 - func removeRedundant(query *Query, candidates []nodeIndex) ([]nodeIndex, error) { 8 + func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error) { 9 9 for _, idx := range candidates { 10 10 if query.effectiveGeneration(idx) != generationInfinity { 11 11 return removeRedundantWithGen(query, candidates), nil ··· 15 15 return removeRedundantNoGen(query, candidates) 16 16 } 17 17 18 - func removeRedundantNoGen(query *Query, candidates []nodeIndex) ([]nodeIndex, error) { 18 + func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, error) { 19 19 redundant := make([]bool, len(candidates)) 20 20 work := make([]nodeIndex, 0, len(candidates)-1) 21 21 filledIndex := make([]int, 0, len(candidates)-1) ··· 72 72 return out, nil 73 73 } 74 74 75 - func removeRedundantWithGen(query *Query, candidates []nodeIndex) []nodeIndex { 75 + func removeRedundantWithGen(query *query, candidates []nodeIndex) []nodeIndex { 76 76 sorted := append([]nodeIndex(nil), candidates...) 77 77 slices.SortFunc(sorted, compareByGeneration(query)) 78 78