diff --git a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java index c3145d7368c..b8a5024689d 100644 --- a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java +++ b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java @@ -138,9 +138,8 @@ public int addEntry(String path, int parentPathId) throws SQLException, Registry if (log.isDebugEnabled()) { log.debug("Failed to insert due to already exist in database : " + path); } - // we have to be expecting an exception with the duplicate value for the path value - // which can be further checked from here.. - pathId = getPathID(conn, path); + // Handle constraint violation by rolling back and retrying pathID lookup. + pathId = getPathIDAfterRollback(conn, path); if (pathId > 0) { success = true; return pathId; @@ -307,9 +306,8 @@ public int addEntry(JDBCDatabaseTransaction.ManagedRegistryConnection conn, if (log.isDebugEnabled()) { log.debug("Failed to insert due to already exist in database : " + path); } - // we have to be expecting an exception with the duplicate value for the path value - // which can be further checked from here.. - pathId = getPathID(conn, path); + // Handle constraint violation by rolling back and retrying pathID lookup. + pathId = getPathIDAfterRollback(conn, path); if (pathId > 0) { success = true; return pathId; @@ -540,4 +538,31 @@ public int getPathID(AbstractConnection conn, String path) throws SQLException { } return -1; } + + /** + * Retrieves the existing path ID after rolling back an aborted transaction + * caused by a constraint violation during concurrent path creation. + * + * @param conn the database connection in aborted transaction state + * @param path the path that caused the constraint violation + * @return the existing path ID if found, or -1 if not found + */ + private int getPathIDAfterRollback(AbstractConnection conn, String path) throws SQLException { + + try { + conn.rollback(); + if (log.isDebugEnabled()) { + log.debug("Rolled back aborted transaction for path: " + path + + " for tenant: " + CurrentSession.getTenantId()); + } + } catch (SQLException rollbackException) { + String msg = "Failed to rollback aborted transaction for path: " + path + + ". " + rollbackException.getMessage(); + log.error(msg, rollbackException); + + // Re-throw to maintain error propagation. + throw rollbackException; + } + return getPathID(conn, path); + } } diff --git a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/utils/RegistryUtils.java b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/utils/RegistryUtils.java index fa2c25f345e..a11e7df7285 100644 --- a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/utils/RegistryUtils.java +++ b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/utils/RegistryUtils.java @@ -1166,48 +1166,63 @@ public static void setupMediaTypes(RegistryService registryService, int tenantId } } + /** + * Gets or creates a lock object for the specified tenant initialization. + * Uses String.intern() for memory-efficient synchronization. + * + * @param tenantId The ID of the tenant. + * @return the lock object for the specified tenant initialization. + */ + private static Object getTenantInitializationLock(int tenantId) { + + return ("initializeTenant:" + tenantId).intern(); + } + // Do tenant-specific initialization. - public static void initializeTenant(RegistryService registryService, int tenantId) - throws RegistryException { - try { - UserRegistry systemRegistry = registryService.getConfigSystemRegistry(); - if (systemRegistry.getRegistryContext() != null) { - HandlerManager handlerManager = - systemRegistry.getRegistryContext() - .getHandlerManager(); - if (handlerManager instanceof HandlerLifecycleManager) { - ((HandlerLifecycleManager) handlerManager).init(tenantId); - } - } - systemRegistry = - registryService.getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME, - tenantId); - addMountCollection(systemRegistry); - registerMountPoints(systemRegistry, tenantId); - new RegistryCoreServiceComponent().setupMounts(registryService, tenantId); - setupMediaTypes(registryService, tenantId); - // We need to set the tenant ID for current session. Otherwise the - // underlying operations fails + public static void initializeTenant(RegistryService registryService, int tenantId) throws RegistryException { + + // Synchronize on the specific tenant to prevent race conditions during tenant initialization. + synchronized (getTenantInitializationLock(tenantId)) { try { - CurrentSession.setTenantId(tenantId); - RegistryContext registryContext = systemRegistry.getRegistryContext(); - // Adding collection to store user profile information. - addUserProfileCollection(systemRegistry, - getAbsolutePath(registryContext, - registryContext.getProfilesPath())); - // Adding collection to store services. - addServiceStoreCollection(systemRegistry, - getAbsolutePath(registryContext, - registryContext.getServicePath())); - // Adding service configuration resources. - addServiceConfigResources(systemRegistry); - } finally { - CurrentSession.removeTenantId(); + UserRegistry systemRegistry = registryService.getConfigSystemRegistry(); + if (systemRegistry.getRegistryContext() != null) { + HandlerManager handlerManager = + systemRegistry.getRegistryContext() + .getHandlerManager(); + if (handlerManager instanceof HandlerLifecycleManager) { + ((HandlerLifecycleManager) handlerManager).init(tenantId); + } + } + systemRegistry = + registryService.getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME, + tenantId); + addMountCollection(systemRegistry); + registerMountPoints(systemRegistry, tenantId); + new RegistryCoreServiceComponent().setupMounts(registryService, tenantId); + setupMediaTypes(registryService, tenantId); + // We need to set the tenant ID for current session. Otherwise the + // underlying operations fails + try { + CurrentSession.setTenantId(tenantId); + RegistryContext registryContext = systemRegistry.getRegistryContext(); + // Adding collection to store user profile information. + addUserProfileCollection(systemRegistry, + getAbsolutePath(registryContext, + registryContext.getProfilesPath())); + // Adding collection to store services. + addServiceStoreCollection(systemRegistry, + getAbsolutePath(registryContext, + registryContext.getServicePath())); + // Adding service configuration resources. + addServiceConfigResources(systemRegistry); + } finally { + CurrentSession.removeTenantId(); + } + } catch (RegistryException e) { + log.error("Unable to initialize registry for tenant " + tenantId + ".", e); + throw new RegistryException("Unable to initialize registry for tenant " + tenantId + + ".", e); } - } catch (RegistryException e) { - log.error("Unable to initialize registry for tenant " + tenantId + ".", e); - throw new RegistryException("Unable to initialize registry for tenant " + tenantId + - ".", e); } }