Skip to content

Lazy SQL generation for SelectLockingStrategy #1702

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

Closed
wants to merge 2 commits into from

Conversation

bahusoid
Copy link
Member

I believe most of those lock statements are never used in most apps but we generate them for each lock mode:

protected internal virtual void InitLockers()
{
lockers[LockMode.Read] = GenerateLocker(LockMode.Read);
lockers[LockMode.Upgrade] = GenerateLocker(LockMode.Upgrade);
lockers[LockMode.UpgradeNoWait] = GenerateLocker(LockMode.UpgradeNoWait);
lockers[LockMode.Force] = GenerateLocker(LockMode.Force);
}

So let's not waste memory unless it's really requested.

}

private SqlString Sql => sql ?? (sql = GenerateLockString());
Copy link
Member

Choose a reason for hiding this comment

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

This kind of lazy initialization without memory barriers can be dangerous: in a multi-threaded context, due to compilation optimizations, the member can get initialized with an object pointer before having actually finished constructing the object. Then a concurrent thread could try to use the object while it is still constructed by the first thread.
This is not a theoretical trouble, I already had to fix an application which startup was randomly failing due to this mistake. (Granted, that was in the .Net Framework 2.0 era, and the 4.0 has strengthen up a bit its memory handling. But still, I would rather not take the risk without a strong reason.)
In other words, there is a reason why Lazy<T> exists: robust lazy initialization in multi-threaded context is not a trivial task.

I do not think this kind of small optimization is worth putting in place memory barriers. Have you measured how much memory this was saving?

Copy link
Member

@hazzik hazzik May 21, 2018

Choose a reason for hiding this comment

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

Have you measured how much memory this was saving?

I think a lot, but did not check for how much. There is a strong demand for this optimisation: #400, #1316. I did investigate this issue recently, but was more inclining towards a redesign of the loaders. The heaviest (both by memory and time) part is the SQL generation, so if this does at least delay it then this change is a clear win. But, still, looking at exact numbers would be a good thing.

Ok, forget my nonsense.. I confused this with another part.

Copy link
Member Author

@bahusoid bahusoid May 21, 2018

Choose a reason for hiding this comment

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

Ok. I just saw it as a simple harmless optimization. I didn't make any measures but code generates for each entity SQL that looks like this:

SELECT Id FROM EntityTable WHERE Id = ?
SELECT Id FROM EntityTable with (updlock, rowlock) WHERE Id = ?
SELECT Id FROM EntityTable with (updlock, rowlock, nowait) WHERE Id = ?
SELECT Id FROM EntityTable with (updlock, rowlock) WHERE Id = ? AND Version = ?

So it seems it's about 0.5 Kb per entity (but it really depends on you data).

I updated code with Lazy. But feel free to close this PR if you think that added overhead is not worth it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@hazzik Yeah. Unfortunately changes you've had in mind can't be scoped to single class. And seems it's been implemented recently in Hibernate:
hibernate/hibernate-orm@98cab7a
hibernate/hibernate-orm@60f4645

@bahusoid
Copy link
Member Author

So closing for now. As it seems it doesn't give any noticeable benefits and requires to use some thread sync logic.

@bahusoid bahusoid closed this May 21, 2018
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