diff options
| author | 2026-03-29 14:42:13 +0000 | |
|---|---|---|
| committer | 2026-03-29 14:47:04 +0000 | |
| commit | df73a4c6f1b58075316ba7449fbfb127b9fbb79d (patch) | |
| tree | 62fee259ec037410b06419ee3ac9c2c189c35ab3 | |
| parent | internal/priorityqueue: Update docs (diff) | |
| signature | No signature | |
commitquery: Reorganize
42 files changed, 334 insertions, 277 deletions
diff --git a/commitquery/commit.go b/commitquery/commit_data.go index dff6a91c..dff6a91c 100644 --- a/commitquery/commit.go +++ b/commitquery/commit_data.go diff --git a/commitquery/errors.go b/commitquery/errors.go index e99011d0..0006c86b 100644 --- a/commitquery/errors.go +++ b/commitquery/errors.go @@ -2,4 +2,5 @@ package commitquery import "errors" +// errBadGenerationOrder reports an invalid priority-queue ordering. var errBadGenerationOrder = errors.New("commitquery: priority queue violated generation ordering") diff --git a/commitquery/mark_bits.go b/commitquery/mark_bits.go new file mode 100644 index 00000000..b10c833b --- /dev/null +++ b/commitquery/mark_bits.go @@ -0,0 +1,17 @@ +package commitquery + +// markBits stores one set of traversal marks on one node. +type markBits uint8 + +// markLeft, markRight, markStale, and markResult track traversal state. +const ( + markLeft markBits = 1 << iota + markRight + markStale + markResult +) + +// allMarks is the union of all defined mark bits. +const ( + allMarks = markLeft | markRight | markStale | markResult +) diff --git a/commitquery/marks.go b/commitquery/marks.go deleted file mode 100644 index 2d0b013f..00000000 --- a/commitquery/marks.go +++ /dev/null @@ -1,102 +0,0 @@ -package commitquery - -// Marks returns the mark bits of one internal node. -func (query *query) marks(idx nodeIndex) markBits { - return query.nodes[idx].marks -} - -// HasAnyMarks reports whether one internal node has any requested bit. -func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool { - return query.nodes[idx].marks&bits != 0 -} - -// HasAllMarks reports whether one internal node already has all requested bits. -func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool { - return query.nodes[idx].marks&bits == bits -} - -// SetMarks ORs one set of mark bits into one internal node. -func (query *query) setMarks(idx nodeIndex, bits markBits) { - newBits := bits &^ query.nodes[idx].marks - if newBits == 0 { - return - } - - query.trackTouched(idx) - query.nodes[idx].marks |= bits -} - -// ClearMarks removes one set of mark bits from one internal node. -func (query *query) clearMarks(idx nodeIndex, bits markBits) { - if query.nodes[idx].marks&bits == 0 { - return - } - - query.trackTouched(idx) - query.nodes[idx].marks &^= bits -} - -// BeginMarkPhase starts one tracked mark-mutation phase. -func (query *query) beginMarkPhase() { - for _, idx := range query.touched { - query.nodes[idx].marks = 0 - } - - query.markPhase++ - if query.markPhase == 0 { - query.markPhase++ - for i := range query.nodes { - query.nodes[i].touchedPhase = 0 - } - } - - query.touched = query.touched[:0] -} - -// ClearTouchedMarks clears the provided bits from all nodes touched in the -// current mark phase. -func (query *query) clearTouchedMarks(bits markBits) { - for _, idx := range query.touched { - query.nodes[idx].marks &^= bits - } -} - -func (query *query) trackTouched(idx nodeIndex) { - if query.nodes[idx].touchedPhase == query.markPhase { - return - } - - query.nodes[idx].touchedPhase = query.markPhase - query.touched = append(query.touched, idx) -} - -func (query *query) collectMarkedResults() []nodeIndex { - out := make([]nodeIndex, 0, 4) - - for _, idx := range query.touched { - if !query.hasAnyMarks(idx, markResult) { - continue - } - - if query.hasAnyMarks(idx, markStale) { - continue - } - - out = append(out, idx) - } - - return out -} - -type markBits uint8 - -const ( - markLeft markBits = 1 << iota - markRight - markStale - markResult -) - -const ( - allMarks = markLeft | markRight | markStale | markResult -) diff --git a/commitquery/node_commit_time.go b/commitquery/node_commit_time.go index 3c42673d..07c1f4e8 100644 --- a/commitquery/node_commit_time.go +++ b/commitquery/node_commit_time.go @@ -1,5 +1,6 @@ package commitquery +// commitTime returns one node's commit time. func (query *query) commitTime(idx nodeIndex) int64 { return query.nodes[idx].commitTime } diff --git a/commitquery/node_compare.go b/commitquery/node_compare.go index 7ae984dc..cf072af2 100644 --- a/commitquery/node_compare.go +++ b/commitquery/node_compare.go @@ -2,7 +2,7 @@ package commitquery import objectid "codeberg.org/lindenii/furgit/object/id" -// Compare compares two internal nodes using merge-base queue ordering. +// compare orders two internal nodes using merge-base queue ordering. func (query *query) compare(left, right nodeIndex) int { leftGeneration := query.effectiveGeneration(left) rightGeneration := query.effectiveGeneration(right) diff --git a/commitquery/node_generation.go b/commitquery/node_generation.go index b04f3762..03283cf6 100644 --- a/commitquery/node_generation.go +++ b/commitquery/node_generation.go @@ -6,7 +6,7 @@ import ( objectid "codeberg.org/lindenii/furgit/object/id" ) -// EffectiveGeneration returns one node's generation value. +// effectiveGeneration returns one node's generation value. func (query *query) effectiveGeneration(idx nodeIndex) uint64 { if !query.nodes[idx].hasGeneration { return generationInfinity @@ -15,10 +15,12 @@ func (query *query) effectiveGeneration(idx nodeIndex) uint64 { return query.nodes[idx].generation } +// generationInfinity sorts nodes without a known generation last. const ( generationInfinity = uint64(math.MaxUint64) ) +// compareByGeneration builds one comparator ordered by generation first. func (query *query) compareByGeneration() func(nodeIndex, nodeIndex) int { return func(left, right nodeIndex) int { leftGeneration := query.effectiveGeneration(left) diff --git a/commitquery/node_id.go b/commitquery/node_id.go index c1d82f38..8ec0b126 100644 --- a/commitquery/node_id.go +++ b/commitquery/node_id.go @@ -2,6 +2,7 @@ package commitquery import objectid "codeberg.org/lindenii/furgit/object/id" +// id returns one node's object ID. func (query *query) id(idx nodeIndex) objectid.ObjectID { return query.nodes[idx].id } diff --git a/commitquery/node_parent.go b/commitquery/node_parent.go deleted file mode 100644 index 17224701..00000000 --- a/commitquery/node_parent.go +++ /dev/null @@ -1,27 +0,0 @@ -package commitquery - -import ( - commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" - objectid "codeberg.org/lindenii/furgit/object/id" -) - -// Parents returns resolved parent node indices for one internal node. -func (query *query) parents(idx nodeIndex) []nodeIndex { - return query.nodes[idx].parents -} - -// parentRef references one commit parent. -type parentRef struct { - ID objectid.ObjectID - GraphPos commitgraphread.Position - HasGraphPos bool -} - -// resolveParent resolves one parent descriptor to one internal node. -func (query *query) resolveParent(parent parentRef) (nodeIndex, error) { - if parent.HasGraphPos { - return query.resolveGraphPos(parent.GraphPos) - } - - return query.resolveOID(parent.ID) -} diff --git a/commitquery/node_parents.go b/commitquery/node_parents.go new file mode 100644 index 00000000..a98a774f --- /dev/null +++ b/commitquery/node_parents.go @@ -0,0 +1,6 @@ +package commitquery + +// parents returns resolved parent node indices for one internal node. +func (query *query) parents(idx nodeIndex) []nodeIndex { + return query.nodes[idx].parents +} diff --git a/commitquery/parent_ref.go b/commitquery/parent_ref.go new file mode 100644 index 00000000..08d224df --- /dev/null +++ b/commitquery/parent_ref.go @@ -0,0 +1,13 @@ +package commitquery + +import ( + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" + objectid "codeberg.org/lindenii/furgit/object/id" +) + +// parentRef references one commit parent. +type parentRef struct { + ID objectid.ObjectID + GraphPos commitgraphread.Position + HasGraphPos bool +} diff --git a/commitquery/queries_acquire.go b/commitquery/queries_acquire.go index ac7b765c..2925010c 100644 --- a/commitquery/queries_acquire.go +++ b/commitquery/queries_acquire.go @@ -1,5 +1,6 @@ package commitquery +// acquire removes one worker from the idle pool or allocates one new worker. func (queries *Queries) acquire() *query { queries.mu.Lock() defer queries.mu.Unlock() diff --git a/commitquery/queries_ancestor.go b/commitquery/queries_is_ancestor.go index e2c955c6..e2c955c6 100644 --- a/commitquery/queries_ancestor.go +++ b/commitquery/queries_is_ancestor.go diff --git a/commitquery/ancestor_integration_test.go b/commitquery/queries_is_ancestor_integration_test.go index 8db680e6..8db680e6 100644 --- a/commitquery/ancestor_integration_test.go +++ b/commitquery/queries_is_ancestor_integration_test.go diff --git a/commitquery/ancestor_unit_test.go b/commitquery/queries_is_ancestor_unit_test.go index 8cb147a6..8cb147a6 100644 --- a/commitquery/ancestor_unit_test.go +++ b/commitquery/queries_is_ancestor_unit_test.go diff --git a/commitquery/queries_merge_base.go b/commitquery/queries_merge_base.go new file mode 100644 index 00000000..28de7fe2 --- /dev/null +++ b/commitquery/queries_merge_base.go @@ -0,0 +1,11 @@ +package commitquery + +import objectid "codeberg.org/lindenii/furgit/object/id" + +// MergeBase reports one merge base between left and right, if any. +func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { + query := queries.acquire() + defer queries.release(query) + + return query.MergeBase(left, right) +} diff --git a/commitquery/queries_mergebase.go b/commitquery/queries_merge_bases.go index ff0aafb9..74c5054a 100644 --- a/commitquery/queries_mergebase.go +++ b/commitquery/queries_merge_bases.go @@ -11,11 +11,3 @@ func (queries *Queries) MergeBases(left, right objectid.ObjectID) ([]objectid.Ob return query.MergeBases(left, right) } - -// MergeBase reports one merge base between left and right, if any. -func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { - query := queries.acquire() - defer queries.release(query) - - return query.MergeBase(left, right) -} diff --git a/commitquery/mergebase_integration_test.go b/commitquery/queries_merge_bases_integration_test.go index f19468eb..f19468eb 100644 --- a/commitquery/mergebase_integration_test.go +++ b/commitquery/queries_merge_bases_integration_test.go diff --git a/commitquery/mergebase_unit_test.go b/commitquery/queries_merge_bases_unit_test.go index 4db4f548..4db4f548 100644 --- a/commitquery/mergebase_unit_test.go +++ b/commitquery/queries_merge_bases_unit_test.go diff --git a/commitquery/queries_release.go b/commitquery/queries_release.go index 791b2f03..5d0b2fde 100644 --- a/commitquery/queries_release.go +++ b/commitquery/queries_release.go @@ -1,5 +1,6 @@ package commitquery +// release resets one worker and returns it to the idle pool if there is room. func (queries *Queries) release(q *query) { q.resetForReuse() diff --git a/commitquery/query.go b/commitquery/query.go new file mode 100644 index 00000000..5f184a5f --- /dev/null +++ b/commitquery/query.go @@ -0,0 +1,23 @@ +package commitquery + +import ( + commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" + objectid "codeberg.org/lindenii/furgit/object/id" + objectstore "codeberg.org/lindenii/furgit/object/store" +) + +// query stores one mutable reusable worker and its cached node arena. +// +// Labels: MT-Unsafe. +type query struct { + store objectstore.ReadingStore + graph *commitgraphread.Reader + + nodes []node + + byOID map[objectid.ObjectID]nodeIndex + byGraphPos map[commitgraphread.Position]nodeIndex + + markPhase uint32 + touched []nodeIndex +} diff --git a/commitquery/query_collect_marked_results.go b/commitquery/query_collect_marked_results.go new file mode 100644 index 00000000..7139fb9b --- /dev/null +++ b/commitquery/query_collect_marked_results.go @@ -0,0 +1,20 @@ +package commitquery + +// collectMarkedResults returns touched nodes marked as non-stale results. +func (query *query) collectMarkedResults() []nodeIndex { + out := make([]nodeIndex, 0, 4) + + for _, idx := range query.touched { + if !query.hasAnyMarks(idx, markResult) { + continue + } + + if query.hasAnyMarks(idx, markStale) { + continue + } + + out = append(out, idx) + } + + return out +} diff --git a/commitquery/query_ensure_loaded.go b/commitquery/query_ensure_loaded.go new file mode 100644 index 00000000..830e9b19 --- /dev/null +++ b/commitquery/query_ensure_loaded.go @@ -0,0 +1,14 @@ +package commitquery + +// ensureLoaded completes one node's metadata load if it is not loaded yet. +func (query *query) ensureLoaded(idx nodeIndex) error { + if query.nodes[idx].loaded { + return nil + } + + if query.nodes[idx].hasGraphPos { + return query.loadByGraphPos(idx) + } + + return query.loadByOID(idx) +} diff --git a/commitquery/query_has_marks.go b/commitquery/query_has_marks.go new file mode 100644 index 00000000..22f44bd4 --- /dev/null +++ b/commitquery/query_has_marks.go @@ -0,0 +1,11 @@ +package commitquery + +// hasAnyMarks reports whether one internal node has any requested bit. +func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool { + return query.nodes[idx].marks&bits != 0 +} + +// hasAllMarks reports whether one internal node already has all requested bits. +func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool { + return query.nodes[idx].marks&bits == bits +} diff --git a/commitquery/ancestor.go b/commitquery/query_is_ancestor.go index 6a43babb..c21892c8 100644 --- a/commitquery/ancestor.go +++ b/commitquery/query_is_ancestor.go @@ -20,6 +20,7 @@ func (query *query) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, er return query.isAncestor(ancestorIdx, descendantIdx) } +// isAncestor answers one ancestry query between two resolved internal nodes. func (query *query) isAncestor(ancestor, descendant nodeIndex) (bool, error) { if ancestor == descendant { return true, nil diff --git a/commitquery/query_load_by_graph_pos.go b/commitquery/query_load_by_graph_pos.go new file mode 100644 index 00000000..718d99b5 --- /dev/null +++ b/commitquery/query_load_by_graph_pos.go @@ -0,0 +1,8 @@ +package commitquery + +// loadByGraphPos populates one node from a commit-graph position. +func (query *query) loadByGraphPos(idx nodeIndex) error { + pos := query.nodes[idx].graphPos + + return query.loadCommitAtGraphPos(idx, pos) +} diff --git a/commitquery/load.go b/commitquery/query_load_by_oid.go index 076f3000..eb997b2d 100644 --- a/commitquery/load.go +++ b/commitquery/query_load_by_oid.go @@ -10,19 +10,6 @@ import ( objecttype "codeberg.org/lindenii/furgit/object/type" ) -// ensureLoaded completes one node's metadata load if it has not been loaded yet. -func (query *query) ensureLoaded(idx nodeIndex) error { - if query.nodes[idx].loaded { - return nil - } - - if query.nodes[idx].hasGraphPos { - return query.loadByGraphPos(idx) - } - - return query.loadByOID(idx) -} - // loadByOID populates one node from an object ID. func (query *query) loadByOID(idx nodeIndex) error { id := query.nodes[idx].id diff --git a/commitquery/graph_pos.go b/commitquery/query_load_commit_at_graph_pos.go index 6b5118b0..f63b6385 100644 --- a/commitquery/graph_pos.go +++ b/commitquery/query_load_commit_at_graph_pos.go @@ -2,50 +2,7 @@ package commitquery import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" -// resolveGraphPos resolves one commit-graph position to one internal query node. -func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { - idx, ok := query.byGraphPos[pos] - if ok { - err := query.ensureLoaded(idx) - if err != nil { - return 0, err - } - - return idx, nil - } - - commit, err := query.graph.CommitAt(pos) - if err != nil { - return 0, err - } - - idx, ok = query.byOID[commit.OID] - if !ok { - idx = query.newNode(commit.OID) - query.byOID[commit.OID] = idx - } - - query.byGraphPos[pos] = idx - query.nodes[idx].graphPos = pos - query.nodes[idx].hasGraphPos = true - - err = query.loadCommitAtGraphPos(idx, pos) - if err != nil { - delete(query.byGraphPos, pos) - - return 0, err - } - - return idx, nil -} - -// loadByGraphPos populates one node from a commit-graph position. -func (query *query) loadByGraphPos(idx nodeIndex) error { - pos := query.nodes[idx].graphPos - - return query.loadCommitAtGraphPos(idx, pos) -} - +// loadCommitAtGraphPos populates one node from one commit-graph record. func (query *query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error { commit, err := query.graph.CommitAt(pos) if err != nil { diff --git a/commitquery/query_mark_phase.go b/commitquery/query_mark_phase.go new file mode 100644 index 00000000..0814df38 --- /dev/null +++ b/commitquery/query_mark_phase.go @@ -0,0 +1,36 @@ +package commitquery + +// beginMarkPhase starts one tracked mark-mutation phase. +func (query *query) beginMarkPhase() { + for _, idx := range query.touched { + query.nodes[idx].marks = 0 + } + + query.markPhase++ + if query.markPhase == 0 { + query.markPhase++ + for i := range query.nodes { + query.nodes[i].touchedPhase = 0 + } + } + + query.touched = query.touched[:0] +} + +// clearTouchedMarks clears the provided bits from all nodes touched in the +// current mark phase. +func (query *query) clearTouchedMarks(bits markBits) { + for _, idx := range query.touched { + query.nodes[idx].marks &^= bits + } +} + +// trackTouched records one node in the current mark phase. +func (query *query) trackTouched(idx nodeIndex) { + if query.nodes[idx].touchedPhase == query.markPhase { + return + } + + query.nodes[idx].touchedPhase = query.markPhase + query.touched = append(query.touched, idx) +} diff --git a/commitquery/query_marks_get.go b/commitquery/query_marks_get.go new file mode 100644 index 00000000..28136d84 --- /dev/null +++ b/commitquery/query_marks_get.go @@ -0,0 +1,6 @@ +package commitquery + +// marks returns the mark bits of one internal node. +func (query *query) marks(idx nodeIndex) markBits { + return query.nodes[idx].marks +} diff --git a/commitquery/query_merge_base.go b/commitquery/query_merge_base.go new file mode 100644 index 00000000..e1ba3126 --- /dev/null +++ b/commitquery/query_merge_base.go @@ -0,0 +1,17 @@ +package commitquery + +import objectid "codeberg.org/lindenii/furgit/object/id" + +// MergeBase reports one merge base between left and right, if any. +func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { + bases, err := query.MergeBases(left, right) + if err != nil { + return objectid.ObjectID{}, false, err + } + + if len(bases) == 0 { + return objectid.ObjectID{}, false, nil + } + + return bases[0], true, nil +} diff --git a/commitquery/merge_bases.go b/commitquery/query_merge_bases.go index 281906f3..384ee019 100644 --- a/commitquery/merge_bases.go +++ b/commitquery/query_merge_bases.go @@ -43,47 +43,3 @@ func (query *query) MergeBases(left, right objectid.ObjectID) ([]objectid.Object return out, nil } - -// MergeBase reports one merge base between left and right, if any. -func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) { - bases, err := query.MergeBases(left, right) - if err != nil { - return objectid.ObjectID{}, false, err - } - - if len(bases) == 0 { - return objectid.ObjectID{}, false, nil - } - - return bases[0], true, nil -} - -func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { - if left == right { - return []nodeIndex{left}, nil - } - - err := query.paintDownToCommon(left, []nodeIndex{right}, 0) - if err != nil { - return nil, err - } - - candidates := query.collectMarkedResults() - - if len(candidates) <= 1 { - slices.SortFunc(candidates, query.compare) - - return candidates, nil - } - - query.clearTouchedMarks(allMarks) - - reduced, err := removeRedundant(query, candidates) - if err != nil { - return nil, err - } - - slices.SortFunc(reduced, query.compare) - - return reduced, nil -} diff --git a/commitquery/query_merge_bases_internal.go b/commitquery/query_merge_bases_internal.go new file mode 100644 index 00000000..2d133435 --- /dev/null +++ b/commitquery/query_merge_bases_internal.go @@ -0,0 +1,34 @@ +package commitquery + +import "slices" + +// mergeBases returns internal merge-base candidates for two resolved nodes. +func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) { + if left == right { + return []nodeIndex{left}, nil + } + + err := query.paintDownToCommon(left, []nodeIndex{right}, 0) + if err != nil { + return nil, err + } + + candidates := query.collectMarkedResults() + + if len(candidates) <= 1 { + slices.SortFunc(candidates, query.compare) + + return candidates, nil + } + + query.clearTouchedMarks(allMarks) + + reduced, err := removeRedundant(query, candidates) + if err != nil { + return nil, err + } + + slices.SortFunc(reduced, query.compare) + + return reduced, nil +} diff --git a/commitquery/reset.go b/commitquery/query_new.go index 465f05c1..722f049e 100644 --- a/commitquery/reset.go +++ b/commitquery/query_new.go @@ -6,19 +6,9 @@ import ( objectstore "codeberg.org/lindenii/furgit/object/store" ) -type query struct { - store objectstore.ReadingStore - graph *commitgraphread.Reader - - nodes []node - - byOID map[objectid.ObjectID]nodeIndex - byGraphPos map[commitgraphread.Position]nodeIndex - - markPhase uint32 - touched []nodeIndex -} - +// newQuery builds one empty mutable worker over one object store and graph. +// +// Labels: Deps-Borrowed, Life-Parent. func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *query { return &query{ store: store, @@ -27,11 +17,3 @@ func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *qu byGraphPos: make(map[commitgraphread.Position]nodeIndex), } } - -func (query *query) resetForReuse() { - for _, idx := range query.touched { - query.nodes[idx].marks = 0 - } - - query.touched = query.touched[:0] -} diff --git a/commitquery/node_paint_down_to_common.go b/commitquery/query_paint_down_to_common.go index 2fa24816..e152e159 100644 --- a/commitquery/node_paint_down_to_common.go +++ b/commitquery/query_paint_down_to_common.go @@ -2,6 +2,7 @@ package commitquery import "codeberg.org/lindenii/furgit/internal/priorityqueue" +// paintDownToCommon propagates left and right marks downward until common nodes. func (query *query) paintDownToCommon(left nodeIndex, rights []nodeIndex, minGeneration uint64) error { query.beginMarkPhase() diff --git a/commitquery/reduce.go b/commitquery/query_reduce.go index 46c3bf39..b7ea5df1 100644 --- a/commitquery/reduce.go +++ b/commitquery/query_reduce.go @@ -1,8 +1,6 @@ package commitquery -import ( - "slices" -) +import "slices" // removeRedundant removes redundant merge-base candidates. func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error) { @@ -15,6 +13,7 @@ func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error) return removeRedundantNoGen(query, candidates) } +// removeRedundantNoGen removes redundant candidates without generation data. func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, error) { redundant := make([]bool, len(candidates)) work := make([]nodeIndex, 0, len(candidates)-1) @@ -72,6 +71,7 @@ func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, er return out, nil } +// removeRedundantWithGen removes redundant candidates using generation data. func removeRedundantWithGen(query *query, candidates []nodeIndex) []nodeIndex { sorted := append([]nodeIndex(nil), candidates...) slices.SortFunc(sorted, query.compareByGeneration()) diff --git a/commitquery/query_reset.go b/commitquery/query_reset.go new file mode 100644 index 00000000..11f7cb3e --- /dev/null +++ b/commitquery/query_reset.go @@ -0,0 +1,10 @@ +package commitquery + +// resetForReuse clears transient state before one worker returns to the pool. +func (query *query) resetForReuse() { + for _, idx := range query.touched { + query.nodes[idx].marks = 0 + } + + query.touched = query.touched[:0] +} diff --git a/commitquery/query_resolve_commitish.go b/commitquery/query_resolve_commitish.go new file mode 100644 index 00000000..1b91c8bd --- /dev/null +++ b/commitquery/query_resolve_commitish.go @@ -0,0 +1,16 @@ +package commitquery + +import ( + "codeberg.org/lindenii/furgit/internal/peel" + objectid "codeberg.org/lindenii/furgit/object/id" +) + +// resolveCommitish peels one commit-ish object ID and resolves the commit. +func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { + commitID, err := peel.ToCommit(query.store, id) + if err != nil { + return 0, err + } + + return query.resolveOID(commitID) +} diff --git a/commitquery/query_resolve_graph_pos.go b/commitquery/query_resolve_graph_pos.go new file mode 100644 index 00000000..dce8fc22 --- /dev/null +++ b/commitquery/query_resolve_graph_pos.go @@ -0,0 +1,40 @@ +package commitquery + +import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" + +// resolveGraphPos resolves one commit-graph position to one internal query node. +func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) { + idx, ok := query.byGraphPos[pos] + if ok { + err := query.ensureLoaded(idx) + if err != nil { + return 0, err + } + + return idx, nil + } + + commit, err := query.graph.CommitAt(pos) + if err != nil { + return 0, err + } + + idx, ok = query.byOID[commit.OID] + if !ok { + idx = query.newNode(commit.OID) + query.byOID[commit.OID] = idx + } + + query.byGraphPos[pos] = idx + query.nodes[idx].graphPos = pos + query.nodes[idx].hasGraphPos = true + + err = query.loadCommitAtGraphPos(idx, pos) + if err != nil { + delete(query.byGraphPos, pos) + + return 0, err + } + + return idx, nil +} diff --git a/commitquery/resolve.go b/commitquery/query_resolve_oid.go index cd6c3650..ad47829c 100644 --- a/commitquery/resolve.go +++ b/commitquery/query_resolve_oid.go @@ -1,10 +1,8 @@ package commitquery -import ( - "codeberg.org/lindenii/furgit/internal/peel" - objectid "codeberg.org/lindenii/furgit/object/id" -) +import objectid "codeberg.org/lindenii/furgit/object/id" +// resolveOID resolves one commit object ID to one internal query node. func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { idx, ok := query.byOID[id] if ok { @@ -28,12 +26,3 @@ func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) { return idx, nil } - -func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) { - commitID, err := peel.ToCommit(query.store, id) - if err != nil { - return 0, err - } - - return query.resolveOID(commitID) -} diff --git a/commitquery/query_resolve_parent.go b/commitquery/query_resolve_parent.go new file mode 100644 index 00000000..6cd75898 --- /dev/null +++ b/commitquery/query_resolve_parent.go @@ -0,0 +1,10 @@ +package commitquery + +// resolveParent resolves one parent descriptor to one internal node. +func (query *query) resolveParent(parent parentRef) (nodeIndex, error) { + if parent.HasGraphPos { + return query.resolveGraphPos(parent.GraphPos) + } + + return query.resolveOID(parent.ID) +} diff --git a/commitquery/query_set_clear_marks.go b/commitquery/query_set_clear_marks.go new file mode 100644 index 00000000..b9619338 --- /dev/null +++ b/commitquery/query_set_clear_marks.go @@ -0,0 +1,22 @@ +package commitquery + +// setMarks ORs one set of mark bits into one internal node. +func (query *query) setMarks(idx nodeIndex, bits markBits) { + newBits := bits &^ query.nodes[idx].marks + if newBits == 0 { + return + } + + query.trackTouched(idx) + query.nodes[idx].marks |= bits +} + +// clearMarks removes one set of mark bits from one internal node. +func (query *query) clearMarks(idx nodeIndex, bits markBits) { + if query.nodes[idx].marks&bits == 0 { + return + } + + query.trackTouched(idx) + query.nodes[idx].marks &^= bits +} |
