feat: Phase 1 — migrate read queries to reservation tables (PG)#313
Open
porcellus wants to merge 25 commits intofeat/isolation-reservation-table-lockingfrom
Open
feat: Phase 1 — migrate read queries to reservation tables (PG)#313porcellus wants to merge 25 commits intofeat/isolation-reservation-table-lockingfrom
porcellus wants to merge 25 commits intofeat/isolation-reservation-table-lockingfrom
Conversation
… pg/oauth containers
Reduce iterations from 3000 to 500 and thread pool from 1000 to 200 threads across all three deadlock tests. Tighten awaitTermination from 2min to 60s with an assertion. Deadlocks still trigger reliably since even 200 threads competing for the same rows produces heavy contention. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce idle timeout from 30s to 3s and set HikariCP housekeeping period to 1s (via system property) in both pool tests. This cuts the Thread.sleep from 65s to 8s. Also reduce concurrent sign-in operations from 10000 to 1000 in testIdleConnectionTimeout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cache per-worker test database (create once, reuse across tests) - Add truncateAllData() that truncates all tables instead of dropping and recreating the database each test - Use killAll(false) in reset() to preserve tables across tests, making CREATE TABLE IF NOT EXISTS statements no-ops - Add killAll(boolean) overload to TestingProcessManager - Update DbConnectionPoolTest idle timeout to use HikariCP minimum Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation-reservation-table-migration
Add time_joined and primary_or_recipe_user_time_joined columns to app_id_to_user_id with 4 pagination indexes. Update all signup write paths (EP, Pless, TP, WebAuthn + bulk import) and account linking methods (updateTimeJoined, unlinkAccounts) to maintain these columns. This prepares app_id_to_user_id to replace all_auth_recipe_users for pagination queries (DEPRECATE ticket 01). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prepares for future CASCADE FK migration by adding ON UPDATE CASCADE to all foreign keys that reference app_id_to_user_id(app_id, user_id). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…able Replaces the old query that joined emailpassword_user_to_tenant with all_auth_recipe_users. The new query joins recipe_user_tenants with app_id_to_user_id, which works for both linked and unlinked users without needing to query primary_user_tenants separately. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate 5 methods in PasswordlessQueries.java from passwordless_user_to_tenant and all_auth_recipe_users to recipe_user_tenants and app_id_to_user_id: - deleteDevicesByPhoneNumber_Transaction - deleteDevicesByEmail_Transaction - getUserInfosWithTenant_Transaction - getPrimaryUserIdUsingEmail - getPrimaryUserByPhoneNumber Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…JVM hang afterTesting() only cleaned up files but never killed test processes. The last test in each class left a SuperTokens instance running with non-daemon threads (webserver, cron jobs, HikariCP) that prevented the test JVM from exiting, causing gradle to hang indefinitely. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate getUserIdByThirdPartyInfo and getPrimaryUserIdUsingEmail to use recipe_user_tenants + app_id_to_user_id instead of thirdparty_user_to_tenant + all_auth_recipe_users. Delete dead code: getPrimaryUserIdUsingEmail_Transaction and getPrimaryUserIdsUsingMultipleEmails_Transaction (no callers). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate 4 methods in WebAuthNQueries.java off webauthn_user_to_tenant and all_auth_recipe_users to use recipe_user_tenants (tenant-scoped) and recipe_user_account_infos (app-scoped) joined with app_id_to_user_id. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e queries Replace per-recipe UNION queries (emailpassword, thirdparty, passwordless, webauthn user_to_tenant tables + all_auth_recipe_users) with unified queries using app_id_to_user_id + recipe_user_tenants. Uses ILIKE for case-insensitive search. Non-search pagination path also migrated to use app_id_to_user_id + recipe_user_tenants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate listPrimaryUsersByEmail, listPrimaryUsersByPhoneNumber, getPrimaryUserByThirdPartyInfo, and listPrimaryUsersByThirdPartyInfo (including _Transaction variant) to use recipe_user_tenants and recipe_user_account_infos tables instead of per-recipe query methods. New unified lookup methods added to AccountInfoQueries.java replace 4 separate per-recipe queries with single queries against the reservation tables. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…l_auth_recipe_users Migrate getUsersCount (app-scoped and tenant-scoped), checkIfUsesAccountLinking to use app_id_to_user_id and recipe_user_tenants instead of all_auth_recipe_users. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ff all_auth_recipe_users - getPrimaryUserInfoForUserIds: LEFT JOIN recipe_user_tenants for tenant_id, time_joined from app_id_to_user_id - getPrimaryUserIdStrForUserId: read from app_id_to_user_id - getTenantIdsForUserIds: use recipe_user_tenants with DISTINCT - SessionQueries: use app_id_to_user_id for primary_or_recipe_user_id lookups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all_auth_recipe_users with recipe_user_tenants and primary_user_tenants for the tenant-scoped doesUserIdExist query. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Part A (ISO-021): Fix wasAlreadyAPrimeryUserResult typo in AccountInfoQueries. Part B (ISO-025): Rewrite lockUsers() to use a single query with FOR UPDATE instead of 2N+M individual queries. Uses UNION to fetch both requested users and their primary users, with ORDER BY user_id for deadlock prevention. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PasswordlessQueries: fix phone_number column name in ResultSet read, remove dead PasswordlessDeviceRowMapper call, insert both email AND phone rows into recipe_user_tenants for dual-contact users - GeneralQueries: move updateTimeJoinedForPrimaryUser after app_id_to_user_id update in linkAccounts so MIN(time_joined) sees all linked users; add hasPhones&&hasProviders and hasEmails&&hasPhones&&hasProviders search tag cases to prevent false matches in getUsers dashboard search - UserLockingQueries: trim user_id from ResultSet to handle CHAR(36) padding in HashMap lookup (fixes lockUser with non-UUID user IDs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend RaceTestUtils with full integrity checks (I1-I6) for all account_info_types (EMAIL, PHONE_NUMBER, THIRD_PARTY): - I1/I2: primary_user_tenants completeness and accuracy - I3: recipe_user_tenants consistency - I4: recipe_user_tenants row count per tenant - I5: recipe_user_account_infos row count - I6: time_joined consistency in app_id_to_user_id Create ReservationTableIntegrityTest with 10 tests covering: - Passwordless dual email+phone reservations (Bug #3 regression) - Time_joined consistency after linking (Bug #2 regression) - Unlink cleanup and primary reservation preservation - Dashboard search tag combinations (Bug #4 regression) - Cross-recipe linking, third-party type, email clearing Hook integrity checks into ExceptionParsingTest signup methods. Update all 6 race test classes to use generalized checker. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
all_auth_recipe_usersand per-recipe*_user_to_tenanttables to reservation tables (recipe_user_tenants,recipe_user_account_infos,primary_user_tenants,app_id_to_user_id)getUsers()dashboard search to unified reservation table queries with proper search tag combinationslistUsersByAccountInfo,getPrimaryUserInfo,getTenantIds, session queries, anddoesUserIdExistlockUsersto single FOR UPDATE queryphone_numbercolumn name, dual email+phone passwordless reservations,linkAccountstime_joined ordering, search tag edge cases, CHAR(36) padding in lockUsersPhase 1 of the DEPRECATE plan — moves all read paths to the new reservation tables. After this, the old tables are only used for writes (Phase 2 will address those).
Companion PRs:
Test plan
ReservationTableIntegrityTest— 10 tests verifying all 6 invariants across email, phone, third-partyExceptionParsingTest— integrity checks added to signup methodsspotlessJavaCheckclean)🤖 Generated with Claude Code