[#933] Read a catalog table another session created while this one was creating it - #1005
Open
vharseko wants to merge 1 commit into
Open
Conversation
…ed while this one was creating it createCatalogTable() answers whether it created the table or found it already there, and openCatalog() reads the rows on the second answer instead of raising catalogTableOpened over an empty enrolledTrees. A storage that adopted a table without reading it enrols every tree of that open again - one upsert and one commit each on the catalog connection, against rows that are already there - and goes on doing it for every later write of that open which names a tree. Fixes OpenIdentityPlatform#933
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 #933
The problem
openCatalog()makes the catalog of a backend usable once per open of the storage: it reads what the catalog records where the table is there, and creates the table where it is not. The lock it runs under orders the transactions of one storage and nothing else, which is whycreateCatalogTable()tolerates a table that turned up while it was being made — an offline tool beside a running server is a pair no lock of one process can order.On that tolerated path the method returned without reading a row, and
openCatalog()went on to raisecatalogTableOpenedover an emptyenrolledTrees. The table is there and full of rows; this storage believes it records nothing.enrolInCatalog()skips a tree the memo already names and writes it otherwise, so every tree of that open is written again — about 25 upserts and 25 commits on the catalog connection for a stock suffix, each a row that was already there, and the same for every later write of that open which names a tree. Not a correctness bug: the upsert is idempotent, the rows are the same rows, and the commits are on the catalog's own connection, so nothing of the caller's transaction is committed andpartlyCommittedis not raised. It defeats the optimisation that exists to make an open of a complete catalog write nothing at all.The change
createCatalogTable()answers whether it created the table or adopted one that was already there, andopenCatalog()reads the rows on the second answer — the reading branch is exactly what such a table is for. Where the create really did create it, there is still nothing to read.The read runs on the session the failed create reset, which is a connection rolled back or, where even the rollback failed, one given up for the read to establish again: either is a session a select may be asked of. A select that fails there is thrown, exactly as it is thrown on the branch that reads a table which was there from the start — one failure, one answer.
The test
testAnOpenThatAdoptsTheCatalogTableOfAnotherSessionEnrolsNothingAgain, in the shared jdbc suite, so every engine runs it.AdoptingStorageanswers once that the catalog table is not there while it is — the state of a session whose lookup ran a moment before another session'screate tablecommitted — and counts the connections its catalog is read and written on.What tells a storage that read the table from one that only wrote its way through the trees of that write is the tree asked for afterwards: one the catalog already names and the adopting write never opened. The catalog of a transaction is opened at the first row that transaction has to write, so a write whose trees the catalog already names opens no connection at all.
Without the fix it fails with
expected [1] but found [2]— the second write had to open a connection to write a row that is already there.Verification
expected [1] but found [2]PgSqlTestCaseMySqlTestCaseCachedConnectionTestCase,CatalogConnectionTestCase,JDBCStatementBoundTestCase,JDBCStorageRetryTest,StampConnectionTestCaseThe mssql and oracle suites were not run locally; the change carries no dialect of its own.