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

Correctly combine sorts in post view cursor-based pagination #4247

Merged
merged 10 commits into from
Dec 14, 2023

Conversation

dullbananas
Copy link
Collaborator

Fixes #4239

@dullbananas dullbananas marked this pull request as ready for review December 12, 2023 03:09
Copy link
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

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

@phiresky
Copy link
Collaborator

this is a bit complicated so i have to admit i couldn't understand if it's right at first glance

@dessalines
Copy link
Member

I'd say lets wait on this until after the release then... that post_view is already complicated enough without adding macros and that other complicated logic.

@dullbananas
Copy link
Collaborator Author

Keeping the incorrect implementation in the final release would be very bad because it could hide some posts from moderators

@dullbananas
Copy link
Collaborator Author

Also, in a comment on the post about using 0.19 on lemmy.ml, someone said "Ever since the upgrade, lemmy feels dead" which might be caused by this bug making recent posts unlikely to appear (because of the 3rd published time sort) unless either New sort type is being used or enough people using old pagination are discovering and upvoting them to make them more likely to appear with the incorrect cursor-based pagination

@dessalines
Copy link
Member

I'm not against merging then, but I'd need to get another RC out to make sure this doesn't slow down anything, before we do the release. cc @phiresky

query = query.filter(column.le(getter(&after.0)));
}
query
#[derive(Clone, Copy)]
Copy link
Member

Choose a reason for hiding this comment

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

This would benefit from deriving Debug, PartialEq, and Eq as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

@phiresky phiresky left a comment

Choose a reason for hiding this comment

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

It's a shame that diesel doesn't support tuple comparison. That would make this much simpler and easy to see that the performance is still fine. The discussion of that feature is here: diesel-rs/diesel#3750

So this approach is the workaround for not being able to simply do WHERE (a,b) < ('foo', 123).

So trying to understand this: Instead of doing (a,b,c)>=(cursora,cursorb,cursorc).

the resulting filter is: (a >= cursora) AND (b >= cursorb OR a != cursora) AND (c >= cursorc OR a != cursora OR b != cursorb).

Which is confusing but seems to make sense. Easier to understand for me would be
a >= cursora OR (a = cursora AND b >= cursorb) OR (a = cursora AND b = cursorb AND c >= cursorc).

Here's three posts about the approach implemented here:

So it does seem like a fairly common solution.

I couldn't find any info about whether Postgresql is able to optimize this or not though which may make it unviable... tbh I doubt it can figure out all those ORs.

Another alternative would probably be to use diesel raw sql. That should look something like

query = query.filter(
   sql::<Bool>("(featured_local, hot_rank, published) >= (")
   .bind::<Bool,_>(cursor.featured_local)
   .sql(", ")
   .bind::<Double,_>(cursor.hot_rank)
   .sql(", ")
   .bind::<Timestamptz,_>(cursor.published)
   .sql(")")
)

It's disgusting but I think that might be better than this... and has pretty much guarantee that PG optimizes it correctly since it's 1:1 a slice of the corresponding index.
What do you think @dullbananas ?

@phiresky
Copy link
Collaborator

It would actually not be that different from this PR, just that loop would be replaced and the macros could be removed (i think)

@dullbananas
Copy link
Collaborator Author

I will try to make it work using tuple comparisons. DESC doesn't work for comparisons, so I guess I would need to negate the descending columns and do the same thing in each index.

I will do it in a separate PR so @dessalines can choose to either wait for it to be done or use the implementation in this PR for now.

@phiresky
Copy link
Collaborator

right, I didn't think about mixed asc and desc :(

@dessalines dessalines merged commit 32afc32 into LemmyNet:main Dec 14, 2023
1 check passed
@dessalines
Copy link
Member

I spose since we're in a rush to get a release out, I'll merge this so we can test it in a release candidate, but ya do work on the alternate version.

@dessalines
Copy link
Member

I've got this deployed into 0.19.0-rc.16, and on lemmy.ml, so we have some time to see how its working.

@Nutomic
Copy link
Member

Nutomic commented Dec 15, 2023

@dullbananas Even though this is merged, it would still be good if you can make a PR to change this to tuple comparisons instead of macros. That way it should be much easier to maintain.

@dullbananas
Copy link
Collaborator Author

dullbananas commented Dec 15, 2023

I will try to make a library that would allow the post view to do order and pagination with very simple method calls on a struct that wraps the query. You're gonna love it.

Because of the need for the negation hack for mixed sorting directions, I will avoid using tuple comparison in the implementation unless it's necessary for a good query plan. And if tuple comparison is needed, then I will check whether or not indexes need to be changed. (Edit: it could also just use tuple comparison for parts of the sort that have the same sorting direction.)

I can probably also implement backwards pagination.

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.

Current implementation of post view cursor pagination probably prevents some posts from appearing
5 participants