-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Working on caching and tokens #4001
Conversation
As a reminder JObject and then Entity is not thread safe. So e.g this is not thread safe to mutate the Update: and idem for all other fields whose assignment are not thread safe, this for object that are cached and shared at the tenant level and that can be mutated. I will need some cloning, immutable collections ... as done in #3930 for |
Came back too late to make some progress so i just added some comments. So i try to use the following rules but i still have a little concern with point 2.
In point 2., when cancelling the token after storing data, another thread may get a new valid token and read data that are not yet updated. Maybe that's why before we were also updating the cache here, but this would not solve the problem in a distributed env and i prefer to always update the cahe with the actual persisted data, e.g by reading again the database. So, at some point i added a So, when a token is tied to data persisted in the database, one idea would be to have a token signal that is only sent at the end of the scope and executed after the session is commited. Knowing that now we can easily register a Update: okay seems to work well with the following, beautiful ;)
|
So, here the main goal was to update services that were already using local caches and signal tokens so that we will be able to keep them in sync by using a distributed signal service. I didn't change here the other services that will need some adaptations but that don't already use the signal service, we will see when re-working on distibuted services. E.g Update: Better to 1st merge #3930 before finalizing and then merging this one. E.g in #3930 there is a more complete version of |
# Conflicts: # src/OrchardCore.Modules/OrchardCore.HomeRoute/HomePageRoute.cs # src/OrchardCore/OrchardCore.Abstractions/ISignal.cs
# Conflicts: # src/OrchardCore.Modules/OrchardCore.Settings/Services/SiteService.cs
public IList<string> RoleNames { get; set; } = new List<string>(); | ||
public IList<UserClaim> UserClaims { get; set; } = new List<UserClaim>(); | ||
public IList<UserLoginInfo> LoginInfos { get; set; } = new List<UserLoginInfo>(); | ||
public ImmutableArray<string> RoleNames { get; set; } = ImmutableArray<string>.Empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? Is a User object used in concurrent threads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As i remember, there are some places where we mutate it and i checked that we act on a same shared instance.
Let me some time to retrieve an example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g in UserStore.AddToRoleAsync()
line 332
((User)user).RoleNames.Add(roleName);
That becomes here
((User)user).RoleNames = ((User)user).RoleNames.Add(roleName);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But only one thread accesses this user instance, so the list is thread-safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes normally but just tried 2 concurrent editing (by using a break point) of the same user, i could see that the 2 concurrent thread are mutating the same user instance and then its roles collection.
The other problem is when we are using / enumerating on e.g roleNames while mutating it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. Where are we mutating and iterating at the same time, if not on two different thread.
just tried 2 concurrent editing
This is worrying. Can you explain how that happens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UserManager
is scoped, it resolves UserStore
which is scoped too, which uses Session
to load a user. In the end I don't understand how two thread would access the same user instance, unless we have some wrong parallel code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay let me check again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, just retried, you're right there are 2 different instances, i don't know what i did, maybe too tired ;) These were some of the last changes i did as for others singletons and without doing the above test, indeed there are all scoped services, i'm stupid.
Thanks, i will revert all the changes around user and roles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, i don't know why i did here the same changes as for other services but using a singleton cache.
Sorry, i reverted the changes related to users and roles.
@sebastienros for infos Okay when a GET is done before a LOAD in the same scope, in the GET for caching we do a session So i did an This is useful particularly for the I already used this heper but right now only for the |
# Conflicts: # src/OrchardCore.Build/Dependencies.props
Close and reopen to restart appveyor building |
Reopen to restart appveyor building |
@sebastienros i'm ready with this one, for the types / parts definitions i tried it with both file and database definition stores. If going to be merged, would be good to do it in pair with #4164. |
# Conflicts: # src/OrchardCore.Modules/OrchardCore.Queries/Drivers/QueryDisplayDriver.cs # src/OrchardCore.Modules/OrchardCore.Templates/Models/TemplatesDocument.cs
No description provided.