Skip to content

Commit b513474

Browse files
committed
fix: report dropped inbound messages at error level
1 parent 7cc037a commit b513474

2 files changed

Lines changed: 70 additions & 9 deletions

File tree

internal/db/p2p/p2p.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,11 @@ type P2P struct {
220220
// the rate for that interval rather than a running total.
221221
statDroppedBudget atomic.Int64
222222
statDroppedFull atomic.Int64
223-
statMergedDocs atomic.Int64
224-
statDroppedDocs atomic.Int64
223+
// dropSample holds a topic from the interval's drops, so the line reporting them can
224+
// name something to go and look at without logging every dropped message.
225+
dropSample atomic.Pointer[string]
226+
statMergedDocs atomic.Int64
227+
statDroppedDocs atomic.Int64
225228
// statSkippedDocs counts documents deliberately not merged: already held, or
226229
// excluded by access or the replication filter. Not a loss, so kept apart.
227230
statSkippedDocs atomic.Int64
@@ -730,10 +733,7 @@ func (p *P2P) pubSubMessageHandler(from string, topic string, msg []byte) ([]byt
730733
p.dedup.observe(msg)
731734
if !p.claimQueueBytes(size) {
732735
p.statDroppedBudget.Add(1)
733-
log.Info("pubsub message queue over byte budget, dropping message",
734-
corelog.Any("topic", topic),
735-
corelog.Int64("bytes", size),
736-
corelog.Int64("budget", p.msgQueueMaxBytes))
736+
p.dropSample.Store(&topic)
737737
return nil, nil
738738
}
739739

@@ -751,7 +751,7 @@ func (p *P2P) pubSubMessageHandler(from string, topic string, msg []byte) ([]byt
751751
default:
752752
p.releaseQueueBytes(size)
753753
p.statDroppedFull.Add(1)
754-
log.Info("pubsub message queue full, dropping message", corelog.Any("topic", topic))
754+
p.dropSample.Store(&topic)
755755
}
756756
return nil, nil
757757
}
@@ -791,13 +791,15 @@ func (p *P2P) reportStats() {
791791
return
792792
case <-ticker.C:
793793
msgsIn, msgsDistinct, dedupTruncated := p.dedup.drain()
794+
droppedOverBudget := p.statDroppedBudget.Swap(0)
795+
droppedQueueFull := p.statDroppedFull.Swap(0)
794796
log.Info("p2p stats",
795797
corelog.Int("queueDepth", len(p.msgQueue)),
796798
corelog.Int("queueSlots", msgQueueSize),
797799
corelog.Int64("queueBytes", p.msgQueueBytes.Load()),
798800
corelog.Int64("queueBudget", p.msgQueueMaxBytes),
799-
corelog.Int64("droppedOverBudget", p.statDroppedBudget.Swap(0)),
800-
corelog.Int64("droppedQueueFull", p.statDroppedFull.Swap(0)),
801+
corelog.Int64("droppedOverBudget", droppedOverBudget),
802+
corelog.Int64("droppedQueueFull", droppedQueueFull),
801803
corelog.Int64("batches", p.statBatches.Swap(0)),
802804
corelog.Int64("batchFailures", p.statBatchFailures.Swap(0)),
803805
corelog.Int64("docsMerged", p.statMergedDocs.Swap(0)),
@@ -821,6 +823,17 @@ func (p *P2P) reportStats() {
821823
corelog.Int64("syncDAGBlocks", p.statSyncDAGBlocks.Swap(0)),
822824
corelog.Int64("syncDAGAbandoned", p.statSyncDAGAbandoned.Swap(0)),
823825
)
826+
// A drop at the door is data this node will not hold. The stats line above is at
827+
// info and corelog has no level between info and error, so a node running at error
828+
// level only sees this. It carries a sampled topic rather than a line per message,
829+
// which on a saturated node is tens per second.
830+
if sample := p.dropSample.Swap(nil); sample != nil {
831+
log.Error("dropped inbound pubsub messages",
832+
corelog.Int64("overBudget", droppedOverBudget),
833+
corelog.Int64("queueFull", droppedQueueFull),
834+
corelog.String("sampleTopic", *sample))
835+
}
836+
824837
reportFailureReasons("car failures", p.carFailureReason.drain())
825838
reportFailureReasons("syncDAG failures", p.syncDAGFailureReason.drain())
826839
reportFailureReasons("document drops", p.docDropReason.drain())

internal/db/p2p/p2p_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,54 @@ func TestPubSubMessageHandler_QueueFullCountedSeparately(t *testing.T) {
170170
assert.Equal(t, int64(len(msg)), p.msgQueueBytes.Load())
171171
}
172172

173+
// The stats line carrying the drop counts is at info, so on a node running at error level the
174+
// sampled topic is the only thing that surfaces a drop at all. A quiet interval must stay quiet.
175+
func TestPubSubMessageHandler_DropRecordsSampleTopic(t *testing.T) {
176+
msg, err := cbor.Marshal(protocol.PushLogRequest{DocID: "docID"})
177+
assert.NoError(t, err)
178+
179+
newP2P := func(maxBytes int64) *P2P {
180+
return &P2P{
181+
ctx: context.Background(),
182+
host: &SimpleMockHost{},
183+
msgQueue: make(chan queuedMessage, 1),
184+
msgQueueMaxBytes: maxBytes,
185+
}
186+
}
187+
188+
t.Run("over budget", func(t *testing.T) {
189+
p := newP2P(1) // smaller than any message, so nothing can be admitted
190+
_, err := p.pubSubMessageHandler("sender", "over-budget-topic", msg)
191+
assert.NoError(t, err)
192+
193+
assert.Equal(t, int64(1), p.statDroppedBudget.Load())
194+
if sample := p.dropSample.Load(); assert.NotNil(t, sample) {
195+
assert.Equal(t, "over-budget-topic", *sample)
196+
}
197+
})
198+
199+
t.Run("queue full", func(t *testing.T) {
200+
p := newP2P(1 << 20) // budget out of the way, so only the slot count can reject
201+
_, err := p.pubSubMessageHandler("sender", "accepted-topic", msg)
202+
assert.NoError(t, err)
203+
_, err = p.pubSubMessageHandler("sender", "queue-full-topic", msg)
204+
assert.NoError(t, err)
205+
206+
assert.Equal(t, int64(1), p.statDroppedFull.Load())
207+
if sample := p.dropSample.Load(); assert.NotNil(t, sample) {
208+
assert.Equal(t, "queue-full-topic", *sample)
209+
}
210+
})
211+
212+
t.Run("nothing dropped", func(t *testing.T) {
213+
p := newP2P(1 << 20)
214+
_, err := p.pubSubMessageHandler("sender", "topic", msg)
215+
assert.NoError(t, err)
216+
217+
assert.Nil(t, p.dropSample.Load(), "an interval with no drops must not raise an error line")
218+
})
219+
}
220+
173221
func TestQueueByteBudget_DerivesFromMemoryLimit(t *testing.T) {
174222
original := debug.SetMemoryLimit(-1)
175223
t.Cleanup(func() { debug.SetMemoryLimit(original) })

0 commit comments

Comments
 (0)