Skip to content

Commit 8af3332

Browse files
committed
fix: repeatable read
1 parent 1995a1e commit 8af3332

File tree

6 files changed

+31
-23
lines changed

6 files changed

+31
-23
lines changed

src/main/java/io/supertokens/storage/postgresql/BulkImportProxyConnection.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ public String getCatalog() throws SQLException {
130130

131131
@Override
132132
public void setTransactionIsolation(int level) throws SQLException {
133-
this.con.setTransactionIsolation(level);
133+
if (level != Connection.TRANSACTION_READ_COMMITTED) {
134+
this.con.setTransactionIsolation(level);
135+
}
134136
}
135137

136138
@Override

src/main/java/io/supertokens/storage/postgresql/BulkImportProxyStorage.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public synchronized Connection getTransactionConnection() throws SQLException, S
4444
if (this.connection == null) {
4545
Connection con = ConnectionPool.getConnectionForProxyStorage(this);
4646
this.connection = new BulkImportProxyConnection(con);
47-
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
4847
connection.setAutoCommit(false);
4948
}
5049
return this.connection;

src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ private synchronized void initialiseHikariDataSource() throws SQLException, Stor
5454
HikariConfig config = new HikariConfig();
5555
PostgreSQLConfig userConfig = Config.getConfig(start);
5656
config.setDriverClassName("org.postgresql.Driver");
57+
config.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
5758

5859
String scheme = userConfig.getConnectionScheme();
5960

src/main/java/io/supertokens/storage/postgresql/Start.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ public void initStorage(boolean shouldWait, List<TenantIdentifier> tenantIdentif
342342
@Override
343343
public <T> T startTransaction(TransactionLogic<T> logic)
344344
throws StorageTransactionLogicException, StorageQueryException {
345-
return startTransaction(logic, TransactionIsolationLevel.SERIALIZABLE);
345+
return startTransaction(logic, TransactionIsolationLevel.READ_COMMITTED);
346346
}
347347

348348
@Override
@@ -431,7 +431,7 @@ protected <T> T startTransactionHelper(TransactionLogic<T> logic, TransactionIso
431431
try {
432432
con = ConnectionPool.getConnection(this);
433433
defaultTransactionIsolation = con.getTransactionIsolation();
434-
int libIsolationLevel = Connection.TRANSACTION_SERIALIZABLE;
434+
int libIsolationLevel = Connection.TRANSACTION_READ_COMMITTED;
435435
switch (isolationLevel) {
436436
case SERIALIZABLE:
437437
libIsolationLevel = Connection.TRANSACTION_SERIALIZABLE;
@@ -449,7 +449,9 @@ protected <T> T startTransactionHelper(TransactionLogic<T> logic, TransactionIso
449449
libIsolationLevel = Connection.TRANSACTION_NONE;
450450
break;
451451
}
452-
con.setTransactionIsolation(libIsolationLevel);
452+
if (libIsolationLevel != Connection.TRANSACTION_READ_COMMITTED) {
453+
con.setTransactionIsolation(libIsolationLevel);
454+
}
453455
con.setAutoCommit(false);
454456
return logic.mainLogicAndCommit(new TransactionConnection(con));
455457
} catch (Exception e) {
@@ -460,9 +462,6 @@ protected <T> T startTransactionHelper(TransactionLogic<T> logic, TransactionIso
460462
} finally {
461463
if (con != null) {
462464
con.setAutoCommit(true);
463-
if (defaultTransactionIsolation != null) {
464-
con.setTransactionIsolation(defaultTransactionIsolation);
465-
}
466465
con.close();
467466
}
468467
}

src/main/java/io/supertokens/storage/postgresql/queries/SAMLQueries.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ public static String getQueryToCreateSAMLRelayStateTable(Start start) {
8181
+ "tenant_id VARCHAR(64) NOT NULL DEFAULT 'public',"
8282
+ "relay_state VARCHAR(256) NOT NULL,"
8383
+ "client_id VARCHAR(256) NOT NULL,"
84-
+ "state TEXT NOT NULL,"
84+
+ "state TEXT,"
8585
+ "redirect_uri TEXT NOT NULL,"
8686
+ "created_at BIGINT NOT NULL,"
87+
+ "expires_at BIGINT NOT NULL,"
8788
+ "CONSTRAINT " + Utils.getConstraintName(schema, tableName, null, "pkey")
8889
+ " PRIMARY KEY(app_id, tenant_id, relay_state),"
8990
+ "CONSTRAINT " + Utils.getConstraintName(schema, tableName, "app_id", "fkey") + " "
@@ -115,6 +116,7 @@ public static String getQueryToCreateSAMLClaimsTable(Start start) {
115116
+ "code VARCHAR(256) NOT NULL,"
116117
+ "claims TEXT NOT NULL,"
117118
+ "created_at BIGINT NOT NULL,"
119+
+ "expires_at BIGINT NOT NULL,"
118120
+ "CONSTRAINT " + Utils.getConstraintName(schema, tableName, null, "pkey")
119121
+ " PRIMARY KEY(app_id, tenant_id, code),"
120122
+ "CONSTRAINT " + Utils.getConstraintName(schema, tableName, "app_id", "fkey") + " "
@@ -140,8 +142,8 @@ public static void saveRelayStateInfo(Start start, TenantIdentifier tenantIdenti
140142
String relayState, String clientId, String state, String redirectURI)
141143
throws StorageQueryException, SQLException {
142144
String QUERY = "INSERT INTO " + getConfig(start).getSAMLRelayStateTable()
143-
+ "(app_id, tenant_id, relay_state, client_id, state, redirect_uri, created_at)"
144-
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
145+
+ "(app_id, tenant_id, relay_state, client_id, state, redirect_uri, created_at, expires_at)"
146+
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
145147

146148
update(start, QUERY, pst -> {
147149
pst.setString(1, tenantIdentifier.getAppId());
@@ -150,19 +152,22 @@ public static void saveRelayStateInfo(Start start, TenantIdentifier tenantIdenti
150152
pst.setString(4, clientId);
151153
pst.setString(5, state);
152154
pst.setString(6, redirectURI);
153-
pst.setLong(7, System.currentTimeMillis());
155+
long now = System.currentTimeMillis();
156+
pst.setLong(7, now);
157+
pst.setLong(8, now + 300000);
154158
});
155159
}
156160

157161
public static SAMLRelayStateInfo getRelayStateInfo(Start start, TenantIdentifier tenantIdentifier, String relayState)
158162
throws StorageQueryException, SQLException {
159163
String QUERY = "SELECT client_id, state, redirect_uri FROM " + getConfig(start).getSAMLRelayStateTable()
160-
+ " WHERE app_id = ? AND tenant_id = ? AND relay_state = ?";
164+
+ " WHERE app_id = ? AND tenant_id = ? AND relay_state = ? AND expires_at >= ?";
161165

162166
return execute(start, QUERY, pst -> {
163167
pst.setString(1, tenantIdentifier.getAppId());
164168
pst.setString(2, tenantIdentifier.getTenantId());
165169
pst.setString(3, relayState);
170+
pst.setLong(4, System.currentTimeMillis());
166171
}, result -> {
167172
if (result.next()) {
168173
return new SAMLRelayStateInfo(
@@ -179,28 +184,31 @@ public static SAMLRelayStateInfo getRelayStateInfo(Start start, TenantIdentifier
179184
public static void saveSAMLClaims(Start start, TenantIdentifier tenantIdentifier, String clientId, String code, String claimsJson)
180185
throws StorageQueryException, SQLException {
181186
String QUERY = "INSERT INTO " + getConfig(start).getSAMLClaimsTable()
182-
+ "(app_id, tenant_id, client_id, code, claims, created_at)"
183-
+ " VALUES (?, ?, ?, ?, ?, ?)";
187+
+ "(app_id, tenant_id, client_id, code, claims, created_at, expires_at)"
188+
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
184189

185190
update(start, QUERY, pst -> {
186191
pst.setString(1, tenantIdentifier.getAppId());
187192
pst.setString(2, tenantIdentifier.getTenantId());
188193
pst.setString(3, clientId);
189194
pst.setString(4, code);
190195
pst.setString(5, claimsJson);
191-
pst.setLong(6, System.currentTimeMillis());
196+
long now = System.currentTimeMillis();
197+
pst.setLong(6, now);
198+
pst.setLong(7, now + 300000);
192199
});
193200
}
194201

195202
public static SAMLClaimsInfo getSAMLClaimsAndRemoveCode(Start start, TenantIdentifier tenantIdentifier, String code)
196203
throws StorageQueryException, SQLException {
197204
String QUERY = "SELECT client_id, claims FROM " + getConfig(start).getSAMLClaimsTable()
198-
+ " WHERE app_id = ? AND tenant_id = ? AND code = ?";
205+
+ " WHERE app_id = ? AND tenant_id = ? AND code = ? AND expires_at >= ?";
199206

200207
SAMLClaimsInfo result = execute(start, QUERY, pst -> {
201208
pst.setString(1, tenantIdentifier.getAppId());
202209
pst.setString(2, tenantIdentifier.getTenantId());
203210
pst.setString(3, code);
211+
pst.setLong(4, System.currentTimeMillis());
204212
}, rs -> {
205213
if (rs.next()) {
206214
try {
@@ -401,20 +409,19 @@ public static boolean removeSAMLClient(Start start, TenantIdentifier tenantIdent
401409

402410
public static void removeExpiredSAMLCodesAndRelayStates(Start start) throws StorageQueryException, SQLException {
403411
long now = System.currentTimeMillis();
404-
long expiredBefore = now - (24 * 60 * 60 * 1000); // 24 hours
405412

406413
// Remove expired relay states
407414
String RELAY_STATE_QUERY = "DELETE FROM " + getConfig(start).getSAMLRelayStateTable()
408-
+ " WHERE created_at < ?";
415+
+ " WHERE expires_at <= ?";
409416
update(start, RELAY_STATE_QUERY, pst -> {
410-
pst.setLong(1, expiredBefore);
417+
pst.setLong(1, now);
411418
});
412419

413420
// Remove expired claims
414421
String CLAIMS_QUERY = "DELETE FROM " + getConfig(start).getSAMLClaimsTable()
415-
+ " WHERE created_at < ?";
422+
+ " WHERE expires_at <= ?";
416423
update(start, CLAIMS_QUERY, pst -> {
417-
pst.setLong(1, expiredBefore);
424+
pst.setLong(1, now);
418425
});
419426
}
420427

src/test/java/io/supertokens/storage/postgresql/test/DeadlockTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public void testConcurrentDeleteAndInsert() throws Exception {
516516
t1Failed.set(false);
517517

518518
return null;
519-
}, TransactionIsolationLevel.SERIALIZABLE);
519+
}, TransactionIsolationLevel.READ_COMMITTED);
520520
} catch (StorageQueryException | StorageTransactionLogicException e) {
521521
// This is expected because of "could not serialize access"
522522
t1Failed.set(true);

0 commit comments

Comments
 (0)