Drop unused statuses/uses from frontend state so they can be garbage collected #581

Open
opened 2019-06-16 19:10:58 +00:00 by lambadalambda · 16 comments

At the moment, we keep all users and all statuses ever seen in the vuex state. For users that should be alright, but for statuses this will lead to ever growing memory requirements, essentially wasting more memory the longer you keep it open. We should drop references for statuses that are not longer needed or can easily be refetched.

At the moment, we keep all users and all statuses ever seen in the vuex state. For users that should be alright, but for statuses this will lead to ever growing memory requirements, essentially wasting more memory the longer you keep it open. We should drop references for statuses that are not longer needed or can easily be refetched.
Member

@lambadalambda is there an api to fetch some posts by their ids, preferably to for FE to supply list of IDs and BE reply with list of posts with these IDs?

@lambadalambda is there an api to fetch some posts by their ids, preferably to for FE to supply list of IDs and BE reply with list of posts with these IDs?
Member

Maybe this could go together with virtual scrolling #284

Maybe this could go together with virtual scrolling #284
Author
Owner

Sure, there's the usual status api at https://docs.joinmastodon.org/api/rest/statuses/#get-api-v1-statuses-id. This will only return one status for now.

Usually, it should be safe to drop all statuses that are not currently displayed as they should be refetched by the currently existing means (like timelines, status get, conversation...), so I don't think a new API will be needed. We can add something though, if it's necessary.

Sure, there's the usual status api at https://docs.joinmastodon.org/api/rest/statuses/#get-api-v1-statuses-id. This will only return one status for now. Usually, it should be safe to drop all statuses that are not currently displayed as they should be refetched by the currently existing means (like timelines, status get, conversation...), so I don't think a new API will be needed. We can add something though, if it's necessary.
Member

I mean, FE doesn't exactly knows which statuses are displayed and which are not, there are also some statuses that are not displayed but should propably remain in cache - recently opened threads, posts replied to, maybe some other cases.

As architecture currently stands at most parts store has very little knowledge about context of where post is show, so right now I can only see some sort of actual java-style GC being implemented.

My biggest concern would be that since we don't have context for posts, there could be situation where GC could remove like 50 oldest statuses from Home TL and when user tries to get to them back FE would be like "oh shit i need posts 12314, 12310, 12290, 12287, 12253, 11001" and proceed to request them separately instead of "oh shit maybe i need to fetch home tl pages 5 and 6" or something like that.

I mean, FE doesn't exactly knows which statuses are displayed and which are not, there are also some statuses that are not displayed but should propably remain in cache - recently opened threads, posts replied to, maybe some other cases. As architecture currently stands at most parts store has very little knowledge about context of where post is show, so right now I can only see some sort of actual java-style GC being implemented. My biggest concern would be that since we don't have context for posts, there could be situation where GC could remove like 50 oldest statuses from Home TL and when user tries to get to them back FE would be like "oh shit i need posts 12314, 12310, 12290, 12287, 12253, 11001" and proceed to request them separately instead of "oh shit maybe i need to fetch home tl pages 5 and 6" or something like that.
Member

Pleroma.js-framework when?

Pleroma.js-framework when?
Member

?

?
Owner

Virtual scrolling impossible with dynamically resizing elements: inline thread expansion, sliding user profile panel, etc

Virtual scrolling impossible with dynamically resizing elements: inline thread expansion, sliding user profile panel, etc
Member

@hj I am thinking about having the user take the same action that they did in the first place to get to the viewable status.

For example, if they scroll down through the timeline all of the statuses will be shown. When they scroll back up they will be shown to a limit. The statuses will be removed from the timeline and other status objects at that limit.

To see more again they would need to scroll back down and the timeline pages will be reloaded from where they were removed.

if the limit was 100: 100 objects -> scroll down 120 -> scroll down again 140 -> scroll up remove to 120 -> scroll up remove to 100 -> scroll down again, show 120 as if it was their first time.

This seems to be a start. They will no longer have an extra 40 objects to store.

For a GC implementation we would need to tag the objects for lastViewed and maybe remove old ones that have not been viewed recently. Any other ideas around how it would determine unused statuses would be great :)

@hj I am thinking about having the user take the same action that they did in the first place to get to the viewable status. For example, if they scroll down through the timeline all of the statuses will be shown. When they scroll back up they will be shown to a limit. The statuses will be removed from the timeline and other status objects at that limit. To see more again they would need to scroll back down and the timeline pages will be reloaded from where they were removed. if the limit was 100: 100 objects -> scroll down 120 -> scroll down again 140 -> scroll up remove to 120 -> scroll up remove to 100 -> scroll down again, show 120 as if it was their first time. This seems to be a start. They will no longer have an extra 40 objects to store. For a GC implementation we would need to tag the objects for lastViewed and maybe remove old ones that have not been viewed recently. Any other ideas around how it would determine unused statuses would be great :)
Member

not entirely, you can have it with dynamically resizing elements as long as it's controlled.

