-
Notifications
You must be signed in to change notification settings - Fork 27
Optimize Tracking: convert ChangedValue & TrackingStackFrame to readonly structs #249
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
Optimize Tracking: convert ChangedValue & TrackingStackFrame to readonly structs #249
Conversation
"00240000048000009400000006020000002400005253413100040000010001007f8790a0573a2a" + | ||
"4f7b77907240977b669d33774bcaef77ef39d5186de4d4c836623fb661be674c7db731bc376184" + | ||
"f6848fc6b64eeba506654c8212de624e9d1f15ad1fe765f769e9a5b59ecaab2866632a983e7828" + | ||
"f3bf20ff7afffa021951cf8adc9ac1e786716430b0637893fb71b7566405fe14acc5e340c4af4a" + | ||
"a293c994")] |
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.
Extensions should not rely on internal members and should not be in friendly assemblies
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.
Even providers have no access to internals
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.
The alternative is to make DirectSessionAccessor.GetChangedEntitiesInternal()
public
IMO it is better to move some extensions into main Xtensive.Orm
project.
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.
IMO it is better to move some extensions into main Xtensive.Orm project.
Why? What is the criteria for this movement?
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? What is the criteria for this movement?
In this case GetChangedEntitiesInternal()
optimization.
But in general integration of stable extensions into main project simplifies using DO.
Then we need to reference only 2 packages from the app: Orm + DB driver (SqlServer or other)
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.
The idea of extension is that it is optional one-purpose package, if you need it then you install it, otherwise you don't. You look at this from your perspective when you 100% use it. That's biased opinion.
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.
The idea of extension is that it is optional one-purpose package, if you need it then you install it, otherwise you don't.
The same idea as for any function or class.
This Xtensive.Orm.Tracking.dll
extension is just 16KB of binary. Not a big deal if the main package will be 16KB bigger and we avoid all installation efforts.
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.
I have changed implementation to use conditional compilation:
public IEnumerable<EntityState> GetChangedEntities(PersistenceState persistenceState) =>
#if DO_SAFE_COLLECTION_WRAPPER
Session.EntityChangeRegistry.GetItems(persistenceState);
#else
Session.EntityChangeRegistry.GetContainer(persistenceState);
#endif
This allows to have safe implementation for public DO package and the optimized for ourown build (depending on environment variable)
And we need not visibility-attributes and internal method anymore
We can apply this approach to other places where we create unnecessary ReadOnly-wrappers
So you want to return the original HashSet but don't want public API to have an opportunity to change HashSet by just casting it to the original type, right? What if we returned IReadOnlyCollection and also made sure that it was not a pure HashSet but lightweight wrapper which implements IReadOnlyCollection? |
Yes
Lightweight wrapper is not better than additional |
Well, everything has allocation price otherwise we would be C++ing :) that doesn't mean we should expose everything. I'll check the performance losses and allocations. |
Some update on performance of
I did one enumeration of 100 items per case
Summary: current enumeration via I also assume that results of The struct I used for benchmarks
|
Thank you for benchmarking. |
I didn't choose great name, I needed some name for benchmarking and it was good enough for it :) It was just a proof-of-concept.
I agree, GetItemsWithStructAsInterface shows this clearly, returning interface basically doubles execution time or even worse
Yes, I thought about this. Here's my point, highly likely that the result of GetItems will be enumerated right after caller have got it, we already enumerate them everywhere, but my main concern is users' code base, they can start caching results, though it is pointless (we clear internal hashsets in certain scenarios like session disposal, persist of changes, etc.). I took a wider view and I saw that we have three registries with similar GetItems() methods - |
I'm going to make the changes for registries' After I merge my PR to master you'll need to revert commit af4427e, especially visibility changes. |
Ok. Looks to be not a big deal |
I have merged the #283 with registry changes |
This reverts commit af4427e.
No description provided.