Copilot commented on code in PR #1210:
URL: 
https://github.com/apache/skywalking-banyandb/pull/1210#discussion_r3541040584


##########
banyand/trace/merger.go:
##########
@@ -315,32 +338,63 @@ func (tst *tsTable) releaseDispatchRequest(req 
*mergeDispatchRequest) {
        }
 }
 
+// mergeOverrides lets the finalize round drive mergePartsThenSendIntroduction 
with a
+// pre-built sampler filter (bypassing the hot-path isMergeHot/merge_grace 
build) and a
+// finalize-generation stamp for the output part. A nil *mergeOverrides means 
the hot /
+// flusher path: build the filter from merge-time rules and min-propagate 
finalizeGen.
+type mergeOverrides struct {
+       filter      *mergeFilter
+       finalizeGen *uint64
+}
+
+// buildHotMergeFilter builds the in-merge retention filter for the hot / 
flusher merge
+// path from the merge-time rules (registered samplers + merge_grace 
maturity). It
+// returns nil when the native pipeline is off, no samplers are registered, or 
the merge
+// is still hot (parts younger than merge_grace), in which case the merge runs 
unfiltered.
+func (tst *tsTable) buildHotMergeFilter(parts []*partWrapper) *mergeFilter {
+       if !tst.option.nativePipelineEnabled {
+               return nil
+       }
+       samplers := lookupSamplers(tst.group)
+       if len(samplers) == 0 {
+               return nil
+       }
+       graceNs := lookupMergeGrace(tst.group)
+       if graceNs <= 0 {
+               graceNs = int64(tst.option.mergeGraceDefault)
+       }
+       if isMergeHot(parts, graceNs, time.Now().UnixNano()) {

Review Comment:
   `enabled_events` no longer reliably disables the MERGE-time retention 
filter. With a FINALIZE-only config, `reconcilePipeline` still registers 
samplers, and `buildHotMergeFilter` applies them to hot merges whenever 
`nativePipelineEnabled` is on (it only checks `lookupSamplers(tst.group)`). 
That contradicts the comment in `reconcilePipeline` that filtering can be 
disabled via `enabled_events`, and makes it impossible to enable FINALIZE 
without also enabling MERGE filtering.
   
   Consider tracking per-group merge-event enablement separately (e.g., a small 
registry boolean set by `reconcilePipeline`) and have `buildHotMergeFilter` 
return nil when MERGE is disabled for the group, even if samplers are 
registered for FINALIZE.



##########
banyand/trace/finalize_state.go:
##########
@@ -0,0 +1,91 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package trace
+
+import (
+       "encoding/json"
+       "path/filepath"
+
+       "github.com/pkg/errors"
+
+       "github.com/apache/skywalking-banyandb/banyand/internal/storage"
+       "github.com/apache/skywalking-banyandb/pkg/fs"
+)
+
+// finalizeStateFilename is the per-shard finalization-sampling state document,
+// stored in the shard directory alongside snapshots.
+const finalizeStateFilename = "finalize.json"
+
+// finalizeState is the per-shard finalization-sampling state, persisted 
atomically
+// in the shard directory (Rev 8: per-shard, NOT in the per-segment metadata). 
It is
+// the sole authority for a shard's finalize generation, cooldown clock, round 
count,
+// and arrival-based unsampled-bytes counter. The finalize worker is the only 
writer
+// (serialized node-wide); readers seed the cached tsTable fields at open. A 
missing
+// or corrupt file decodes to the zero value ("never finalized"), so 
pre-finalize
+// shards and partial writes both fail open.
+type finalizeState struct {
+       // LastFinalizedAt is the RFC3339Nano wall-clock of the last successful 
round;
+       // empty means never finalized. It is the cooldown clock.
+       LastFinalizedAt string `json:"lastFinalizedAt,omitempty"`
+       // FinalizeGeneration is the shard's monotonic current generation; 0 = 
never
+       // finalized. A part is selectable when its FinalizeGen < this value.
+       FinalizeGeneration uint64 `json:"finalizeGeneration,omitempty"`

Review Comment:
   The `FinalizeGeneration` comment doesn’t match the implemented selection 
predicate. `runFinalizeRound` selects parts with `FinalizeGen < gNext`, where 
`gNext = FinalizeGeneration + 1`, which effectively means `FinalizeGen <= 
FinalizeGeneration` (full rewrite per round). The current comment says 
“selectable when FinalizeGen < this value”, which would imply survivors stamped 
at `FinalizeGeneration` are *not* selected, contradicting the current semantics.



##########
banyand/trace/svc_standalone.go:
##########
@@ -218,6 +221,16 @@ func (s *standalone) PreRun(ctx context.Context) error {
        if err != nil {
                return err
        }
+       // Start the background finalization-sampling scanner when the native 
pipeline is
+       // enabled. It is a single node-wide goroutine (concurrency-1) that 
sweeps cooled
+       // segments of finalize-enabled groups; it is inert until a group 
enables the
+       // FINALIZE event, so starting it unconditionally-under-the-flag is 
safe.
+       if s.option.nativePipelineEnabled {
+               s.finalizeCloser = run.NewCloser(1)
+               //nolint:contextcheck // the finalize scanner uses the 
run.Closer for cancellation, not a context (mirrors the tsTable loops).
+               go s.schemaRepo.finalizeScanLoop(s.finalizeCloser, 
defaultFinalizeScanInterval)
+       }

Review Comment:
   This starts a long-running background goroutine with a raw `go` statement. 
Elsewhere in the codebase, service-lifetime goroutines are typically launched 
via `run.Go(...)` to get centralized panic recovery/diagnostics. Using a bare 
`go` here means any unexpected panic inside `finalizeScanLoop` would crash the 
whole process.
   
   Consider switching this launch to `run.Go` (similar to 
`banyand/internal/storage/rotation.go:56`) so panics are recovered and reported 
consistently.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to