not entirely, you can have it with dynamically resizing elements as long as it's controlled.
Member
  1. visibility range should extend at least half a screen above and half a screen below, maybe even whole screen, so that all the loading is done out of sight.
  2. Every post must have a reference/visibility counter - same post from 50 pages ago might be still visible at the top of notifications column. In addition to that - every post has a reply-to hover popup which also should contribute to visibility counter, this also applies to reverse-replies - the "Replies: #2 #3" also has popups which also should contribute to visibility counter.
  3. If visibility counter reaches zero post should be replaced with an empty shell of it either immediately or during a periodic GC swoop.
  4. When I say counter I really mean each post should probably have an object like { visible: true, notification: false, isReplyTo: true, isReplyFor: true } with "counter" part being amount of "trues" - this would ease the development and debugging.
  5. The biggest issue probably would be the actual marking as visible/invisible, as well as using efficient structures and algorithms so that we get a net profit, not trade memory usage for CPU usage.
  6. Well, of course and loading posts back from server, which should probably be batched together, i.e. when element enters "visibility range" it most likely doesn't enter it alone, so making 1 big request for 10 posts is much much better and efficient than DDoSing server for each and every post.
  7. To insult the injury of point 6 - requests to bring back may fail and there should be a way in UI to manually retry them.
1. visibility range should extend at least half a screen above and half a screen below, maybe even whole screen, so that all the loading is done out of sight. 2. Every post must have a reference/visibility counter - same post from 50 pages ago might be still visible at the top of notifications column. In addition to that - every post has a reply-to hover popup which also should contribute to visibility counter, this also applies to reverse-replies - the "Replies: #<span></span>2 #<span></span>3" also has popups which also should contribute to visibility counter. 3. If visibility counter reaches zero post should be replaced with an empty shell of it either immediately or during a periodic GC swoop. 4. When I say counter I really mean each post should probably have an object like `{ visible: true, notification: false, isReplyTo: true, isReplyFor: true }` with "counter" part being amount of "trues" - this would ease the development and debugging. 5. The biggest issue probably would be the actual marking as visible/invisible, as well as using efficient structures and algorithms so that we get a net profit, not trade memory usage for CPU usage. 6. Well, of course and loading posts back from server, which should probably be batched together, i.e. when element enters "visibility range" it most likely doesn't enter it alone, so making 1 big request for 10 posts is much much better and efficient than DDoSing server for each and every post. 7. To insult the injury of point 6 - requests to bring back may fail and there should be a way in UI to manually retry them.
Member

Good information!

Intersection Observer works on most modern browsers. There is a way to get it working on older browsers too.

https://www.w3.org/TR/intersection-observer/

When a post is within view we can update when that occurred. I am thinking to use this as the basis to determine GC.

6 & 7. above are tough ones.
Batch remove and batch add is where I may start, like my comment above.

Good information! Intersection Observer works on most modern browsers. There is a way to get it working on older browsers too. https://www.w3.org/TR/intersection-observer/ When a post is within view we can update when that occurred. I am thinking to use this as the basis to determine GC. 6 & 7. above are tough ones. Batch remove and batch add is where I may start, like my comment above.
Member

IntersectionObserver isn't exactly supported everywhere (looking at IE and certain mobile browsers) so probably should only enable GC for browsers that support it.

IntersectionObserver isn't exactly [supported](https://caniuse.com/#feat=intersectionobserver) everywhere (looking at IE and certain mobile browsers) so probably should only enable GC for browsers that support it.
Member

There is a Polyfill for older browsers that can be turned on:
https://github.com/w3c/IntersectionObserver/tree/master/polyfill

Support as of now:
https://caniuse.com/#feat=intersectionobserver

There is a Polyfill for older browsers that can be turned on: https://github.com/w3c/IntersectionObserver/tree/master/polyfill Support as of now: https://caniuse.com/#feat=intersectionobserver
Member

I would rather disable GC than use limited and potentially buggy polyfill.

I would rather disable GC than use limited and potentially buggy polyfill.
Member

Did a push for checking

Did a push for checking
Member

@lambadalambda I am currently removing old statuses from the timeline that have not been viewed recently. They are put back when the user scrolls back down to view them via the normal method.

If the user keeps scrolling down (maybe forever) and I remove the un-viewed statuses from the top of the timeline, it gets a bit more complicated. I am collecting the ids of the removed statuses;
would need to reverse keep track of the max and min ids and call them 20 at a time as they scroll back up. Deleted may not be in order because it is dependent on what the user is currently viewing.

In this case it would be great to have an endpoint that allows me to batch call with these ids. It would greatly simplify the process to get the removed ids back into the timeline.

@lambadalambda I am currently removing old statuses from the timeline that have not been viewed recently. They are put back when the user scrolls back down to view them via the normal method. If the user keeps scrolling down (maybe forever) and I remove the un-viewed statuses from the top of the timeline, it gets a bit more complicated. I am collecting the ids of the removed statuses; would need to reverse keep track of the max and min ids and call them 20 at a time as they scroll back up. Deleted may not be in order because it is dependent on what the user is currently viewing. In this case it would be great to have an endpoint that allows me to batch call with these ids. It would greatly simplify the process to get the removed ids back into the timeline.
Sign in to join this conversation.
No milestone
No project
No assignees
5 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pleroma/pleroma-fe#581
No description provided.