Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 6 additions & 19 deletions src/main/java/io/supertokens/storageLayer/StorageLayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,26 +262,10 @@ public static void loadAllTenantStorage(Main main, TenantConfig[] tenants)
userPoolsInUse.add(userPoolId);
}

// TODO: should the below code be outside of this locked code cause it takes time
// and any other thread that will want access to the resource distributor will have
// to wait for this?
// we remove storage layers that are no longer being used

for (ResourceDistributor.KeyClass key : existingStorageMap.keySet()) {
try {
if (((StorageLayer) main.getResourceDistributor()
.getResource(key.getTenantIdentifier(), RESOURCE_KEY)).storage !=
((StorageLayer) existingStorageMap.get(key)).storage) {
// this means that this storage layer is no longer being used, so we close it
((StorageLayer) existingStorageMap.get(key)).storage.close();
((StorageLayer) existingStorageMap.get(key)).storage.stopLogging();
}
} catch (TenantOrAppNotFoundException e) {
// this means a tenant has been removed but the storage may need closing
if (!userPoolsInUse.contains(((StorageLayer) existingStorageMap.get(key)).storage.getUserPoolId())) {
((StorageLayer) existingStorageMap.get(key)).storage.close();
((StorageLayer) existingStorageMap.get(key)).storage.stopLogging();
}
if (!userPoolsInUse.contains(((StorageLayer) existingStorageMap.get(key)).storage.getUserPoolId())) {
((StorageLayer) existingStorageMap.get(key)).storage.close();
((StorageLayer) existingStorageMap.get(key)).storage.stopLogging();
}
}

Expand All @@ -303,8 +287,11 @@ public static void loadAllTenantStorage(Main main, TenantConfig[] tenants)
// we still want other tenants to continue to work
}
}

return null;
});


} catch (ResourceDistributor.FuncException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2011,4 +2011,53 @@ public void testStorageDoesNotLoadAgainAfterTenantDeletionWhenRefreshedFromDb()
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

@Test
public void testThatOriginalStorageIsNotClosedIfTheStorageForATenantChangesAndTheOriginalStorageIsUsedByAnotherTenant() 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});
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

if (StorageLayer.isInMemDb(process.getProcess())) {
return;
}

// The tenant shares storage with base
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
new JsonObject()
), false);

Storage storage = StorageLayer.getBaseStorage(process.getProcess());
storage.getKeyValue(TenantIdentifier.BASE_TENANT, "somekey"); // Should pass

// Change the storage
JsonObject config = new JsonObject();
StorageLayer.getStorage(new TenantIdentifier(null, null, null), process.getProcess())
.modifyConfigToAddANewUserPoolForTesting(config, 1);
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
new TenantIdentifier(null, null, "t1"),
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
config
), false);

storage = StorageLayer.getBaseStorage(process.getProcess());
storage.getKeyValue(TenantIdentifier.BASE_TENANT, "somekey"); // Should continue to pass

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}
}