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

Add addresses field for closing listeners #1485

Merged
merged 5 commits into from
Mar 23, 2020

Conversation

tcharding
Copy link
Contributor

@tcharding tcharding commented Mar 9, 2020

We would like to be able expire addresses when a listener closes.

Add an addresses field to the ListenersEvent and the ListenerClosed to hold the addresses of a listener that has just closed. When we return a ListenerClosed network event, loop over the addresses and call inject_expired_listen_address() on each one.

Fixes: #1482

@tomaka
Copy link
Member

tomaka commented Mar 9, 2020

Our code isn't formatted with rustfmt, so please remove the first commit!

@tcharding
Copy link
Contributor Author

tcharding commented Mar 9, 2020

Our code isn't formatted with rustfmt, so please remove the first commit!

Oh, that would explain the indentation for your macro_use! blocks (which is super nice).

Will change my editor setup to match you project and submit non-draft PR :)

Thanks @tomaka

@tcharding
Copy link
Contributor Author

Our code isn't formatted with rustfmt

I see you guys use .editorconfig instead. In order to educate myself; what is the reason behind using this instead of rustfmt please?

Add an addresses field to the ListenersEvent and the ListenerClosed to
hold the addresses of a listener that has just closed. When we return a
ListenerClosed network event loop over the addresses and call
inject_expired_listen_address on each one.

Fixes: libp2p#1482
@tcharding tcharding marked this pull request as ready for review March 9, 2020 22:03
@tcharding
Copy link
Contributor Author

FTR, I did not configure my editor to use .editorconfig. If CI fails (and before patching this repo again) I will invest the time to do so.

@tcharding
Copy link
Contributor Author

I'm not sure how to proceed with the CI integration test failure.

@tcharding
Copy link
Contributor Author

Researching further, rustfmt - is there a reason libp2p does not use rustfmt.toml to get a formatting style we like?

Discussed here: https://www.reddit.com/r/rust/comments/9jl6a9/pro_tip_if_you_use_cargo_fmtrustfmt_use_a/

@mxinden
Copy link
Member

mxinden commented Mar 10, 2020

I'm not sure how to proceed with the CI integration test failure.

