Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: proxy all types of delegated routing #23

Merged
merged 10 commits into from
Jan 15, 2024
Merged

feat: proxy all types of delegated routing #23

merged 10 commits into from
Jan 15, 2024

Conversation

hacdias
Copy link
Member

@hacdias hacdias commented Nov 20, 2023

This is my initial version of the "everything bagel" for someguy: proxy everything we get from other sources and spit it back when asked. I did not use that much code from go-libp2p-routing-helpers however. Our Delegated Routing stuff uses iterators, while libp2p relies on channels. Makes it very hard to re-use most of the code.

To Do

cc @aschmahmann

@hacdias hacdias changed the title feat: proxy everything feat: proxy all types of delegated routing Nov 27, 2023
Copy link
Contributor

@aschmahmann aschmahmann left a comment

Choose a reason for hiding this comment

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

Thanks for starting this 🙏.

Figure out why the network on my laptop stops working properly if I have this turned on for a few minutes.

My guess is running the accelerated dht client isn't making your router happy, but it has some QoS protections (like per-device limits) to protect your devices from each other. You can use a cli flag to enable/disable the accelerated DHT client and you should see if that makes the difference for you.

server_routers.go Outdated Show resolved Hide resolved
server_routers.go Outdated Show resolved Hide resolved
server_routers.go Show resolved Hide resolved
Comment on lines 50 to 52
type parallelRouter struct {
routers []server.ContentRouter
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This code seems complicated enough that we should have some tests. The code looks similar to the go-libp2p-routing-helpers code so might be you can crib tests from there.

Copy link
Member Author

Choose a reason for hiding this comment

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

I still have to add more tests. It's not as easy to port the tests from libp2p as I thought

server_routers.go Show resolved Hide resolved
@hacdias
Copy link
Member Author

hacdias commented Nov 30, 2023

My guess is running the accelerated dht client isn't making your router happy, but it has some QoS protections (like per-device limits) to protect your devices from each other. You can use a cli flag to enable/disable the accelerated DHT client and you should see if that makes the difference for you.

I will check this once at home. I haven't had this issue on the coworking space.

Edit: seems to be the case.

@hacdias hacdias self-assigned this Nov 30, 2023
it, itErr := call(ri)

if itErr != nil {
err = errors.Join(err, itErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

how are you thinking we're going to detect errors (e.g. with cid.contact) in prod? e.g. should we be logging from here or within one of the other packages? Does sending an error back along with the results make sense or will that cause problems?

Copy link
Member Author

Choose a reason for hiding this comment

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

Personally, I would always prefer that the caller handles the errors. Unfortunately, Boxo's server implementation ignores closing errors:

So we'd probably have to add it here if we want them.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair, does that mean we should be doing some logging in the meanwhile as a sanity check around cid.contact errors?

server_routers.go Outdated Show resolved Hide resolved
server_routers.go Outdated Show resolved Hide resolved
return mi.its[mi.next].Val()
}

func (mi *manyIter[T]) Close() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

May not really matter here (and might not be required if the semantics of iter.Close are intentionally loose), but is calling Next() after Close() supposed to work or not?

Doesn't seem like you need to worry about concurrent reads+closes (https://github.com/ipfs/boxo/blob/08959f281f866bd4197b40bc90cf75c2828c07f0/routing/http/types/iter/iter.go#L6), but not sure if all implementations are supposed to follow a similar pattern to https://github.com/ipfs/boxo/blob/08959f281f866bd4197b40bc90cf75c2828c07f0/routing/http/types/iter/json.go#L55

Copy link
Member Author

@hacdias hacdias Dec 4, 2023

Choose a reason for hiding this comment

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

May not really matter here (and might not be required if the semantics of iter.Close are intentionally loose), but is calling Next() after Close() supposed to work or not?

As far as I understand, yes. The documentation states Next sets the iterator to the next value, returning true if an attempt was made to get the next value., which for me reads that: after Close, Next will always return false as it does not make an attempt to get the next value.

@codecov-commenter
Copy link

codecov-commenter commented Dec 4, 2023

Codecov Report

Attention: 156 lines in your changes are missing coverage. Please review.

Comparison is base (0d72338) 0.00% compared to head (cb65e75) 23.67%.

Files Patch % Lines
server_routers.go 57.26% 98 Missing and 5 partials ⚠️
server_dht.go 0.00% 41 Missing ⚠️
server.go 0.00% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##           main      #23       +/-   ##
=========================================
+ Coverage      0   23.67%   +23.67%     
=========================================
  Files         0        5        +5     
  Lines         0      583      +583     
=========================================
+ Hits          0      138      +138     
- Misses        0      440      +440     
- Partials      0        5        +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@hacdias hacdias force-pushed the parallel branch 2 times, most recently from 8cde154 to 1975da4 Compare December 4, 2023 11:47
- use WaitGroup and select for ctx.Done()
- call .Val right after .Next inside Goroutine
@hacdias
Copy link
Member Author

hacdias commented Dec 5, 2023

@aschmahmann I've added some tests. They're a bit more basic than the ones we have in https://github.com/libp2p/go-libp2p-routing-helpers, but they should cover enough for now. I think I addressed all the feedback.

I extracted the local storage to a separate issue to tackle in a different PR.

@hacdias
Copy link
Member Author

hacdias commented Jan 2, 2024

Ping @aschmahmann

@hacdias
Copy link
Member Author

hacdias commented Jan 12, 2024

new ping for @aschmahmann ;)

Copy link
Contributor

@aschmahmann aschmahmann left a comment

Choose a reason for hiding this comment

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

Apologies for the delay here @hacdias and thanks for the pings + callouts. Made a few relatively small comments but should be good to go otherwise.

If after the changes you're blocked for me on review just ask @Jorropo to review. I'd expect the changes here should be pretty small an easy for me to review though so he doesn't have to load context into the whole PR.

it, itErr := call(ri)

if itErr != nil {
err = errors.Join(err, itErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Fair, does that mean we should be doing some logging in the meanwhile as a sanity check around cid.contact errors?

Comment on lines 191 to 192
mi.done = true
mi.wg.Wait()
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like there might be a race here. For example: assume the context passed to newManyIter never gets cancelled, but:

  1. it.Next returns true in the newManyIter goroutine but the select statement hasn't finished yet
  2. The user calls it.Cancel
  3. The it.Cancel call is blocked on wg.Wait because it'll never be possible to read it.val into mi.ch

One way to fix this is to add a cancel func to the struct that's tied to the context (via context.WithCancel()) and call that before triggering the Wait.

@Jorropo
Copy link

Jorropo commented Jan 15, 2024

I'm missing something but it seems this code is duplicated from go-libp2p-routing-helpers, this is tricky code (I added a fair amount of deadlocks in go-libp2p-routing-helpers) I would rather squash bugs once there.

@hacdias
Copy link
Member Author

hacdias commented Jan 15, 2024

I'm missing something but it seems this code is duplicated

It isn't. It can't be used directly. I had to make many changes. It simpler in many ways. We've discussed this before - perhaps only in calls. It wasn't possible to reuse the libp2p router helpers.

I'm merging this as per @aschmahmann approval. We can iterate later.

@hacdias hacdias merged commit df191a3 into main Jan 15, 2024
4 checks passed
@hacdias hacdias deleted the parallel branch January 15, 2024 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants