Skip to content

Commit

Permalink
Merge branch '5.0' into db-optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Feb 9, 2024
2 parents 097bce7 + abe5312 commit 15de9da
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 99 deletions.
Binary file modified jar/postgresql-plugin-5.0.7.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,34 @@

package io.supertokens.storage.postgresql.test;

import static org.junit.Assert.*;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import io.supertokens.pluginInterface.multitenancy.*;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import com.google.gson.JsonObject;

import io.supertokens.ProcessState;
import io.supertokens.emailpassword.exceptions.EmailChangeNotAllowedException;
import io.supertokens.featureflag.EE_FEATURES;
import io.supertokens.featureflag.FeatureFlagTestContent;
import io.supertokens.multitenancy.Multitenancy;
import io.supertokens.multitenancy.exception.BadPermissionException;
import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.multitenancy.*;
import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storageLayer.StorageLayer;
import io.supertokens.thirdparty.ThirdParty;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import static org.junit.Assert.*;

public class DbConnectionPoolTest {
@Rule
Expand Down Expand Up @@ -116,106 +118,129 @@ public void testActiveConnectionsWithTenants() throws Exception {
public void testDownTimeWhenChangingConnectionPoolSize() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
FeatureFlagTestContent.getInstance(process.getProcess())
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY});
Utils.setValueInConfig("postgresql_minimum_idle_connections", "10");
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

Start start = (Start) StorageLayer.getBaseStorage(process.getProcess());
assertEquals(10, start.getDbActivityCount("supertokens"));

JsonObject config = new JsonObject();
start.modifyConfigToAddANewUserPoolForTesting(config, 1);
config.addProperty("postgresql_connection_pool_size", 300);
config.addProperty("postgresql_minimum_idle_connections", 300);
AtomicLong firstErrorTime = new AtomicLong(-1);
AtomicLong successAfterErrorTime = new AtomicLong(-1);
AtomicInteger errorCount = new AtomicInteger(0);

Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);

Thread.sleep(3000); // let the new tenant be ready

assertEquals(300, start.getDbActivityCount("st1"));

ExecutorService es = Executors.newFixedThreadPool(100);
for (int t = 0; t < 5; t++) {
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
FeatureFlagTestContent.getInstance(process.getProcess())
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY});
process.startProcess();
Utils.setValueInConfig("postgresql_minimum_idle_connections", "10");
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

for (int i = 0; i < 10000; i++) {
int finalI = i;
es.execute(() -> {
try {
TenantIdentifier t1 = new TenantIdentifier(null, null, "t1");
TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess()));
ThirdParty.signInUp(t1WithStorage, process.getProcess(), "google", "googleid"+ finalI, "user" +
finalI + "@example.com");
Start start = (Start) StorageLayer.getBaseStorage(process.getProcess());
assertEquals(10, start.getDbActivityCount("supertokens"));

if (firstErrorTime.get() != -1 && successAfterErrorTime.get() == -1) {
successAfterErrorTime.set(System.currentTimeMillis());
}
} catch (StorageQueryException e) {
if (e.getMessage().contains("Connection is closed") || e.getMessage().contains("has been closed")) {
if (firstErrorTime.get() == -1) {
firstErrorTime.set(System.currentTimeMillis());
JsonObject config = new JsonObject();
start.modifyConfigToAddANewUserPoolForTesting(config, 1);
config.addProperty("postgresql_connection_pool_size", 300);
config.addProperty("postgresql_minimum_idle_connections", 300);
AtomicLong firstErrorTime = new AtomicLong(-1);
AtomicLong successAfterErrorTime = new AtomicLong(-1);
AtomicInteger errorCount = new AtomicInteger(0);

Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);

Thread.sleep(5000); // let the new tenant be ready

assertEquals(300, start.getDbActivityCount("st1"));

ExecutorService es = Executors.newFixedThreadPool(100);

for (int i = 0; i < 10000; i++) {
int finalI = i;
es.execute(() -> {
try {
TenantIdentifier t1 = new TenantIdentifier(null, null, "t1");
TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess()));
ThirdParty.signInUp(t1WithStorage, process.getProcess(), "google", "googleid"+ finalI, "user" +
finalI + "@example.com");

if (firstErrorTime.get() != -1 && successAfterErrorTime.get() == -1) {
successAfterErrorTime.set(System.currentTimeMillis());
}
} catch (StorageQueryException e) {
if (e.getMessage().contains("Connection is closed") || e.getMessage().contains("has been closed")) {
if (firstErrorTime.get() == -1) {
firstErrorTime.set(System.currentTimeMillis());
}
} else {
errorCount.incrementAndGet();
throw new RuntimeException(e);
}
} else {
} catch (EmailChangeNotAllowedException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
} catch (TenantOrAppNotFoundException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
} catch (BadPermissionException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Please call initPool before getConnection")) {
if (firstErrorTime.get() == -1) {
firstErrorTime.set(System.currentTimeMillis());
}
} else {
errorCount.incrementAndGet();
throw e;
}
}
} catch (EmailChangeNotAllowedException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
} catch (TenantOrAppNotFoundException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
} catch (BadPermissionException e) {
errorCount.incrementAndGet();
throw new RuntimeException(e);
}
});
}
});
}

// change connection pool size
config.addProperty("postgresql_connection_pool_size", 200);
config.addProperty("postgresql_minimum_idle_connections", 200);
// change connection pool size
config.addProperty("postgresql_connection_pool_size", 200);
config.addProperty("postgresql_minimum_idle_connections", 200);

Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);

Thread.sleep(3000); // let the new tenant be ready
Thread.sleep(3000); // let the new tenant be ready

es.shutdown();
es.awaitTermination(2, TimeUnit.MINUTES);
es.shutdown();
es.awaitTermination(2, TimeUnit.MINUTES);

assertEquals(0, errorCount.get());
assertEquals(0, errorCount.get());

assertEquals(200, start.getDbActivityCount("st1"));
assertEquals(200, start.getDbActivityCount("st1"));

// delete tenant
Multitenancy.deleteTenant(new TenantIdentifier(null, null, "t1"), process.getProcess());
Thread.sleep(3000); // let the tenant be deleted
// delete tenant
Multitenancy.deleteTenant(new TenantIdentifier(null, null, "t1"), process.getProcess());
Thread.sleep(3000); // let the tenant be deleted

assertEquals(0, start.getDbActivityCount("st1"));
assertEquals(0, start.getDbActivityCount("st1"));

System.out.println(successAfterErrorTime.get() - firstErrorTime.get() + "ms");
assertTrue(successAfterErrorTime.get() - firstErrorTime.get() < 250);
assertTrue(successAfterErrorTime.get() - firstErrorTime.get() > 0);
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
System.out.println(successAfterErrorTime.get() - firstErrorTime.get() + "ms");
assertTrue(successAfterErrorTime.get() - firstErrorTime.get() < 250);

if (successAfterErrorTime.get() - firstErrorTime.get() == 0) {
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
continue; // retry
}

assertTrue(successAfterErrorTime.get() - firstErrorTime.get() > 0);
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));

return;
}

fail(); // tried 5 times
}


@Test
public void testMinimumIdleConnections() throws Exception {
String[] args = {"../"};
Expand Down Expand Up @@ -375,4 +400,4 @@ public void testIdleConnectionTimeout() throws Exception {
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ public void testDBPasswordMasking() throws Exception {

Utils.setValueInConfig("info_log_path", "null");
Utils.setValueInConfig("error_log_path", "null");
Utils.setValueInConfig("postgresql_password", "db_password");

System.setOut(new PrintStream(stdOutput));
System.setErr(new PrintStream(errorOutput));
Expand Down

0 comments on commit 15de9da

Please sign in to comment.