Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Fix selector helpers #24

Merged
merged 3 commits into from Aug 16, 2021
Merged

Fix selector helpers #24

merged 3 commits into from Aug 16, 2021

Conversation

aschmahmann
Copy link
Contributor

@aschmahmann aschmahmann commented Aug 13, 2021

Per ipfs/kubo#7976 (comment) there seem to be some issues with the traversal code here, and probably with the Fetcher interface as well.

This is an attempt to resolve them, but I'm not very familiar with the codebase so please lmk if I'm just missing things.

Comment on lines +13 to +21
var matchAllSelector ipld.Node

func init() {
ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)
matchAllSelector = ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreUnion(
ssb.Matcher(),
ssb.ExploreAll(ssb.ExploreRecursiveEdge()),
)).Node()
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAICT this selector means matchAll and there's no reason to rebuild it continuously given that it's a static thing that shouldn't eat much memory.

Copy link
Member

@warpfork warpfork Aug 15, 2021

Choose a reason for hiding this comment

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

FWIW, I also added one of these upstream recently, here: https://github.com/ipld/go-ipld-prime/blob/df94e6a99727d6dfd9f3381f0f407f3df368178a/traversal/selector/parse/selector_parse.go#L94

Though I'm fine seeing a construction snippet like this recur locally in places, as needed, too. It's more antifragile that way. (I added that precompiled one to upstream as much for an example as for any other purpose; I don't know if it actually really "belongs" in the API surface area up there.)

Comment on lines 38 to 40
// BlockAll traverses all nodes in the graph linked by root. The nodes will be untyped and send over the results
// channel.
func BlockAll(ctx context.Context, f fetcher.Fetcher, root ipld.Link, cb fetcher.FetchCallback) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could probably just kill this function in exchange for exporting the selector itself but it shouldn't be a big deal.


// BlockAllOfType traverses all nodes in the graph linked by root. The nodes will typed according to ptype
// and send over the results channel.
func BlockAllOfType(ctx context.Context, f fetcher.Fetcher, root ipld.Link, ptype ipld.NodePrototype, cb fetcher.FetchCallback) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

IIUC this function seems actively harmful. Even if this function were fixed up it would be special casing the first node in the traversal which feels like bugs just waiting to happen.

Comment on lines +100 to +103
_ ipld.NodePrototype, cb fetcher.FetchCallback) error {

// retrieve first node
node, err := f.BlockOfType(ctx, root, ptype)
prototype, err := f.PrototypeFromLink(root)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Special casing the type of the first node over the others seems harmful/bug prone. We can just use the linksystem to figure out what it should be.

It seems like we could probably also just change the name and signature of this function in the Fetcher interface to drop this. I'm not sure if it would cause much propagation damage and should wait for a follow-up set of PRs though. If we're not going to do this let's at least add a comment to the interface saying that the prototype should be ignored.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what the issue is here? And I'm not sure LinkSystem is that smart?

One typically wants a NodePrototype parameter to either A) say what kind of memory layout to use, or B) say what kind of types to use, if it's a schema node (and this, then, can go on to hint where ADLs should be later, etc, though we do not use this anywhere in IPFS yet, and it may be some time before we do).

LinkSystem has a NodeReifier callback, yes, but it's not meant to do half of those jobs.

(All of this should be prefixed with "I think". I don't understand big picture what this function is supposed to be doing.)

Copy link
Member

Choose a reason for hiding this comment

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

... Looking yet again, I set the strength of my previous comment to zero. Because I agree with Will's comment that PrototypeFromLink doesn't seem to belong here at all, I just can't make sense of this, so if you're telling me this fixed something, I can't protest.

@willscott
Copy link
Contributor

I read through this proposed change and am generally okay with switching the interface to not take the explicit prototype constructor to use. That said, i would prefer to let @warpfork or @hannahhoward have a chance to review, since I know some thought and iteration has gone into this interface.

I do still think PrototypeFromLink shouldn't belong on the fetcher interface at all. It's not a property of the fetcher, but of the linksystem environment using the fetcher. (it's not getting data, and it's not something the fetcher is in a unique position to know information about)

@warpfork
Copy link
Member

I'm also gonna punt to @hannahhoward. I don't see anything to object to in the diffs, but I don't feel ownership here either.

(As I touched lightly on in the megapost in go-path (which ended up reviewing a lot of the whole module graph), my current understanding of go-fetcher is that it contains a lot of glue code; and my hope is in the future it either {develops a stronger identity and clear scope}, or {we fold the reusable parts into upstreams and fold the glue parts into downstreams}... so I don't really have a good sense of what's appropriate abstraction in this repo right now and what's not.)

Copy link
Member

@warpfork warpfork left a comment

Choose a reason for hiding this comment

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

We all seem to be in a "no objections" state, so let's call this good and move forward.

  • The CI shows downstream having problems before this: https://circleci.com/gh/ipfs/go-ipfs/55708 , described in IPLD Prime In IPFS: Target Merge Branch kubo#7976 (comment)
  • The CI shows a commit downstream getting green by this change: ipfs/kubo@7a975b0
  • It's unfortunate that there's no tests in this repo that demonstrate the issue or the fix, but I'm unwilling to block us on that given the general confidence in this API as written.
  • My main worry would be that we're going to merge this and tag and it bubble it up and then find it doesn't fix anything, but that appears addressed by the above existing CI observations from the only downstream that matters.

@warpfork
Copy link
Member

IIUC, the path to bubble this up into go-ipfs is just:

  • go-fetcher (this)
  • go-path
  • interface-go-ipfs-core
  • go-ipfs 🎉

@warpfork warpfork merged commit 86467b9 into main Aug 16, 2021
@warpfork warpfork deleted the fix/selector-helpers branch August 16, 2021 17:27
Jorropo pushed a commit to ipfs/go-libipfs-rapide that referenced this pull request Mar 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants