mirror of
https://github.com/milvus-io/milvus.git
synced 2026-07-21 02:05:41 +00:00
issue: #47404 - message trace context: add trace context serialization and restore/inject helpers for WAL messages and msgstream conversion - WAL append trace: normalize WAL spans for autocommit, txn, broadcast, append, appendimpl, and broadcast callback paths - trace propagation: restore message trace context in producer, broadcast retry, replicate primary/secondary, recovery, flusher, and query/data flowgraph consumers --------- Signed-off-by: chyezh <chyezh@outlook.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
123 lines
4.0 KiB
Go
123 lines
4.0 KiB
Go
package broadcaster
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
|
|
"github.com/milvus-io/milvus/internal/distributed/streaming"
|
|
"github.com/milvus-io/milvus/pkg/v3/mlog"
|
|
"github.com/milvus-io/milvus/pkg/v3/streaming/util/message"
|
|
"github.com/milvus-io/milvus/pkg/v3/streaming/util/types"
|
|
"github.com/milvus-io/milvus/pkg/v3/util/typeutil"
|
|
)
|
|
|
|
var errBroadcastTaskIsNotDone = errors.New("broadcast task is not done")
|
|
|
|
// newPendingBroadcastTask creates a new pendingBroadcastTask.
|
|
func newPendingBroadcastTask(task *broadcastTask) *pendingBroadcastTask {
|
|
msgs := task.PendingBroadcastMessages()
|
|
if len(msgs) == 0 {
|
|
return nil
|
|
}
|
|
return &pendingBroadcastTask{
|
|
broadcastTask: task,
|
|
pendingMessages: msgs,
|
|
appendResult: make(map[string]*types.AppendResult, len(msgs)),
|
|
BackoffWithInstant: typeutil.NewBackoffWithInstant(typeutil.BackoffTimerConfig{
|
|
Default: 10 * time.Second,
|
|
Backoff: typeutil.BackoffConfig{
|
|
InitialInterval: 10 * time.Millisecond,
|
|
Multiplier: 2.0,
|
|
MaxInterval: 10 * time.Second,
|
|
},
|
|
}),
|
|
}
|
|
}
|
|
|
|
// pendingBroadcastTask is a task that is pending to be broadcasted.
|
|
type pendingBroadcastTask struct {
|
|
*broadcastTask
|
|
pendingMessages []message.MutableMessage
|
|
appendResult map[string]*types.AppendResult
|
|
*typeutil.BackoffWithInstant
|
|
}
|
|
|
|
// Execute reexecute the task, return nil if the task is done, otherwise not done.
|
|
// Execute can be repeated called until the task is done.
|
|
// Same semantics as the `Poll` operation in eventloop.
|
|
func (b *pendingBroadcastTask) Execute(ctx context.Context) error {
|
|
ctx = message.ExtractTraceContext(ctx, b.msg)
|
|
|
|
if err := b.InitializeRecovery(ctx); err != nil {
|
|
b.Logger().Warn(ctx, "broadcast task initialize recovery failed", mlog.Err(err))
|
|
return err
|
|
}
|
|
|
|
if len(b.pendingMessages) > 0 {
|
|
b.Logger().Debug(ctx, "broadcast task is polling to make sent...", mlog.Int("pendingMessages", len(b.pendingMessages)))
|
|
resps := streaming.WAL().AppendMessages(ctx, b.pendingMessages...)
|
|
newPendings := make([]message.MutableMessage, 0)
|
|
for idx, resp := range resps.Responses {
|
|
if resp.Error != nil {
|
|
b.Logger().Warn(ctx, "broadcast task append message failed", mlog.Int("idx", idx), mlog.Err(resp.Error))
|
|
newPendings = append(newPendings, b.pendingMessages[idx])
|
|
continue
|
|
}
|
|
b.appendResult[b.pendingMessages[idx].VChannel()] = resp.AppendResult
|
|
}
|
|
b.pendingMessages = newPendings
|
|
b.Logger().Info(ctx, "broadcast task make a new broadcast done", mlog.Int("backoffRetryMessages", len(b.pendingMessages)))
|
|
}
|
|
if len(b.pendingMessages) == 0 {
|
|
// trigger a fast ack operation when the broadcast operation is done.
|
|
if err := b.FastAck(ctx, b.appendResult); err != nil {
|
|
b.Logger().Warn(ctx, "broadcast task save task failed", mlog.Err(err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
b.UpdateInstantWithNextBackOff()
|
|
return errBroadcastTaskIsNotDone
|
|
}
|
|
|
|
// pendingBroadcastTaskArray is a heap of pendingBroadcastTask.
|
|
type pendingBroadcastTaskArray []*pendingBroadcastTask
|
|
|
|
// Len returns the length of the heap.
|
|
func (h pendingBroadcastTaskArray) Len() int {
|
|
return len(h)
|
|
}
|
|
|
|
// Less returns true if the element at index i is less than the element at index j.
|
|
func (h pendingBroadcastTaskArray) Less(i, j int) bool {
|
|
return h[i].NextInstant().Before(h[j].NextInstant())
|
|
}
|
|
|
|
// Swap swaps the elements at indexes i and j.
|
|
func (h pendingBroadcastTaskArray) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
|
|
|
// Push pushes the last one at len.
|
|
func (h *pendingBroadcastTaskArray) Push(x interface{}) {
|
|
// Push and Pop use pointer receivers because they modify the slice's length,
|
|
// not just its contents.
|
|
*h = append(*h, x.(*pendingBroadcastTask))
|
|
}
|
|
|
|
// Pop pop the last one at len.
|
|
func (h *pendingBroadcastTaskArray) Pop() interface{} {
|
|
old := *h
|
|
n := len(old)
|
|
x := old[n-1]
|
|
old[n-1] = nil // release the memory of underlying array.
|
|
*h = old[0 : n-1]
|
|
return x
|
|
}
|
|
|
|
// Peek returns the element at the top of the heap.
|
|
// Panics if the heap is empty.
|
|
func (h *pendingBroadcastTaskArray) Peek() interface{} {
|
|
return (*h)[0]
|
|
}
|