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 pagination and timeout to commitments and ack queries #4110

Merged
merged 8 commits into from
Aug 12, 2024

Conversation

ljoss17
Copy link
Contributor

@ljoss17 ljoss17 commented Jul 31, 2024

Closes: #4101

Description


PR author checklist:

  • Added changelog entry, using unclog.
  • Added tests: integration (for Hermes) or unit/mock tests (for modules).
  • Linked to GitHub issue.
  • Updated code comments and documentation (e.g., docs/).
  • Tagged one reviewer who will be the one responsible for shepherding this PR.

Reviewer checklist:

  • Reviewed Files changed in the GitHub PR explorer.
  • Manually tested (in case integration/unit/mock tests are absent).

@ljoss17 ljoss17 requested a review from romac August 2, 2024 12:06
@ljoss17 ljoss17 marked this pull request as ready for review August 2, 2024 12:08
Comment on lines 1 to 2
- Implemented pagination for `query_packet_commitments` and `query_packet_acknowledgements`
during the scanning phase to optimize the determination of whether to spawn a packet worker.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- Implemented pagination for `query_packet_commitments` and `query_packet_acknowledgements`
during the scanning phase to optimize the determination of whether to spawn a packet worker.
- Paginate results of `query_packet_commitments` and `query_packet_acknowledgements`
queries to speed up the scanning phase.

@@ -1,6 +1,7 @@
use core::fmt;

use abscissa_core::clap::Parser;
use ibc_relayer::chain::requests::Paginate;
Copy link
Member

Choose a reason for hiding this comment

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

Let's move this in the import group below.

.and_then(|raw_height| raw_height.try_into().ok())
.ok_or_else(|| Error::grpc_response_param("height".to_string()))?;
let mut tonic_request = tonic::Request::new(raw_request);
tonic_request.set_timeout(Duration::from_secs(10));
Copy link
Member

Choose a reason for hiding this comment

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

Just a note for us that we should eventually make this either:
a) Configurable (eg. grpc_timeout setting)
b) Inferred from the pagination, ie. use larger timeout for Paginate::All and smaller one otherwise


let responses =
results.into_iter().collect::<Result<
Vec<ibc_proto::ibc::core::channel::v1::QueryPacketCommitmentsResponse>,
Copy link
Member

Choose a reason for hiding this comment

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

Can't the inner type be elided here?

Suggested change
Vec<ibc_proto::ibc::core::channel::v1::QueryPacketCommitmentsResponse>,
Vec<_>,

.map(|v| v.sequence.into())
.collect();
let mut tonic_request = tonic::Request::new(raw_request);
tonic_request.set_timeout(Duration::from_secs(10));
Copy link
Member

Choose a reason for hiding this comment

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

Same here

}

let responses = results.into_iter().collect::<Result<
Vec<ibc_proto::ibc::core::channel::v1::QueryPacketAcknowledgementsResponse>,
Copy link
Member

Choose a reason for hiding this comment

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

Same here

) -> Result<Option<(Vec<Sequence>, Height)>, Error> {
let (commitments_on_src, _) = commitments_on_chain(chain, &path.port_id, &path.channel_id)?;
let (commitments_on_src, _) =
commitments_on_chain(chain, &path.port_id, &path.channel_id, pagination.clone())?;
Copy link
Member

Choose a reason for hiding this comment

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

Paginate can be made Copy:

Suggested change
commitments_on_chain(chain, &path.port_id, &path.channel_id, pagination.clone())?;
commitments_on_chain(chain, &path.port_id, &path.channel_id, pagination)?;

Comment on lines 158 to 165
if let Paginate::PerPage {
pagination: _,
limit,
} = self
{
return *limit;
}
0
Copy link
Member

Choose a reason for hiding this comment

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

A simple match would look more idiomatic here

Comment on lines 171 to 177
match value {
Paginate::All => PageRequest::all(),
Paginate::PerPage {
pagination: _,
limit,
} => PageRequest::per_page(limit),
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
match value {
Paginate::All => PageRequest::all(),
Paginate::PerPage {
pagination: _,
limit,
} => PageRequest::per_page(limit),
}
match value {
Paginate::All => PageRequest::all(),
Paginate::PerPage { limit, .. } => PageRequest::per_page(limit),
}

All,

PerPage {
pagination: u64,
Copy link
Member

@romac romac Aug 7, 2024

Choose a reason for hiding this comment

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

Is this field ever used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a mistake in when converting to the PageRequest. The pagination should be the limit, number of results, and limit should be the number of times the query is done. I will update this code

} => PageRequest::per_page(limit),
to use pagination

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 will rename to:

    PerPage {
        limit: u64,
        max_queries: u64,
    },

Copy link
Member

@romac romac Aug 7, 2024

Choose a reason for hiding this comment

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

imho it should contain two fields: one which specifies how many results per page we want and one which specifies how many results in total we want.

Copy link
Member

Choose a reason for hiding this comment

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

So maybe per_page: u64 and total: u64?

Copy link
Member

Choose a reason for hiding this comment

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

then we can just stop issuing queries once we either a) have total results or b) there is no more next page/key

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 I had it set to one field for how many results per page and another one for the maximum number of queries. I will change to the option you suggested

.map_err(Error::grpc_transport)?;

client = client
.max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize);
if request.pagination.is_enabled() {
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 are dealing with pagination in two queries, and are duplicating a bunch of fairly complex code, how about extracting the pagination logic in a standalone function we can use in both places?

async fn paginate<C, Req, Res, F>(
    mut client: C,
    request: Req,
    mut do_query: impl FnMut(&mut C, Req, Vec<u8>) -> F,
    get_next_key: impl Fn(&Res) -> Option<Vec<u8>>,
) -> Vec<Result<Res, Error>>
where
    F: Future<Output = Result<Res, Error>> + 'static,
    Req: Clone,
{
    let mut results = vec![];
    let mut page_key = vec![];

    loop {
        let response =
            do_query(&mut client, request.clone(), std::mem::take(&mut page_key)).await;

        match response {
            Ok(response) => {
                let next_key = get_next_key(&response);

                results.push(Ok(response));

                match next_key {
                    Some(next_key) if !next_key.is_empty() => {
                        page_key = next_key;
                    }
                    _ => break,
                }
            }
            Err(e) => {
                results.push(Err(e));
                break;
            }
        }
    }

    results
}

Copy link
Member

Choose a reason for hiding this comment

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

We can leave this for a follow-up PR, or when we add pagination to yet another query.

@ljoss17
Copy link
Contributor Author

ljoss17 commented Aug 7, 2024

Applied the suggestions in this commit d048aff.
And opened this issue to follow-up on the paginate method abstraction #4135

@ljoss17 ljoss17 added this pull request to the merge queue Aug 12, 2024
Merged via the queue into master with commit e099709 Aug 12, 2024
31 checks passed
@ljoss17 ljoss17 deleted the luca_joss/add-pagination-to-queries branch August 12, 2024 06:47
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.

Something blocking Hermes from properly starting up and spinning up workers
2 participants