Skip to content

Conversation

hsanjuan
Copy link
Contributor

@hsanjuan hsanjuan commented Jul 29, 2025

This updates boxo to this PR ipfs/boxo#976, which decentralizes the providing responsibilities.

Then it perfoms the necessary changes in Kubo, which consist in initializing the Pinner, MFS and the blockstore with the provider.System.

Since the provider.System is created first, the reproviding KeyChanFunc is set later when we can create it.

Aims to Close #10837

@hsanjuan hsanjuan self-assigned this Jul 29, 2025
This updates boxo to this PR ipfs/boxo#976, which decentralizes the providing responsibilities.

Then it perfoms the necessary changes in Kubo, which consist in initializing the Pinner, MFS and the blockstore with the provider.System.

Since the provider.System is created first, the reproviding KeyChanFunc is set
later when we can create it.
@hsanjuan hsanjuan force-pushed the fix/10837-provide-according-to-strategy branch from dc44336 to 72a97c7 Compare July 29, 2025 12:55
Rather than fx.Provide(). Since no one was needing the strategy for anything, it was not getting called, and not getting set in the reprovider.
@hsanjuan

This comment was marked as outdated.

This commit ensure that added blocks get provided with "pinned" strategy.

Normally, blocks would get provided at the blockstore or pinner facility, but
when adding with "pinned" strategy, the blockstore does not provide, and the
pinner does not traverse the DAG so we need to provide directly from the Adder.

This is resolved by wrapping the DAGService in a "providingDAGService" which
provides every added block, when using the "pinned" strategy. There are
alternatives like wiring a provider in coreunix but this seems simple enough
and follows existing style as the DAGService is already wrapped as a Syncer.

CoreAPI also overwrote the provider into a NoopProvider when using
--offline. However, we have strategies to follow and it did not overwrite the
blockstore. So --offline would provide anyways with strategy "all", and not
provide with strategy "pinned".

It seems reasonable to provide following the provider strategy when the node
is online, regardless of the client flag. Otherwise we can change it later by
overwriting the provider and the blockstore.

cli/provider tests have been fixed and made to not rely on `--offline`.
@hsanjuan hsanjuan marked this pull request as ready for review August 6, 2025 08:24
@hsanjuan hsanjuan requested a review from a team as a code owner August 6, 2025 08:24
Copy link
Contributor Author

@hsanjuan hsanjuan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self review and clarifications

@@ -70,7 +73,8 @@ type CoreAPI struct {
ipldPathResolver pathresolver.Resolver
unixFSPathResolver pathresolver.Resolver

provider provider.System
provider provider.System
providingStrategy string
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carry the strategy so we can react on it when adding content.

Comment on lines -47 to -50
if err := api.provider.Provide(ctx, dagNode.Cid(), true); err != nil {
return err
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, at the end of the Pin process, coreapi would trigger a Provide for the root CID (regardless of prividing strategy).

We now provide according to strategy, and this does not need to happen here (happens in the pinner).

Comment on lines 107 to 120
var dserv ipld.DAGService = merkledag.NewDAGService(bserv)

// wrap the DAGService in a providingDAG service which provides every block written.
// note about strategies:
// - "all"/"flat" gets handled directly at the blockstore so no need to provide
// - "roots" gets handled in the pinner
// - "mfs" gets handled in mfs
// We need to provide the "pinned" cases only. Added blocks are not
// going to be provided by the blockstore (wrong strategy for that),
// nor by the pinner (it does not traverse the pinned DAG).
if settings.Pin && !settings.OnlyHash &&
(api.providingStrategy == "pinned" || api.providingStrategy == "pinned+mfs") {
dserv = &providingDagService{dserv, api.provider}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the comment, we need to ensure we provide blocks while Adding with the "pinned" strategy as this cannot happen in the Pinner (it doesn't traverse the DAG itself). For that, we wrap the DagService.

@@ -183,7 +200,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
if err != nil {
return path.ImmutablePath{}, err
}
mr, err := mfs.NewRoot(ctx, md, emptyDirNode, nil)
mr, err := mfs.NewRoot(ctx, md, emptyDirNode, nil, nil)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new nil is the provider, which we leave disabled for MFS here. We are using a providing DAG service when needed.

Could we potentially passed a provider around and initialize MFS with it here and have it provide this way, rather than wrapping the DAGService? Potentially yes, but I'm not sure what happens with file-chunks and if MFS touches them at all. If not, I would need to wire the chunkers too etc. Overall it seemed more complex and fragile to do it that way.


in.Provider.SetKeyProvider(kcf)

var strategyChanged bool
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strategy-change detection has been moved here. No changes in code blocks below.

@hsanjuan hsanjuan force-pushed the fix/10837-provide-according-to-strategy branch from d1de66a to 64d5096 Compare August 6, 2025 09:15
Things like block/put are now provided correctly. Tests rely on those things
not being provided and a manual call to "routing provide" being needed.

Fix things by setting "roots" as strategy for tests.
@hsanjuan hsanjuan changed the title Provide according to strategy Provide according to Reprovider.Strategy Aug 6, 2025
Copy link
Contributor

@gammazero gammazero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments.

@@ -126,6 +141,8 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
}
}

// reminder: the dag server gets wrapped again (!) as a batching dagservice in coreunix.Adder.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this happen? Does this refer to where a batch is created in the dag put command?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here:

bufferedDS := ipld.NewBufferedDAG(ctx, ds)

There is a normal DAGService, which gets wrapped in a providing DAGService, which gets wrapped in a SyncDAGService, which gets wrapped in a Buffered DAGService.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@guillaumemichel guillaumemichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

A few comments

* more tests
* work with bit flags rather than string for the strategies
* fix typos
@lidel lidel mentioned this pull request Aug 7, 2025
51 tasks
lidel added 3 commits August 7, 2025 20:18
just a precaution, since we don't want pinner provide to hide issues
with "all" strategy
extra info from comments to #10886
@lidel lidel self-requested a review August 7, 2025 18:42
@lidel lidel changed the title Provide according to Reprovider.Strategy fix: Provide according to Reprovider.Strategy Aug 7, 2025
did too many things, this makes it easier to understand and maintain
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed some extra go comments with context from this and boxo PRs + small refactor.

Lgtm, but want to run some additional manual tests before merging.
Will post once done.

lidel added 2 commits August 7, 2025 22:30
just making sure dag and block puts are wired "the same way" as add
command
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @hsanjuan, this should make future changes easier to reason about. Lgtm, pushed extra docs/tests.

Ok to squash&merge, but would like you to take one final look at split I did in 3b481cd and give 👍

If no concerns my plan is to merge this by the end of this week (end of Friday 8th) to unblock other PRs that depend on latest boxo (e.g. #10851 (comment)).

@hsanjuan
Copy link
Contributor Author

hsanjuan commented Aug 8, 2025

Split looks good

@hsanjuan hsanjuan merged commit a673c2e into master Aug 8, 2025
16 checks passed
@hsanjuan hsanjuan deleted the fix/10837-provide-according-to-strategy branch August 8, 2025 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide newly received blocks according to reprovide strategy
4 participants