Repository navigation
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4284 +/- ##
==========================================
+ Coverage 32.78% 32.87% +0.08%
==========================================
Files 673 673
Lines 41707 41711 +4
==========================================
+ Hits 13673 13711 +38
+ Misses 28034 28000 -34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
carpawell
left a comment
There was a problem hiding this comment.
While this PR should not break anything, cause only storage routines were added, i do not like it cause it was kinda a feature: every object goes one by one in a strict order, this is why the meta service was created. With this PR, the order of object savings to the local index may change now. HEADing in parallel and the common idea is ok to me, but i would have kept the original object order.
d4b3e9a to
07aa25e
Compare
|
Kept the worker pool rather than preserving order — my call, but say the word and I will switch. The order already is not observable downstream: I did write the order-preserving variant — fetch concurrently, hand off in arrival order — and did not push it because it reintroduces head-of-line blocking: one hung HEAD stalls everything after |
d2503f0 to
d95f619
Compare
I don't think so. It's a slice and it's iterated one by one. So for a typical case of tombstone/lock conflict order matters a lot, one should succeed, the other should fail and the winner is determined by order defined by the order of transactions. So while the problem is somewhat valid (certainly not critical at this point), the fix suggested is not correct. |
storager handled one task at a time, and each may need a network HEAD to fetch a header it does not already have, so a slow peer delayed indexing of every object queued behind it. Resolve a group of headers concurrently instead, bounded like the same kind of per-object HEAD in split.Verifier, and hand them to batchWriter in the order they were queued. The order is load-bearing: metabase.DB.PutBatch applies a batch in slice order within one transaction, so for a lock and a tombstone of the same object it decides which is indexed and which is skipped as non-critical, and tasks arrive here in metadata chain order, which is the same on every node holding the container. A group is one blocking take plus whatever is already queued, so a single task is still handled immediately. Signed-off-by: Fabian Wahle <fabian@nash.io> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
d95f619 to
6aedf5f
Compare
|
Confirmed, you're right. Reworked to keep it: a group of up to 16 headers is resolved concurrently into a positionally indexed slice and handed to Worth flagging that this no longer helps a peer that hangs rather than one that is slow, since preserving order means head-of-line blocking. What is left is the latency amortization. Title and description updated. |
Summary
storagerhandled onestorageTaskat a time, and each may need a network HEAD (m.net.Head) to fetch a header it does not already have. That call goes through the same get service as any object HEAD and may have to reach a remote peer. Sincestoragerwas the sole reader of its queue, a slow peer delayed indexing of every object queued behind it.Fix
Resolve a group of up to
storagerConcurrencyheaders concurrently into a positionally indexed slice, then hand them tobatchWriterin the order they were queued. 16 is the boundsplit.Verifieralready uses for the same kind of per-object HEAD. A group is one blocking take plus whatever is already queued, so a single task is still handled immediately.Queue order is preserved deliberately:
metabase.DB.PutBatchapplies a batch in slice order within one transaction, so for a lock and a tombstone of the same object it decides which one is indexed and which is skipped as non-critical. Tasks arrive here in metadata chain order, and resolving them out of order would make that outcome depend on local header-fetch timing instead.Scope
This does not help a peer that hangs rather than one that is slow: preserving order means head-of-line blocking, and
Headruns on the service context with no deadline. The gain is that N slow-but-responsive peers cost one HEAD round trip rather than N.Test plan
TestMeta_storager_KeepsQueueOrder: tombstone queued first with a slow header, lock second with an immediate one, asserts the tombstone still wins the conflict. Verified to fail both on the previous worker-pool version and on a variant that fills the group in completion order.TestMeta_storager_BoundsConcurrency: verified to fail on master (serial), passes here.go test ./pkg/services/meta/... -raceclean over 20 consecutive runs;go vet ./..., golangci-lint andgo build ./...clean.🤖 Generated with Claude Code