[#929] Establish a catalog connection the way the pool establishes its own - #1009
Open
vharseko wants to merge 1 commit into
Open
[#929] Establish a catalog connection the way the pool establishes its own#1009vharseko wants to merge 1 commit into
vharseko wants to merge 1 commit into
Conversation
… pool establishes its own CachedConnection.establish() is now the one place a connect of this backend is made: the properties the driver is handed, the login, the transaction the rows of this backend need, and the read bound the connection carries afterwards. The pool wraps what it returns, the tree catalog takes the connection as it is, and what becomes of one whose read bound would not come off is the caller's - the pool closes it rather than pooling it, the catalog keeps it, having no second connection to fall back to. Written out twice, that half had already drifted: OpenIdentityPlatform#885 gave the standing read bound to the pooled connect alone, leaving the catalog connection with the lift and nothing bounding the reads between its statements - its commit(), the rollback() of a session given up, the close() of one that lost the race. It now carries org.openidentityplatform.opendj.jdbc.read.timeout as a pooled connection does; a deployment on the default of that property is where it was. The two retry loops stay two: the pool hands its wait to the poll of its deque, where a peer returning a connection ends it early, while a catalog connect has no peer to wait for and sleeps it out, and the timeout each raises differs on purpose - 08001 against the driver's own state, which write() must not read as a connection the database dropped. What they share is the backoff schedule, now CachedConnection.nextBackoffMs(), and both differences are named in the code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #929.
Problem
JDBCStorage.connectCatalog()was a copy ofCachedConnection.connect(): a freshProperties,dialect.bound(...),DriverManager.getConnection(...),setAutoCommit(false),TRANSACTION_READ_COMMITTED, close-on-failure, and the lift of the read bound of the login. The retry loop around it repeated the pool's own besides.The copy had already drifted, one commit after it landed. #885 (#934) replaced the lift in
connect()withapplyStandingReadBound(), which both lifts the bound of the login and putsorg.openidentityplatform.opendj.jdbc.read.timeouton the connection for the rest of its life.connectCatalog()was not touched, so the catalog connection was left with the lift alone — nothing bounding the reads between its statements: itscommit(), therollback()of a session given up, theclose()of one that lost the race to another thread. That is precisely the gap section 2 of #885 exists to close, and this connection was established beside the pooled ones it was closed for.What this changes
One place a connect is made.
CachedConnection.establish()holds the login and the set-up behind it — the half that is the same wherever this backend connects. It hands back the connection, whether the read bound of the login is off it, and the moment the login was known to be through; the pool wraps that into aCachedConnection, the tree catalog takes the connection as it is.What is not shared is what becomes of a connection whose read bound would not come off, which is why the warning names both the connection and its fate: the pool closes such a connection rather than pooling it, while the catalog keeps it — this backend has one catalog connection and no borrower behind it to hand another to, and failing there instead would stop a backend opening on a driver whose
setNetworkTimeoutis not implemented at all, where the pooled connection beside it works.The catalog connection now carries the standing read bound. The behaviour change of this PR, and the drift above put right: a deployment that asked for
read.timeoutgets it on this connection as it gets it on every pooled one. A deployment on the default of that property (no bound) is exactly where it was. Its statements were, and stay, bounded by the class of the work they belong to (#877, #882); what is new is the socket bound standing behind everything else on the connection.The retry loops stay two. Folding them would have to model an iteration that makes no attempt — the pool-full wait, which the catalog has no analogue of — over two deadlines, two exception types and two ways of waiting. What they share is the backoff schedule, now
CachedConnection.nextBackoffMs(), and the two deliberate differences are named in the code rather than left to be rediscovered:08001where the catalog's carries the driver's own state, sincesaysTheConnectionIsGone()reads class 08 as a dropped connection and a manufactured one would put a healthy attempt into the replay.Also here:
closeQuietly(con, unwinding)— the variant that reports the failure of the close on the exception being unwound — moved intoCachedConnectionand replaced the swallowing one, so a driver that will not close is visible on the pooled path too. It cannot change a retry decision:isWorthRetrying()walks the cause andgetNextException()chains, not the suppressed ones.Tests
CatalogConnectionTestCasegains three cases: the connection carries the configured read bound; it carries it whether or not its login had one to lift (connect.timeout=0); and a read bound standing in the connection string is not replaced by it, which is a guard - the value comes fromstandingReadBoundMillis(), so a bound put on from the property alone would pass every other case of the class. The first two fail on the head of this branch, the third passes there.CachedConnectionTestCasegains one for the shared backoff schedule: a millisecond, doubling to the ceiling and staying there.Run locally, one JVM per class:
CatalogConnectionTestCase16,CachedConnectionTestCase100,JDBCStatementBoundTestCase44,JDBCStorageRetryTest67,StampConnectionTestCase5 — all green. The container suites of the four dialects are left to CI.Version
master (5.2.x), all four JDBC dialects.