MNT-22186: propTablesCleanupJobDetail v2 can cause Out of Memory errors (CleanAlfPropTablesV2.sql ) (#390)

- added dialect check to set MySQL specific fetch size limitation (Integer.MIN_VALUE). fetchSize activates result set streaming.
- updated tests
This commit is contained in:
Cristian Turlica
2021-04-19 18:02:19 +03:00
committed by GitHub
parent ef441fc2c8
commit 5e38be6f7d
3 changed files with 32 additions and 7 deletions

View File

@@ -25,6 +25,8 @@
*/
package org.alfresco.repo.domain.schema.script;
import org.alfresco.repo.domain.dialect.Dialect;
import org.alfresco.repo.domain.dialect.MySQLInnoDBDialect;
import org.alfresco.util.LogUtil;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
@@ -74,6 +76,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
private int line;
private File scriptFile;
private Properties globalProperties;
private Dialect dialect;
private boolean readOnly;
private int deleteBatchSize;
@@ -84,12 +87,18 @@ public class DeleteNotExistsExecutor implements StatementExecutor
private Date startTime;
public DeleteNotExistsExecutor(Connection connection, String sql, int line, File scriptFile, Properties globalProperties)
{
this(connection, sql, line, scriptFile, globalProperties, null);
}
public DeleteNotExistsExecutor(Connection connection, String sql, int line, File scriptFile, Properties globalProperties, Dialect dialect)
{
this.connection = connection;
this.sql = sql;
this.line = line;
this.scriptFile = scriptFile;
this.globalProperties = globalProperties;
this.dialect = dialect;
}
public void checkProperties()
@@ -164,6 +173,21 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
/**
* @return Integer.MIN_VALUE in case of MySQL otherwise the batch size.
*/
private int computeFetchSize()
{
if (this.dialect instanceof MySQLInnoDBDialect)
{
// Note the MySQL specific fetch size limitation (Integer.MIN_VALUE). fetchSize
// activates result set streaming.
return Integer.MIN_VALUE;
}
return batchSize;
}
private void process(Pair<String, String>[] tableColumn, Long[] tableUpperLimits, String[] optionalWhereClauses) throws SQLException
{
// The approach is to fetch ordered row ids from all referencer/secondary (e.g.
@@ -184,6 +208,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
PreparedStatement[] secondaryPrepStmts = null;
PreparedStatement deletePrepStmt = null;
Set<Long> deleteIds = new HashSet<>();
int fetchSize = computeFetchSize();
deletedCount = 0L;
startTime = new Date();
@@ -191,7 +216,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
{
connection.setAutoCommit(false);
primaryPrepStmt = connection.prepareStatement(createPreparedSelectStatement(primaryTableName, primaryColumnName, primaryWhereClause));
primaryPrepStmt.setFetchSize(batchSize);
primaryPrepStmt.setFetchSize(fetchSize);
primaryPrepStmt.setLong(1, primaryId);
primaryPrepStmt.setLong(2, tableUpperLimits[0]);
@@ -204,7 +229,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
for (int i = 1; i < tableColumn.length; i++)
{
PreparedStatement secStmt = connection.prepareStatement(createPreparedSelectStatement(tableColumn[i].getFirst(), tableColumn[i].getSecond(), optionalWhereClauses[i]));
secStmt.setFetchSize(batchSize);
secStmt.setFetchSize(fetchSize);
secStmt.setLong(1, primaryId);
secStmt.setLong(2, tableUpperLimits[i]);

View File

@@ -350,7 +350,7 @@ public class ScriptExecutorImpl implements ScriptExecutor
}
else if (sql.startsWith("--DELETE_NOT_EXISTS"))
{
DeleteNotExistsExecutor deleteNotExists = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, globalProperties);
DeleteNotExistsExecutor deleteNotExists = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, globalProperties, dialect);
deleteNotExists.execute();
// Reset

View File

@@ -90,7 +90,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("true");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties, null);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -100,7 +100,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties, null);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -133,7 +133,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_DELETE_BATCH_SIZE)).thenReturn("1");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties, null);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -167,7 +167,7 @@ public class DeleteNotExistsExecutorTest
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_BATCH_SIZE)).thenReturn("2");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties, null);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);