As far as I can tell this is unrelated to your patch set. (See #1323.)

In order to educate myself; what is the reason behind using this instead of rustfmt please?

You might find some answers in #1164 and the resources linked within.

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

This looks good to me, but I would like @tomaka or some other maintainer to take another look.

@mxinden
Copy link
Member

mxinden commented Mar 10, 2020

Retriggered the tests. All green now.

@@ -148,6 +148,8 @@ where
Closed {
/// The ID of the listener that closed.
listener_id: ListenerId,
/// The addresses that the listener was listening on.
addresses: SmallVec<[Multiaddr; 4]>,
Copy link
Member

Choose a reason for hiding this comment

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

This is a nit, but I'd rather go with Vec in order to not expose a third-party dependency in our API.
Alternatively, a custom iterator type that wraps around smallvec::IntoIter would work as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries, will fix and re-spin. Thanks.

@@ -283,12 +285,14 @@ where
Poll::Ready(None) => {
return Poll::Ready(ListenersEvent::Closed {
listener_id: *listener_project.id,
addresses: listener.addresses.clone(),
Copy link
Member

Choose a reason for hiding this comment

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

Since we're destroying the listener, you don't need to clone.

Suggested change
addresses: listener.addresses.clone(),
addresses: mem::replace(listener.addresses, SmallVec::new()),

(or, for Vec, listener.addresses.drain(..).collect())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I went with a Vec and used the SmallVec method to_vec() for the conversion.

@@ -55,6 +56,8 @@ where
ListenerClosed {
/// The listener ID that closed.
listener_id: ListenerId,
/// The addresses that the listener was listening on.
addresses: SmallVec<[Multiaddr; 4]>,
Copy link
Member

Choose a reason for hiding this comment

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

Same remark

In order to not expose a third party dependency in our API use a `Vec`
type for the addresses list instead of a `SmallVec`.
@tcharding
Copy link
Contributor Author

Whats the rust-libp2p projects protocol on squashing/rebasing of PRs? Would you prefer the second commit (added after review) to be squashed into the first or left as it is? Thanks for the reviews.

@mxinden
Copy link
Member

mxinden commented Mar 11, 2020

Whats the rust-libp2p projects protocol on squashing/rebasing of PRs? Would you prefer the second commit (added after review) to be squashed into the first or left as it is? Thanks for the reviews.

@tcharding no action required from your side. We use Github's Squash and merge feature.

@@ -283,12 +285,14 @@ where
Poll::Ready(None) => {
return Poll::Ready(ListenersEvent::Closed {
listener_id: *listener_project.id,
addresses: listener.addresses.to_vec(),
Copy link
Member

Choose a reason for hiding this comment

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

It's still cloning the content of the container, which is what I was trying to avoid with my suggestion.

Suggested change
addresses: listener.addresses.to_vec(),
addresses: listener.addresses.drain(..).collect(),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Its hard to get good help :) I did try your suggestion but it didn't seem to work. Will explore further. Thanks

Copy link
Contributor Author

@tcharding tcharding Mar 11, 2020

Choose a reason for hiding this comment

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

I've had a bit more of a play with it. Please correct me if I'm wrong but it seems we cannot get a mutable reference to listener (needed if we want to drain addresses) because we have already taken a mutable reference. We would need the following code to be possible (I think, open to correction):

    /// Provides an API similar to `Stream`, except that it cannot end.
    pub fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<ListenersEvent<TTrans>> {
        let mut remaining = self.listeners.len();
        while let Some(mut listener) = self.listeners.pop_back() {
            let mut listener_project = listener.as_mut().project();
            let mut addresses = listener.as_mut().addresses;

This is clearly not possible. Am I missing something, is there another way to do this?

Copy link
Member

Choose a reason for hiding this comment

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

Ah sorry, you just have to use listener_project

Suggested change
addresses: listener.addresses.to_vec(),
addresses: listener_project.addresses.drain(..).collect(),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool, thanks. I learned (a little bit) about pin_project, seems I still have a lot to learn about pinning :) Thanks for your patient revies @tomaka. One final thing, just to make sure, are you happy with the remaining usage of SmallVec in connection/listener.rs introduced in this PR?

Closed {
         /// The ID of the listener that closed.
         listener_id: ListenerId,
+        /// The addresses that the listener was listening on.
+        addresses: SmallVec<[Multiaddr; 4]>,

And, since I'm new and its good to start on the right foot; can you please confirm that the typical pre-PR-push tasks you would expect to pass are only:

  • cargo build
  • cargo test

(i.e., no clippy, no e2e tests etc)

Thanks,
Tobin.

Copy link
Member

Choose a reason for hiding this comment

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

are you happy with the remaining usage of SmallVec in connection/listener.rs introduced in this PR?

Ah! No, I missed that. Please turn that into a Vec as well.

There are more tests than cargo test, but running cargo test locally is good enough before opening a PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I think we are getting dangerously close to a mergeable PR :)

Copy link
Member

Choose a reason for hiding this comment

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

Wait. Please revert that last change. Having SmallVec in a private field is good.
(you mentioned "introduced in this PR", but your PR didn't touch this.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh boy, you are right. I hope you meant 'revert' figuratively, I removed last patch and force pushed. Thanks for your patience.

core/src/connection/listeners.rs Outdated Show resolved Hide resolved
We would like to avoid clones where possible for efficiency reasons.
When returning a `ListenersEvent::Closed` we are already consuming the
listener (by way of a pin projection).  We can therefore use a consuming
iterator instead of cloning.

Use `drain(..).collect()` instead of clone to consume the addresses when
returning a `ListenersEvent::Closed`.
Copy link
Member

@tomaka tomaka left a comment

Choose a reason for hiding this comment

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

Should be good for merge after that

Comment on lines +451 to +453
for addr in addresses.iter() {
this.behaviour.inject_expired_listen_addr(addr);
}
Copy link
Member

Choose a reason for hiding this comment

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

One last change: could you move this above inject_listener_closed?
The listener and its addresses technically expire at the same time, but since here we have to pick an order, it makes more sense that the addresses expire before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries, done!

tcharding and others added 2 commits March 20, 2020 08:42
The listener and its addresses technically expire at the same time, but
since here we have to pick an order, it makes more sense that the
addresses expire first.
@tomaka tomaka merged commit 7bf5266 into libp2p:master Mar 23, 2020
@tcharding tcharding deleted the add-addresses branch March 23, 2020 20:47
folex added a commit to fluencelabs/rust-libp2p that referenced this pull request Mar 30, 2020
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.

Expire listening addresses if a listener is closed
3 participants