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: Reorganize

Runxi Yu df73a4c6 21e1e151

+484 -427
+1
commitquery/ancestor.go commitquery/query_is_ancestor.go
··· 20 20 return query.isAncestor(ancestorIdx, descendantIdx) 21 21 } 22 22 23 + // isAncestor answers one ancestry query between two resolved internal nodes. 23 24 func (query *query) isAncestor(ancestor, descendant nodeIndex) (bool, error) { 24 25 if ancestor == descendant { 25 26 return true, nil
commitquery/ancestor_integration_test.go commitquery/queries_is_ancestor_integration_test.go
commitquery/ancestor_unit_test.go commitquery/queries_is_ancestor_unit_test.go
commitquery/commit.go commitquery/commit_data.go
+1
commitquery/errors.go
··· 2 2 3 3 import "errors" 4 4 5 + // errBadGenerationOrder reports an invalid priority-queue ordering. 5 6 var errBadGenerationOrder = errors.New("commitquery: priority queue violated generation ordering")
-107
commitquery/graph_pos.go
··· 1 - package commitquery 2 - 3 - import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 4 - 5 - // resolveGraphPos resolves one commit-graph position to one internal query node. 6 - func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { 7 - idx, ok := query.byGraphPos[pos] 8 - if ok { 9 - err := query.ensureLoaded(idx) 10 - if err != nil { 11 - return 0, err 12 - } 13 - 14 - return idx, nil 15 - } 16 - 17 - commit, err := query.graph.CommitAt(pos) 18 - if err != nil { 19 - return 0, err 20 - } 21 - 22 - idx, ok = query.byOID[commit.OID] 23 - if !ok { 24 - idx = query.newNode(commit.OID) 25 - query.byOID[commit.OID] = idx 26 - } 27 - 28 - query.byGraphPos[pos] = idx 29 - query.nodes[idx].graphPos = pos 30 - query.nodes[idx].hasGraphPos = true 31 - 32 - err = query.loadCommitAtGraphPos(idx, pos) 33 - if err != nil { 34 - delete(query.byGraphPos, pos) 35 - 36 - return 0, err 37 - } 38 - 39 - return idx, nil 40 - } 41 - 42 - // loadByGraphPos populates one node from a commit-graph position. 43 - func (query *query) loadByGraphPos(idx nodeIndex) error { 44 - pos := query.nodes[idx].graphPos 45 - 46 - return query.loadCommitAtGraphPos(idx, pos) 47 - } 48 - 49 - func (query *query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error { 50 - commit, err := query.graph.CommitAt(pos) 51 - if err != nil { 52 - return err 53 - } 54 - 55 - parents := make([]parentRef, 0, 2+len(commit.ExtraParents)) 56 - 57 - if commit.Parent1.Valid { 58 - parentOID, err := query.graph.OIDAt(commit.Parent1.Pos) 59 - if err != nil { 60 - return err 61 - } 62 - 63 - parents = append(parents, parentRef{ 64 - ID: parentOID, 65 - GraphPos: commit.Parent1.Pos, 66 - HasGraphPos: true, 67 - }) 68 - } 69 - 70 - if commit.Parent2.Valid { 71 - parentOID, err := query.graph.OIDAt(commit.Parent2.Pos) 72 - if err != nil { 73 - return err 74 - } 75 - 76 - parents = append(parents, parentRef{ 77 - ID: parentOID, 78 - GraphPos: commit.Parent2.Pos, 79 - HasGraphPos: true, 80 - }) 81 - } 82 - 83 - for _, parentPos := range commit.ExtraParents { 84 - parentOID, err := query.graph.OIDAt(parentPos) 85 - if err != nil { 86 - return err 87 - } 88 - 89 - parents = append(parents, parentRef{ 90 - ID: parentOID, 91 - GraphPos: parentPos, 92 - HasGraphPos: true, 93 - }) 94 - } 95 - 96 - data := commitData{ 97 - ID: commit.OID, 98 - Parents: parents, 99 - CommitTime: commit.CommitTimeUnix, 100 - Generation: commit.GenerationV2, 101 - HasGeneration: commit.GenerationV2 != 0, 102 - GraphPos: pos, 103 - HasGraphPos: true, 104 - } 105 - 106 - return query.populateNode(idx, data) 107 - }
-13
commitquery/load.go commitquery/query_load_by_oid.go
··· 10 10 objecttype "codeberg.org/lindenii/furgit/object/type" 11 11 ) 12 12 13 - // ensureLoaded completes one node's metadata load if it has not been loaded yet. 14 - func (query *query) ensureLoaded(idx nodeIndex) error { 15 - if query.nodes[idx].loaded { 16 - return nil 17 - } 18 - 19 - if query.nodes[idx].hasGraphPos { 20 - return query.loadByGraphPos(idx) 21 - } 22 - 23 - return query.loadByOID(idx) 24 - } 25 - 26 13 // loadByOID populates one node from an object ID. 27 14 func (query *query) loadByOID(idx nodeIndex) error { 28 15 id := query.nodes[idx].id
+17
commitquery/mark_bits.go
··· 1 + package commitquery 2 + 3 + // markBits stores one set of traversal marks on one node. 4 + type markBits uint8 5 + 6 + // markLeft, markRight, markStale, and markResult track traversal state. 7 + const ( 8 + markLeft markBits = 1 << iota 9 + markRight 10 + markStale 11 + markResult 12 + ) 13 + 14 + // allMarks is the union of all defined mark bits. 15 + const ( 16 + allMarks = markLeft | markRight | markStale | markResult 17 + )
-102
commitquery/marks.go
··· 1 - package commitquery 2 - 3 - // Marks returns the mark bits of one internal node. 4 - func (query *query) marks(idx nodeIndex) markBits { 5 - return query.nodes[idx].marks 6 - } 7 - 8 - // HasAnyMarks reports whether one internal node has any requested bit. 9 - func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool { 10 - return query.nodes[idx].marks&bits != 0 11 - } 12 - 13 - // HasAllMarks reports whether one internal node already has all requested bits. 14 - func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool { 15 - return query.nodes[idx].marks&bits == bits 16 - } 17 - 18 - // SetMarks ORs one set of mark bits into one internal node. 19 - func (query *query) setMarks(idx nodeIndex, bits markBits) { 20 - newBits := bits &^ query.nodes[idx].marks 21 - if newBits == 0 { 22 - return 23 - } 24 - 25 - query.trackTouched(idx) 26 - query.nodes[idx].marks |= bits 27 - } 28 - 29 - // ClearMarks removes one set of mark bits from one internal node. 30 - func (query *query) clearMarks(idx nodeIndex, bits markBits) { 31 - if query.nodes[idx].marks&bits == 0 { 32 - return 33 - } 34 - 35 - query.trackTouched(idx) 36 - query.nodes[idx].marks &^= bits 37 - } 38 - 39 - // BeginMarkPhase starts one tracked mark-mutation phase. 40 - func (query *query) beginMarkPhase() { 41 - for _, idx := range query.touched { 42 - query.nodes[idx].marks = 0 43 - } 44 - 45 - query.markPhase++ 46 - if query.markPhase == 0 { 47 - query.markPhase++ 48 - for i := range query.nodes { 49 - query.nodes[i].touchedPhase = 0 50 - } 51 - } 52 - 53 - query.touched = query.touched[:0] 54 - } 55 - 56 - // ClearTouchedMarks clears the provided bits from all nodes touched in the 57 - // current mark phase. 58 - func (query *query) clearTouchedMarks(bits markBits) { 59 - for _, idx := range query.touched { 60 - query.nodes[idx].marks &^= bits 61 - } 62 - } 63 - 64 - func (query *query) trackTouched(idx nodeIndex) { 65 - if query.nodes[idx].touchedPhase == query.markPhase { 66 - return 67 - } 68 - 69 - query.nodes[idx].touchedPhase = query.markPhase 70 - query.touched = append(query.touched, idx) 71 - } 72 - 73 - func (query *query) collectMarkedResults() []nodeIndex { 74 - out := make([]nodeIndex, 0, 4) 75 - 76 - for _, idx := range query.touched { 77 - if !query.hasAnyMarks(idx, markResult) { 78 - continue 79 - } 80 - 81 - if query.hasAnyMarks(idx, markStale) { 82 - continue 83 - } 84 - 85 - out = append(out, idx) 86 - } 87 - 88 - return out 89 - } 90 - 91 - type markBits uint8 92 - 93 - const ( 94 - markLeft markBits = 1 << iota 95 - markRight 96 - markStale 97 - markResult 98 - ) 99 - 100 - const ( 101 - allMarks = markLeft | markRight | markStale | markResult 102 - )
-89
commitquery/merge_bases.go
··· 1 - package commitquery 2 - 3 - import ( 4 - "slices" 5 - 6 - objectid "codeberg.org/lindenii/furgit/object/id" 7 - ) 8 - 9 - // MergeBases reports all merge bases in Git's merge-base --all order. 10 - // 11 - // Both inputs are peeled through annotated tags before commit traversal. 12 - func (query *query) MergeBases(left, right objectid.ObjectID) ([]objectid.ObjectID, error) { 13 - leftIdx, err := query.resolveCommitish(left) 14 - if err != nil { 15 - return nil, err 16 - } 17 - 18 - rightIdx, err := query.resolveCommitish(right) 19 - if err != nil { 20 - return nil, err 21 - } 22 - 23 - candidates, err := query.mergeBases(leftIdx, rightIdx) 24 - if err != nil { 25 - return nil, err 26 - } 27 - 28 - slices.SortFunc(candidates, func(left, right nodeIndex) int { 29 - switch { 30 - case query.commitTime(left) > query.commitTime(right): 31 - return -1 32 - case query.commitTime(left) < query.commitTime(right): 33 - return 1 34 - default: 35 - return objectid.Compare(query.id(left), query.id(right)) 36 - } 37 - }) 38 - 39 - out := make([]objectid.ObjectID, 0, len(candidates)) 40 - for _, idx := range candidates { 41 - out = append(out, query.id(idx)) 42 - } 43 - 44 - return out, nil 45 - } 46 - 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) { 49 - bases, err := query.MergeBases(left, right) 50 - if err != nil { 51 - return objectid.ObjectID{}, false, err 52 - } 53 - 54 - if len(bases) == 0 { 55 - return objectid.ObjectID{}, false, nil 56 - } 57 - 58 - return bases[0], true, nil 59 - } 60 - 61 - func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { 62 - if left == right { 63 - return []nodeIndex{left}, nil 64 - } 65 - 66 - err := query.paintDownToCommon(left, []nodeIndex{right}, 0) 67 - if err != nil { 68 - return nil, err 69 - } 70 - 71 - candidates := query.collectMarkedResults() 72 - 73 - if len(candidates) <= 1 { 74 - slices.SortFunc(candidates, query.compare) 75 - 76 - return candidates, nil 77 - } 78 - 79 - query.clearTouchedMarks(allMarks) 80 - 81 - reduced, err := removeRedundant(query, candidates) 82 - if err != nil { 83 - return nil, err 84 - } 85 - 86 - slices.SortFunc(reduced, query.compare) 87 - 88 - return reduced, nil 89 - }
commitquery/mergebase_integration_test.go commitquery/queries_merge_bases_integration_test.go
commitquery/mergebase_unit_test.go commitquery/queries_merge_bases_unit_test.go
+1
commitquery/node_commit_time.go
··· 1 1 package commitquery 2 2 3 + // commitTime returns one node's commit time. 3 4 func (query *query) commitTime(idx nodeIndex) int64 { 4 5 return query.nodes[idx].commitTime 5 6 }
+1 -1
commitquery/node_compare.go
··· 2 2 3 3 import objectid "codeberg.org/lindenii/furgit/object/id" 4 4 5 - // Compare compares two internal nodes using merge-base queue ordering. 5 + // compare orders two internal nodes using merge-base queue ordering. 6 6 func (query *query) compare(left, right nodeIndex) int { 7 7 leftGeneration := query.effectiveGeneration(left) 8 8 rightGeneration := query.effectiveGeneration(right)
+3 -1
commitquery/node_generation.go
··· 6 6 objectid "codeberg.org/lindenii/furgit/object/id" 7 7 ) 8 8 9 - // EffectiveGeneration returns one node's generation value. 9 + // effectiveGeneration returns one node's generation value. 10 10 func (query *query) effectiveGeneration(idx nodeIndex) uint64 { 11 11 if !query.nodes[idx].hasGeneration { 12 12 return generationInfinity ··· 15 15 return query.nodes[idx].generation 16 16 } 17 17 18 + // generationInfinity sorts nodes without a known generation last. 18 19 const ( 19 20 generationInfinity = uint64(math.MaxUint64) 20 21 ) 21 22 23 + // compareByGeneration builds one comparator ordered by generation first. 22 24 func (query *query) compareByGeneration() func(nodeIndex, nodeIndex) int { 23 25 return func(left, right nodeIndex) int { 24 26 leftGeneration := query.effectiveGeneration(left)
+1
commitquery/node_id.go
··· 2 2 3 3 import objectid "codeberg.org/lindenii/furgit/object/id" 4 4 5 + // id returns one node's object ID. 5 6 func (query *query) id(idx nodeIndex) objectid.ObjectID { 6 7 return query.nodes[idx].id 7 8 }
+1
commitquery/node_paint_down_to_common.go commitquery/query_paint_down_to_common.go
··· 2 2 3 3 import "codeberg.org/lindenii/furgit/internal/priorityqueue" 4 4 5 + // paintDownToCommon propagates left and right marks downward until common nodes. 5 6 func (query *query) paintDownToCommon(left nodeIndex, rights []nodeIndex, minGeneration uint64) error { 6 7 query.beginMarkPhase() 7 8
-27
commitquery/node_parent.go
··· 1 - package commitquery 2 - 3 - import ( 4 - commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 - objectid "codeberg.org/lindenii/furgit/object/id" 6 - ) 7 - 8 - // Parents returns resolved parent node indices for one internal node. 9 - func (query *query) parents(idx nodeIndex) []nodeIndex { 10 - return query.nodes[idx].parents 11 - } 12 - 13 - // parentRef references one commit parent. 14 - type parentRef struct { 15 - ID objectid.ObjectID 16 - GraphPos commitgraphread.Position 17 - HasGraphPos bool 18 - } 19 - 20 - // resolveParent resolves one parent descriptor to one internal node. 21 - func (query *query) resolveParent(parent parentRef) (nodeIndex, error) { 22 - if parent.HasGraphPos { 23 - return query.resolveGraphPos(parent.GraphPos) 24 - } 25 - 26 - return query.resolveOID(parent.ID) 27 - }
+6
commitquery/node_parents.go
··· 1 + package commitquery 2 + 3 + // parents returns resolved parent node indices for one internal node. 4 + func (query *query) parents(idx nodeIndex) []nodeIndex { 5 + return query.nodes[idx].parents 6 + }
+13
commitquery/parent_ref.go
··· 1 + package commitquery 2 + 3 + import ( 4 + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 + objectid "codeberg.org/lindenii/furgit/object/id" 6 + ) 7 + 8 + // parentRef references one commit parent. 9 + type parentRef struct { 10 + ID objectid.ObjectID 11 + GraphPos commitgraphread.Position 12 + HasGraphPos bool 13 + }
+1
commitquery/queries_acquire.go
··· 1 1 package commitquery 2 2 3 + // acquire removes one worker from the idle pool or allocates one new worker. 3 4 func (queries *Queries) acquire() *query { 4 5 queries.mu.Lock() 5 6 defer queries.mu.Unlock()
commitquery/queries_ancestor.go commitquery/queries_is_ancestor.go
+11
commitquery/queries_merge_base.go
··· 1 + package commitquery 2 + 3 + import objectid "codeberg.org/lindenii/furgit/object/id" 4 + 5 + // MergeBase reports one merge base between left and right, if any. 6 + func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { 7 + query := queries.acquire() 8 + defer queries.release(query) 9 + 10 + return query.MergeBase(left, right) 11 + }
-8
commitquery/queries_mergebase.go commitquery/queries_merge_bases.go
··· 11 11 12 12 return query.MergeBases(left, right) 13 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 - }
+1
commitquery/queries_release.go
··· 1 1 package commitquery 2 2 3 + // release resets one worker and returns it to the idle pool if there is room. 3 4 func (queries *Queries) release(q *query) { 4 5 q.resetForReuse() 5 6
+23
commitquery/query.go
··· 1 + package commitquery 2 + 3 + import ( 4 + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 + objectid "codeberg.org/lindenii/furgit/object/id" 6 + objectstore "codeberg.org/lindenii/furgit/object/store" 7 + ) 8 + 9 + // query stores one mutable reusable worker and its cached node arena. 10 + // 11 + // Labels: MT-Unsafe. 12 + type query struct { 13 + store objectstore.ReadingStore 14 + graph *commitgraphread.Reader 15 + 16 + nodes []node 17 + 18 + byOID map[objectid.ObjectID]nodeIndex 19 + byGraphPos map[commitgraphread.Position]nodeIndex 20 + 21 + markPhase uint32 22 + touched []nodeIndex 23 + }
+20
commitquery/query_collect_marked_results.go
··· 1 + package commitquery 2 + 3 + // collectMarkedResults returns touched nodes marked as non-stale results. 4 + func (query *query) collectMarkedResults() []nodeIndex { 5 + out := make([]nodeIndex, 0, 4) 6 + 7 + for _, idx := range query.touched { 8 + if !query.hasAnyMarks(idx, markResult) { 9 + continue 10 + } 11 + 12 + if query.hasAnyMarks(idx, markStale) { 13 + continue 14 + } 15 + 16 + out = append(out, idx) 17 + } 18 + 19 + return out 20 + }
+14
commitquery/query_ensure_loaded.go
··· 1 + package commitquery 2 + 3 + // ensureLoaded completes one node's metadata load if it is not loaded yet. 4 + func (query *query) ensureLoaded(idx nodeIndex) error { 5 + if query.nodes[idx].loaded { 6 + return nil 7 + } 8 + 9 + if query.nodes[idx].hasGraphPos { 10 + return query.loadByGraphPos(idx) 11 + } 12 + 13 + return query.loadByOID(idx) 14 + }
+11
commitquery/query_has_marks.go
··· 1 + package commitquery 2 + 3 + // hasAnyMarks reports whether one internal node has any requested bit. 4 + func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool { 5 + return query.nodes[idx].marks&bits != 0 6 + } 7 + 8 + // hasAllMarks reports whether one internal node already has all requested bits. 9 + func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool { 10 + return query.nodes[idx].marks&bits == bits 11 + }
+8
commitquery/query_load_by_graph_pos.go
··· 1 + package commitquery 2 + 3 + // loadByGraphPos populates one node from a commit-graph position. 4 + func (query *query) loadByGraphPos(idx nodeIndex) error { 5 + pos := query.nodes[idx].graphPos 6 + 7 + return query.loadCommitAtGraphPos(idx, pos) 8 + }
+64
commitquery/query_load_commit_at_graph_pos.go
··· 1 + package commitquery 2 + 3 + import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 4 + 5 + // loadCommitAtGraphPos populates one node from one commit-graph record. 6 + func (query *query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error { 7 + commit, err := query.graph.CommitAt(pos) 8 + if err != nil { 9 + return err 10 + } 11 + 12 + parents := make([]parentRef, 0, 2+len(commit.ExtraParents)) 13 + 14 + if commit.Parent1.Valid { 15 + parentOID, err := query.graph.OIDAt(commit.Parent1.Pos) 16 + if err != nil { 17 + return err 18 + } 19 + 20 + parents = append(parents, parentRef{ 21 + ID: parentOID, 22 + GraphPos: commit.Parent1.Pos, 23 + HasGraphPos: true, 24 + }) 25 + } 26 + 27 + if commit.Parent2.Valid { 28 + parentOID, err := query.graph.OIDAt(commit.Parent2.Pos) 29 + if err != nil { 30 + return err 31 + } 32 + 33 + parents = append(parents, parentRef{ 34 + ID: parentOID, 35 + GraphPos: commit.Parent2.Pos, 36 + HasGraphPos: true, 37 + }) 38 + } 39 + 40 + for _, parentPos := range commit.ExtraParents { 41 + parentOID, err := query.graph.OIDAt(parentPos) 42 + if err != nil { 43 + return err 44 + } 45 + 46 + parents = append(parents, parentRef{ 47 + ID: parentOID, 48 + GraphPos: parentPos, 49 + HasGraphPos: true, 50 + }) 51 + } 52 + 53 + data := commitData{ 54 + ID: commit.OID, 55 + Parents: parents, 56 + CommitTime: commit.CommitTimeUnix, 57 + Generation: commit.GenerationV2, 58 + HasGeneration: commit.GenerationV2 != 0, 59 + GraphPos: pos, 60 + HasGraphPos: true, 61 + } 62 + 63 + return query.populateNode(idx, data) 64 + }
+36
commitquery/query_mark_phase.go
··· 1 + package commitquery 2 + 3 + // beginMarkPhase starts one tracked mark-mutation phase. 4 + func (query *query) beginMarkPhase() { 5 + for _, idx := range query.touched { 6 + query.nodes[idx].marks = 0 7 + } 8 + 9 + query.markPhase++ 10 + if query.markPhase == 0 { 11 + query.markPhase++ 12 + for i := range query.nodes { 13 + query.nodes[i].touchedPhase = 0 14 + } 15 + } 16 + 17 + query.touched = query.touched[:0] 18 + } 19 + 20 + // clearTouchedMarks clears the provided bits from all nodes touched in the 21 + // current mark phase. 22 + func (query *query) clearTouchedMarks(bits markBits) { 23 + for _, idx := range query.touched { 24 + query.nodes[idx].marks &^= bits 25 + } 26 + } 27 + 28 + // trackTouched records one node in the current mark phase. 29 + func (query *query) trackTouched(idx nodeIndex) { 30 + if query.nodes[idx].touchedPhase == query.markPhase { 31 + return 32 + } 33 + 34 + query.nodes[idx].touchedPhase = query.markPhase 35 + query.touched = append(query.touched, idx) 36 + }
+6
commitquery/query_marks_get.go
··· 1 + package commitquery 2 + 3 + // marks returns the mark bits of one internal node. 4 + func (query *query) marks(idx nodeIndex) markBits { 5 + return query.nodes[idx].marks 6 + }
+17
commitquery/query_merge_base.go
··· 1 + package commitquery 2 + 3 + import objectid "codeberg.org/lindenii/furgit/object/id" 4 + 5 + // MergeBase reports one merge base between left and right, if any. 6 + func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { 7 + bases, err := query.MergeBases(left, right) 8 + if err != nil { 9 + return objectid.ObjectID{}, false, err 10 + } 11 + 12 + if len(bases) == 0 { 13 + return objectid.ObjectID{}, false, nil 14 + } 15 + 16 + return bases[0], true, nil 17 + }
+45
commitquery/query_merge_bases.go
··· 1 + package commitquery 2 + 3 + import ( 4 + "slices" 5 + 6 + objectid "codeberg.org/lindenii/furgit/object/id" 7 + ) 8 + 9 + // MergeBases reports all merge bases in Git's merge-base --all order. 10 + // 11 + // Both inputs are peeled through annotated tags before commit traversal. 12 + func (query *query) MergeBases(left, right objectid.ObjectID) ([]objectid.ObjectID, error) { 13 + leftIdx, err := query.resolveCommitish(left) 14 + if err != nil { 15 + return nil, err 16 + } 17 + 18 + rightIdx, err := query.resolveCommitish(right) 19 + if err != nil { 20 + return nil, err 21 + } 22 + 23 + candidates, err := query.mergeBases(leftIdx, rightIdx) 24 + if err != nil { 25 + return nil, err 26 + } 27 + 28 + slices.SortFunc(candidates, func(left, right nodeIndex) int { 29 + switch { 30 + case query.commitTime(left) > query.commitTime(right): 31 + return -1 32 + case query.commitTime(left) < query.commitTime(right): 33 + return 1 34 + default: 35 + return objectid.Compare(query.id(left), query.id(right)) 36 + } 37 + }) 38 + 39 + out := make([]objectid.ObjectID, 0, len(candidates)) 40 + for _, idx := range candidates { 41 + out = append(out, query.id(idx)) 42 + } 43 + 44 + return out, nil 45 + }
+34
commitquery/query_merge_bases_internal.go
··· 1 + package commitquery 2 + 3 + import "slices" 4 + 5 + // mergeBases returns internal merge-base candidates for two resolved nodes. 6 + func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { 7 + if left == right { 8 + return []nodeIndex{left}, nil 9 + } 10 + 11 + err := query.paintDownToCommon(left, []nodeIndex{right}, 0) 12 + if err != nil { 13 + return nil, err 14 + } 15 + 16 + candidates := query.collectMarkedResults() 17 + 18 + if len(candidates) <= 1 { 19 + slices.SortFunc(candidates, query.compare) 20 + 21 + return candidates, nil 22 + } 23 + 24 + query.clearTouchedMarks(allMarks) 25 + 26 + reduced, err := removeRedundant(query, candidates) 27 + if err != nil { 28 + return nil, err 29 + } 30 + 31 + slices.SortFunc(reduced, query.compare) 32 + 33 + return reduced, nil 34 + }
+19
commitquery/query_new.go
··· 1 + package commitquery 2 + 3 + import ( 4 + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 + objectid "codeberg.org/lindenii/furgit/object/id" 6 + objectstore "codeberg.org/lindenii/furgit/object/store" 7 + ) 8 + 9 + // newQuery builds one empty mutable worker over one object store and graph. 10 + // 11 + // Labels: Deps-Borrowed, Life-Parent. 12 + func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *query { 13 + return &query{ 14 + store: store, 15 + graph: graph, 16 + byOID: make(map[objectid.ObjectID]nodeIndex), 17 + byGraphPos: make(map[commitgraphread.Position]nodeIndex), 18 + } 19 + }
+10
commitquery/query_reset.go
··· 1 + package commitquery 2 + 3 + // resetForReuse clears transient state before one worker returns to the pool. 4 + func (query *query) resetForReuse() { 5 + for _, idx := range query.touched { 6 + query.nodes[idx].marks = 0 7 + } 8 + 9 + query.touched = query.touched[:0] 10 + }
+16
commitquery/query_resolve_commitish.go
··· 1 + package commitquery 2 + 3 + import ( 4 + "codeberg.org/lindenii/furgit/internal/peel" 5 + objectid "codeberg.org/lindenii/furgit/object/id" 6 + ) 7 + 8 + // resolveCommitish peels one commit-ish object ID and resolves the commit. 9 + func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { 10 + commitID, err := peel.ToCommit(query.store, id) 11 + if err != nil { 12 + return 0, err 13 + } 14 + 15 + return query.resolveOID(commitID) 16 + }
+40
commitquery/query_resolve_graph_pos.go
··· 1 + package commitquery 2 + 3 + import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 4 + 5 + // resolveGraphPos resolves one commit-graph position to one internal query node. 6 + func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { 7 + idx, ok := query.byGraphPos[pos] 8 + if ok { 9 + err := query.ensureLoaded(idx) 10 + if err != nil { 11 + return 0, err 12 + } 13 + 14 + return idx, nil 15 + } 16 + 17 + commit, err := query.graph.CommitAt(pos) 18 + if err != nil { 19 + return 0, err 20 + } 21 + 22 + idx, ok = query.byOID[commit.OID] 23 + if !ok { 24 + idx = query.newNode(commit.OID) 25 + query.byOID[commit.OID] = idx 26 + } 27 + 28 + query.byGraphPos[pos] = idx 29 + query.nodes[idx].graphPos = pos 30 + query.nodes[idx].hasGraphPos = true 31 + 32 + err = query.loadCommitAtGraphPos(idx, pos) 33 + if err != nil { 34 + delete(query.byGraphPos, pos) 35 + 36 + return 0, err 37 + } 38 + 39 + return idx, nil 40 + }
+28
commitquery/query_resolve_oid.go
··· 1 + package commitquery 2 + 3 + import objectid "codeberg.org/lindenii/furgit/object/id" 4 + 5 + // resolveOID resolves one commit object ID to one internal query node. 6 + func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { 7 + idx, ok := query.byOID[id] 8 + if ok { 9 + err := query.ensureLoaded(idx) 10 + if err != nil { 11 + return 0, err 12 + } 13 + 14 + return idx, nil 15 + } 16 + 17 + idx = query.newNode(id) 18 + query.byOID[id] = idx 19 + 20 + err := query.loadByOID(idx) 21 + if err != nil { 22 + delete(query.byOID, id) 23 + 24 + return 0, err 25 + } 26 + 27 + return idx, nil 28 + }
+10
commitquery/query_resolve_parent.go
··· 1 + package commitquery 2 + 3 + // resolveParent resolves one parent descriptor to one internal node. 4 + func (query *query) resolveParent(parent parentRef) (nodeIndex, error) { 5 + if parent.HasGraphPos { 6 + return query.resolveGraphPos(parent.GraphPos) 7 + } 8 + 9 + return query.resolveOID(parent.ID) 10 + }
+22
commitquery/query_set_clear_marks.go
··· 1 + package commitquery 2 + 3 + // setMarks ORs one set of mark bits into one internal node. 4 + func (query *query) setMarks(idx nodeIndex, bits markBits) { 5 + newBits := bits &^ query.nodes[idx].marks 6 + if newBits == 0 { 7 + return 8 + } 9 + 10 + query.trackTouched(idx) 11 + query.nodes[idx].marks |= bits 12 + } 13 + 14 + // clearMarks removes one set of mark bits from one internal node. 15 + func (query *query) clearMarks(idx nodeIndex, bits markBits) { 16 + if query.nodes[idx].marks&bits == 0 { 17 + return 18 + } 19 + 20 + query.trackTouched(idx) 21 + query.nodes[idx].marks &^= bits 22 + }
+3 -3
commitquery/reduce.go commitquery/query_reduce.go
··· 1 1 package commitquery 2 2 3 - import ( 4 - "slices" 5 - ) 3 + import "slices" 6 4 7 5 // removeRedundant removes redundant merge-base candidates. 8 6 func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error) { ··· 15 13 return removeRedundantNoGen(query, candidates) 16 14 } 17 15 16 + // removeRedundantNoGen removes redundant candidates without generation data. 18 17 func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, error) { 19 18 redundant := make([]bool, len(candidates)) 20 19 work := make([]nodeIndex, 0, len(candidates)-1) ··· 72 71 return out, nil 73 72 } 74 73 74 + // removeRedundantWithGen removes redundant candidates using generation data. 75 75 func removeRedundantWithGen(query *query, candidates []nodeIndex) []nodeIndex { 76 76 sorted := append([]nodeIndex(nil), candidates...) 77 77 slices.SortFunc(sorted, query.compareByGeneration())
-37
commitquery/reset.go
··· 1 - package commitquery 2 - 3 - import ( 4 - commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 - objectid "codeberg.org/lindenii/furgit/object/id" 6 - objectstore "codeberg.org/lindenii/furgit/object/store" 7 - ) 8 - 9 - type query struct { 10 - store objectstore.ReadingStore 11 - graph *commitgraphread.Reader 12 - 13 - nodes []node 14 - 15 - byOID map[objectid.ObjectID]nodeIndex 16 - byGraphPos map[commitgraphread.Position]nodeIndex 17 - 18 - markPhase uint32 19 - touched []nodeIndex 20 - } 21 - 22 - func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *query { 23 - return &query{ 24 - store: store, 25 - graph: graph, 26 - byOID: make(map[objectid.ObjectID]nodeIndex), 27 - byGraphPos: make(map[commitgraphread.Position]nodeIndex), 28 - } 29 - } 30 - 31 - func (query *query) resetForReuse() { 32 - for _, idx := range query.touched { 33 - query.nodes[idx].marks = 0 34 - } 35 - 36 - query.touched = query.touched[:0] 37 - }
-39
commitquery/resolve.go
··· 1 - package commitquery 2 - 3 - import ( 4 - "codeberg.org/lindenii/furgit/internal/peel" 5 - objectid "codeberg.org/lindenii/furgit/object/id" 6 - ) 7 - 8 - func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { 9 - idx, ok := query.byOID[id] 10 - if ok { 11 - err := query.ensureLoaded(idx) 12 - if err != nil { 13 - return 0, err 14 - } 15 - 16 - return idx, nil 17 - } 18 - 19 - idx = query.newNode(id) 20 - query.byOID[id] = idx 21 - 22 - err := query.loadByOID(idx) 23 - if err != nil { 24 - delete(query.byOID, id) 25 - 26 - return 0, err 27 - } 28 - 29 - return idx, nil 30 - } 31 - 32 - func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { 33 - commitID, err := peel.ToCommit(query.store, id) 34 - if err != nil { 35 - return 0, err 36 - } 37 - 38 - return query.resolveOID(commitID) 39 - }