-
Notifications
You must be signed in to change notification settings - Fork 435
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
Detect changed context is just ... #610
Comments
@TobiasSQL My eyes are burning! 😱 Let see:
The answer is apparently 4x I see no reason not to kill it. The proposal outlined above, of simply throwing, seems reasonable. |
Thanks @brettwooldridge , I share your sentiment exactly. |
I will add that the reason I went with re-try in the first implementation is that otherwise it would be a breaking change. I.e. someone not using cached handles would not have gotten and exception and now they do. I verified internally that we can make it safe to re-try. |
Hello @TobiasSQL The reason to remove the re-try logic was due to errors that were introduced by it in some scenarios. The new implementation is definitely slower but prevents from inconsistent behaviors and errors. In the original PR #543 it's also mentioned that this implementation is definitely slower in some cases. In my humble opinion, having something working slower is better than causing errors... But yes, it will be much better if there will be a way to fix the previous re-try logic without performance impact. |
Hi @TobiasSQL and @brettwooldridge Thank you for bringing up the concern with us. We re-evaluated he risks involved and agree with your recommendations. The current implementation would degrade performance to a lot extent for many customers executing large queries. We agree with that. Since we are nearing stable release of the driver, we agreed to make below changes to the driver right away and proceed with the following:
We also think that splitting It would be really helpful if you can provide us your views on the listed approach for upcoming release. |
Thanks @cheenamalhotra, most of this makes good sense to me :-) A few comments:
Please cc me and @brettwooldridge on the PR. |
@TobiasSQL The hacker in me couldn't let it go... While the tweak of the existing code (below) looks hairy, it:
When I measured this on a couple of large SQL statements, several kilobytes long, it benchmarked at a couple of hundred nanoseconds. The logic is:
Just thought I'd throw this out there, as sometimes the simplest solutions end up being the most stable... void checkIfContextChanged(final String sql) {
if (connection.contextIsAlreadyChanged) {
connection.contextChanged = true;
return;
}
for (int i = 3; i < sql.length() - 3; i++) {
if (sql.charAt(i) == ' ') {
char ch = Character.toUpperCase(sql.charAt(i - 3));
if (ch != 'U' && ch != 'S') { // not candidate "USE " or "SET "
continue;
}
// look backwards ... was this "USE "?
if (sql.regionMatches(true /*ignoreCase*/, i - 3, "USE", 0, 3)) {
connection.contextIsAlreadyChanged = true;
connection.contextChanged = true;
return;
}
// else likely "SET "
// find next non-whitespace
for (i++; i < sql.length() - 4 && Character.isWhitespace(sql.charAt(i)); i++);
if (sql.regionMatches(true /*ignoreCase*/, i, "ANSI_NULLS", 0, "ANSI_NULLS".length()) ||
sql.regionMatches(true /*ignoreCase*/, i, "DEFAULT_SCHEMA", 0, "DEFAULT_SCHEMA".length()) ||
sql.regionMatches(true /*ignoreCase*/, i, "QUOTED_IDENTIFIER", 0, "QUOTED_IDENTIFIER".length())) {
connection.contextIsAlreadyChanged = true;
connection.contextChanged = true;
return;
}
}
}
} Still has the false positive exposure ... for example, the text "recuse yourself" would trigger due to a space preceded by "use". But maybe acceptable? (Expressions like UPDATE: char ch = sql.charAt(i - 3);
if (ch != 'U' && ch != 'u' && ch != 'S' && ch != 's') { // not candidate "USE " or "SET " ends up being more efficient than: char ch = Character.toUpperCase(sql.charAt(i - 3));
if (ch != 'U' && ch != 'S') { // not candidate "USE " or "SET " slightly less readable, but understandable with the comment. |
I love the passion @brettwooldridge! :-) My sense would still be to avoid this since we are trying to read the "mind" of the server. I.e. if things change on the server and handle does not need to be discarded the driver is still "optimizing". My $.02. What is your take? |
Understood. |
Hi @TobiasSQL , @brettwooldridge The current dev branch does not have the retry logic, you can use version V6.3.4 for testing. |
Thanks @v-afrafi , let me know when the dev-branch is in the right place and I can take a look. The duplicate insert issue is what I eluded to above, that is easily fixed based on context for retry. |
@v-afrafi, I did an implementation on v6.3.4. It is very simple: for the retry logic you basically never retry if a prepare needs to happen. In
|
@TobiasSQL Thanks Tobias! That fixed the issue 🎉 |
Thanks @v-afrafi , submitted one comment. Thanks for the quick turn around! |
@TobiasSQL I found another issue similar to the one I posted above, here is a sample: There is a fix that if we add these at the following code lines will fix the issue:
The reason is that needsPrepared at the fifth iteration returns false, but we are doing retry again after raiseError happens. |
Hello Tobias, Would like to know your thoughts on the above issue before we take a call to implement the fix as per our analysis. Appreciate your response soon, since we are nearing release schedule. |
Hi, I get a 404 error when trying to go to https://gist.github.com/v-afrafi/2e90f325008423cdc0eb92e30eea100c |
Hi Tobias, |
Thanks, I see. The problem here is that the way we (I) test is busted given we now retry. We need to change things a bit, I suggest the following:
Something along these lines :-) |
Thanks @TobiasSQL . understood. Looks like a test scenario issue, we could not reproduce it with context change that we thought originally. We will be merging the pr soon. |
Closing issue as requested changes merged to driver. |
https://github.com/Microsoft/mssql-jdbc/blob/e0e70a429aa6f84d151e5a18aef8b92f3337e269/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java#L806
+@brettwooldridge to keep me honest.
The
checkIfContextChanged
method inSQLServerStatement
has a bunch of issues. My understanding is that this was added to handle the case where prepared handles cannot be re-used because the server context has changed. However, first off the implementation is very flaky, for ex. if I have a stored procedure called AddUser it will be detected as a context change. This also adds a bunch of overhead in terms of string manipulation & comparison with very little gain (most of the time the context will not have changed).The previous implementation (that I did) attempted to re-create the handle if the context changed. There are pros and cons here, but I think that or simply throwing an error are the only reasonable alternatives. IMHO, the cons against this current approach are:
Thoughts?
/Tobias
The text was updated successfully, but these errors were encountered: