Skip to content

Commit 43edc44

Browse files
rishabhpoddarRishabh
andauthored
Fixes issue with memory leak during testing (#35)
* fixes issue #34 * updates changelog Co-authored-by: Rishabh <rishabh@supertokens.io>
1 parent 5d7c2cd commit 43edc44

File tree

10 files changed

+61
-29
lines changed

10 files changed

+61
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
- Fixes https://github.com/supertokens/supertokens-postgresql-plugin/issues/34
910

1011
## [1.14.0] - 2022-02-23
1112

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.supertokens.storage.postgresql.config.PostgreSQLConfig;
2525
import io.supertokens.storage.postgresql.output.Logging;
2626

27+
import java.io.ObjectInputFilter;
2728
import java.sql.Connection;
2829
import java.sql.SQLException;
2930
import java.text.DecimalFormat;
@@ -33,12 +34,24 @@
3334
public class ConnectionPool extends ResourceDistributor.SingletonResource {
3435

3536
private static final String RESOURCE_KEY = "io.supertokens.storage.postgresql.ConnectionPool";
36-
private final HikariDataSource ds;
37+
private static HikariDataSource hikariDataSource = null;
3738

3839
private ConnectionPool(Start start) {
3940
if (!start.enabled) {
4041
throw new RuntimeException("Connection to refused"); // emulates exception thrown by Hikari
4142
}
43+
44+
if (ConnectionPool.hikariDataSource != null) {
45+
// This implies that it was already created before and that
46+
// there is no need to create Hikari again.
47+
48+
// If ConnectionPool.hikariDataSource == null, it implies that
49+
// either the config file had changed somehow (which means the plugin JAR was reloaded, resulting in static
50+
// variables to be set to null), or it means that this is the first time we are trying to connect to a db
51+
// (applicable only for testing).
52+
return;
53+
}
54+
4255
HikariConfig config = new HikariConfig();
4356
PostgreSQLConfig userConfig = Config.getConfig(start);
4457
config.setDriverClassName("org.postgresql.Driver");
@@ -81,7 +94,7 @@ private ConnectionPool(Start start) {
8194
// - Failed to validate connection org.mariadb.jdbc.MariaDbConnection@79af83ae (Connection.setNetworkTimeout
8295
// cannot be called on a closed connection). Possibly consider using a shorter maxLifetime value.
8396
config.setPoolName("SuperTokens");
84-
ds = new HikariDataSource(config);
97+
hikariDataSource = new HikariDataSource(config);
8598
}
8699

87100
private static int getTimeToWaitToInit(Start start) {
@@ -166,13 +179,14 @@ public static Connection getConnection(Start start) throws SQLException {
166179
if (!start.enabled) {
167180
throw new SQLException("Storage layer disabled");
168181
}
169-
return getInstance(start).ds.getConnection();
182+
return ConnectionPool.hikariDataSource.getConnection();
170183
}
171184

172185
static void close(Start start) {
173186
if (getInstance(start) == null) {
174187
return;
175188
}
176-
getInstance(start).ds.close();
189+
ConnectionPool.hikariDataSource.close();
190+
ConnectionPool.hikariDataSource = null;
177191
}
178192
}

src/main/java/io/supertokens/storage/postgresql/output/CustomLayout.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828

2929
class CustomLayout extends LayoutBase<ILoggingEvent> {
3030

31-
private final Start start;
31+
private final String processID;
3232

33-
CustomLayout(Start start) {
33+
CustomLayout(String processID) {
3434
super();
35-
this.start = start;
35+
this.processID = processID;
3636
}
3737

3838
@Override
@@ -47,7 +47,7 @@ public String doLayout(ILoggingEvent event) {
4747
sbuf.append(" | ");
4848

4949
sbuf.append("pid: ");
50-
sbuf.append(start.getProcessId());
50+
sbuf.append(this.processID);
5151
sbuf.append(" | ");
5252

5353
sbuf.append("[");

src/main/java/io/supertokens/storage/postgresql/output/LayoutWrappingEncoder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class LayoutWrappingEncoder extends EncoderBase<ILoggingEvent> {
2828

2929
private Layout<ILoggingEvent> layout;
3030

31-
LayoutWrappingEncoder(Start start) {
32-
layout = new CustomLayout(start);
31+
LayoutWrappingEncoder(String processID) {
32+
layout = new CustomLayout(processID);
3333
}
3434

3535
@Override

src/main/java/io/supertokens/storage/postgresql/output/Logging.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,11 @@ public class Logging extends ResourceDistributor.SingletonResource {
3535

3636
private Logging(Start start, String infoLogPath, String errorLogPath) {
3737
this.infoLogger = infoLogPath.equals("null")
38-
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Info." + start.getProcessId())
39-
: createLoggerForFile(start, infoLogPath,
40-
"io.supertokens.storage.postgresql.Info." + start.getProcessId());
38+
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Info")
39+
: createLoggerForFile(start, infoLogPath, "io.supertokens.storage.postgresql.Info");
4140
this.errorLogger = errorLogPath.equals("null")
42-
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Error." + start.getProcessId())
43-
: createLoggerForFile(start, errorLogPath,
44-
"io.supertokens.storage.postgresql.Error." + start.getProcessId());
41+
? createLoggerForConsole(start, "io.supertokens.storage.postgresql.Error")
42+
: createLoggerForFile(start, errorLogPath, "io.supertokens.storage.postgresql.Error");
4543
}
4644

4745
private static Logging getInstance(Start start) {
@@ -140,7 +138,7 @@ public static void stopLogging(Start start) {
140138

141139
private Logger createLoggerForFile(Start start, String file, String name) {
142140
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
143-
LayoutWrappingEncoder ple = new LayoutWrappingEncoder(start);
141+
LayoutWrappingEncoder ple = new LayoutWrappingEncoder(start.getProcessId());
144142
ple.setContext(lc);
145143
ple.start();
146144
FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
@@ -158,7 +156,7 @@ private Logger createLoggerForFile(Start start, String file, String name) {
158156

159157
private Logger createLoggerForConsole(Start start, String name) {
160158
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
161-
LayoutWrappingEncoder ple = new LayoutWrappingEncoder(start);
159+
LayoutWrappingEncoder ple = new LayoutWrappingEncoder(start.getProcessId());
162160
ple.setContext(lc);
163161
ple.start();
164162
ConsoleAppender<ILoggingEvent> logConsoleAppender = new ConsoleAppender<>();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public void testCodeCreationRapidly() throws Exception {
160160
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
161161
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
162162

163-
ExecutorService es = Executors.newCachedThreadPool();
163+
ExecutorService es = Executors.newFixedThreadPool(1000);
164164

165165
AtomicBoolean pass = new AtomicBoolean(true);
166166

@@ -196,7 +196,7 @@ public void testCodeCreationRapidlyWithDifferentEmails() throws Exception {
196196
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
197197
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
198198

199-
ExecutorService es = Executors.newCachedThreadPool();
199+
ExecutorService es = Executors.newFixedThreadPool(1000);
200200

201201
AtomicBoolean pass = new AtomicBoolean(true);
202202

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public void checkThatInMemDVWorksEvenIfWrongConfig()
9292

9393
{
9494
String[] args = { "../" };
95+
StorageLayer.close();
9596
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
9697
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
9798

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public void beforeEach() {
5454
@Test
5555
public void defaultLogging() throws Exception {
5656
String[] args = { "../" };
57+
StorageLayer.close();
5758
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
5859

5960
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
@@ -148,14 +149,15 @@ public void customLogging() throws Exception {
148149
@Test
149150
public void confirmLoggerClosed() throws Exception {
150151
String[] args = { "../" };
152+
StorageLayer.close();
151153
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
152154

153155
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
154156

155157
ch.qos.logback.classic.Logger postgresqlInfo = (ch.qos.logback.classic.Logger) LoggerFactory
156-
.getLogger("io.supertokens.storage.postgresql.Info." + process.getProcess().getProcessId());
158+
.getLogger("io.supertokens.storage.postgresql.Info");
157159
ch.qos.logback.classic.Logger postgresqlError = (ch.qos.logback.classic.Logger) LoggerFactory
158-
.getLogger("io.supertokens.storage.postgresql.Error." + process.getProcess().getProcessId());
160+
.getLogger("io.supertokens.storage.postgresql.Error");
159161

160162
ch.qos.logback.classic.Logger hikariLogger = (Logger) LoggerFactory.getLogger("com.zaxxer.hikari");
161163

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package io.supertokens.storage.postgresql.test;
1919

2020
import io.supertokens.ProcessState;
21+
import io.supertokens.storageLayer.StorageLayer;
2122
import org.junit.AfterClass;
2223
import org.junit.Before;
2324
import org.junit.Rule;
@@ -55,6 +56,8 @@ public void checkingCreationOfNewTable() throws InterruptedException {
5556
process.kill();
5657
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
5758

59+
StorageLayer.close();
60+
5861
process = TestingProcessManager.start(args);
5962
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
6063

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.supertokens.Main;
2121
import io.supertokens.pluginInterface.PluginInterfaceTesting;
2222
import io.supertokens.storage.postgresql.Start;
23+
import io.supertokens.storageLayer.StorageLayer;
2324
import org.apache.tomcat.util.http.fileupload.FileUtils;
2425
import org.junit.rules.TestRule;
2526
import org.junit.rules.TestWatcher;
@@ -31,6 +32,7 @@
3132
import java.nio.charset.StandardCharsets;
3233
import java.nio.file.Files;
3334
import java.nio.file.Paths;
35+
import java.util.Arrays;
3436
import java.util.List;
3537

3638
abstract class Utils extends Mockito {
@@ -78,15 +80,20 @@ static void reset() {
7880
Main.makeConsolePrintSilent = true;
7981
String installDir = "../";
8082
try {
81-
// move from temp folder to installDir
82-
ProcessBuilder pb = new ProcessBuilder("cp", "temp/licenseKey", "./licenseKey");
83-
pb.directory(new File(installDir));
84-
Process process = pb.start();
85-
process.waitFor();
83+
// if the default config is not the same as the current config, we must reset the storage layer
84+
File ogConfig = new File("../temp/config.yaml");
85+
File currentConfig = new File("../config.yaml");
86+
if (currentConfig.isFile()) {
87+
byte[] ogConfigContent = Files.readAllBytes(ogConfig.toPath());
88+
byte[] currentConfigContent = Files.readAllBytes(currentConfig.toPath());
89+
if (!Arrays.equals(ogConfigContent, currentConfigContent)) {
90+
StorageLayer.close();
91+
}
92+
}
8693

87-
pb = new ProcessBuilder("cp", "temp/config.yaml", "./config.yaml");
94+
ProcessBuilder pb = new ProcessBuilder("cp", "temp/config.yaml", "./config.yaml");
8895
pb.directory(new File(installDir));
89-
process = pb.start();
96+
Process process = pb.start();
9097
process.waitFor();
9198

9299
TestingProcessManager.killAll();
@@ -98,6 +105,7 @@ static void reset() {
98105
} catch (Exception e) {
99106
e.printStackTrace();
100107
}
108+
System.gc();
101109
}
102110

103111
static void stopLicenseKeyFromUpdatingToLatest(TestingProcessManager.TestingProcess process) {
@@ -121,6 +129,8 @@ public void write(int b) {
121129
}
122130

123131
public static void setValueInConfig(String key, String value) throws FileNotFoundException, IOException {
132+
// we close the storage layer since there might be a change in the db related config.
133+
StorageLayer.close();
124134

125135
String oldStr = "((#\\s)?)" + key + "(:|((:\\s).+))\n";
126136
String newStr = key + ": " + value + "\n";
@@ -139,6 +149,9 @@ public static void setValueInConfig(String key, String value) throws FileNotFoun
139149
}
140150

141151
public static void commentConfigValue(String key) throws IOException {
152+
// we close the storage layer since there might be a change in the db related config.
153+
StorageLayer.close();
154+
142155
String oldStr = "((#\\s)?)" + key + "(:|((:\\s).+))\n";
143156
String newStr = "# " + key + ":";
144157

0 commit comments

Comments
 (0)