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

Fix #629: Adding subscriptions is very slow #633

Closed
wants to merge 2 commits into from

Conversation

blankbro
Copy link

@blankbro blankbro commented Sep 24, 2021

refactor CTrie

@blankbro blankbro force-pushed the fix629_CNode-Performance branch 4 times, most recently from f4fae07 to 2d978f3 Compare August 18, 2022 11:59
Copy link
Collaborator

@andsel andsel left a comment

Choose a reason for hiding this comment

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

Hi @amzexin
the PR changes a lot the original data structure which was inspired on lock free algorithms on CTrie hash.
I would prefer a PR that only resolve the problem on the loop used in the insertion. The copy of constructor, and the copy in general shouldn't be a problem, as demonstrated by the CTrie hashmap. The copy and the presence of INode (indirect node) is fundamental for correct concurrent access to data structure.

@blankbro blankbro requested a review from andsel August 19, 2022 13:29
Copy link
Collaborator

@andsel andsel left a comment

Choose a reason for hiding this comment

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

Hi @amzexin
thank's for your contribution but, as I described in my previous comment, the changes you are proposing other then resolving the slow search loop also completely changes the spirit of the original data structure that was inspired by CTrie.
I'm happy to review a PR that just resolve the problem on the slow search loop replacing it hash lookup.

@blankbro
Copy link
Author

blankbro commented Aug 21, 2022

Hi @andsel
I tried to optimize CNode.copy, but it seems impossible. Because this itself may be a false proposition.

CAS is a good idea of concurrency lock-free, but it doesn't seem appropriate on CTrie. Because the original Set and List must be copied before adding a subscription or inode in CNode. Take an exaggerated example:if CNode has 1000000 Subscriptions, when we need to add the 1000001st subscription, we must copy these 1000000 Subscription first, then add 1 Subscription, then replace the original CNode by CAS, and when CTrie.insert returns Action.REPEAT, we need to do it again. And this will cause the project to start very slowly, because CTrieSubscriptionDirectory.init will call ctrie.addToTree method. CTrie added 620k Subscriptions need cost 85 minutes, this means that it takes 85 minutes for the project to start, which is very dreadful😱

InsertSubscription bottleneck reproduce: testCNodeCopyForInsertSubscription
AddChild bottleneck reproduce: testCNodeCopyForAddChild

Finally, I have a question. Ctrie must be lock-free? If the answer is yes, can you provide some optimization ideas for CNode.copy? I'm willing to try.

@blankbro blankbro requested a review from andsel August 21, 2022 05:44
@andsel
Copy link
Collaborator

andsel commented Aug 27, 2022

Hi @amzexin
about your questions:

Ctrie must be lock-free?

the answer is yes, because CTrie is accessed concurrently by the subscriber and publisher threads.

can you provide some optimization ideas for CNode.copy?

As was initially explained in this comment the slowness was related to the linear scan on insertion and not to the copy.
Do you have any measure if it's the copy to slow down the entire process?
As an idea to avoid the copy, we could use for children list a persistent data structure, like the one used in by functional languages, where any modification of the data structure create a new view of the data which contains only the changes. In that case we could avoid the need to copy the children array but just use the reference. Everytime we add or remove an element a new view is generated.

@hylkevds
Copy link
Collaborator

The immediate problem is the looping. This is especially bad because it also happens when matching subscriptions for a publish action. I think that needs to be fixed first. Hashtables are a possible solution, but simply sorting the array by token already improves things drastically. See my experiment in #630.

The copy is bad under high load, on large trees, since many failed inserts will happen, and many re-tries, and this will increase the load even further. A simple test should be made if adding a lock-on-update to the current code is faster under load than the current retry-until-success. Reading can remain lock-free that way.

@andsel
Copy link
Collaborator

andsel commented Jun 20, 2023

This is already fixed by #630, please @timeway could you check if it solves your issue and in case close the PR please 🙏 ?

@blankbro
Copy link
Author

blankbro commented Jun 21, 2023

This is already fixed by #630, please @timeway could you check if it solves your issue and in case close the PR please 🙏 ?

I use the latest code of the main branch and test it with the previous case, which is still very slow. This is my test case.

@hylkevds
Copy link
Collaborator

Indeed, this is yet another use-case. This one has few topics, but each topic has many subscribers.

@hylkevds
Copy link
Collaborator

In #758 I converted the HashSet to an ArrayList, since copying an array is much faster than copying a Set.

The test is still the slowest of the three (23 seconds), but it doesn't time out any more.

@andsel andsel closed this in #758 Jul 31, 2023
andsel pushed a commit that referenced this pull request Jul 31, 2023
Converted subscription from HashSet to ArrayList

Copying a Set is much slower than copying an ArrayList. Since the slow part in the code is the copy step, using an ArrayList is much faster overall. Since the code using the subscriptions only iterates over them, the change from Set to List makes no real difference.

Fixes #633
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.

3 participants