Skip to content

Commit

Permalink
0006153: Added parameters that can disable specific types of conflict…
Browse files Browse the repository at this point in the history
… resolution
  • Loading branch information
evan-miller-jumpmind committed Dec 12, 2023
1 parent 7496e95 commit 4482d7b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 19 deletions.
Expand Up @@ -122,6 +122,9 @@ private ParameterConstants() {
public final static String AUTO_RESOLVE_FOREIGN_KEY_VIOLATION_REVERSE = "auto.resolve.foreign.key.violation.reverse";
public final static String AUTO_RESOLVE_FOREIGN_KEY_VIOLATION_REVERSE_PEERS = "auto.resolve.foreign.key.violation.reverse.peers";
public final static String AUTO_RESOLVE_FOREIGN_KEY_VIOLATION_REVERSE_RELOAD = "auto.resolve.foreign.key.violation.reverse.reload";
public final static String AUTO_RESOLVE_FOREIGN_KEY_VIOLATION_DELETE = "auto.resolve.foreign.key.violation.delete";
public final static String AUTO_RESOLVE_PRIMARY_KEY_VIOLATION = "auto.resolve.primary.key.violation";
public final static String AUTO_RESOLVE_UNIQUE_INDEX_VIOLATION = "auto.resolve.unique.index.violation";
public final static String AUTO_RESOLVE_UNIQUE_INDEX_IGNORE_NULL_VALUES = "auto.resolve.unique.index.ignore.null.values";
public final static String AUTO_INSERT_REG_SVR_IF_NOT_FOUND = "auto.insert.registration.svr.if.not.found";
public final static String AUTO_SYNC_CONFIGURATION = "auto.sync.configuration";
Expand Down
Expand Up @@ -54,6 +54,12 @@ public DatabaseWriterSettings buildParameterDatabaseWriterSettings(List<? extend
settings.setSaveCurrentValueOnError(
parameterService.is(ParameterConstants.DATA_LOADER_ERROR_RECORD_CUR_VAL, false));
settings.setFitToColumn(parameterService.is(ParameterConstants.DATA_LOADER_FIT_TO_COLUMN, false));
settings.setAutoResolveForeignKeyViolationDelete(
parameterService.is(ParameterConstants.AUTO_RESOLVE_FOREIGN_KEY_VIOLATION_DELETE, true));
settings.setAutoResolvePrimaryKeyViolation(
parameterService.is(ParameterConstants.AUTO_RESOLVE_PRIMARY_KEY_VIOLATION, true));
settings.setAutoResolveUniqueIndexViolation(
parameterService.is(ParameterConstants.AUTO_RESOLVE_UNIQUE_INDEX_VIOLATION, true));
settings.setAutoResolveUniqueIndexIgnoreNullValues(
parameterService.is(ParameterConstants.AUTO_RESOLVE_UNIQUE_INDEX_IGNORE_NULL_VALUES, true));
settings.setLogConflictResolution(parameterService.is(ParameterConstants.LOG_CONFLICT_RESOLUTION));
Expand Down
46 changes: 37 additions & 9 deletions symmetric-core/src/main/resources/symmetric-default.properties
Expand Up @@ -1091,15 +1091,6 @@ auto.resolve.foreign.key.violation.reverse=false
# Type: boolean
auto.resolve.foreign.key.violation.reverse.peers=false

# If this is true, when a batch receives a unique index violation,
# the blocking rows for each unique index will only be deleted
# if the unique index has a value that is not null.
#
# DatabaseOverridable: false
# Tags: load
# Type: boolean
auto.resolve.unique.index.ignore.null.values=true

# If this is true, when a reload batch receives a foreign key violation,
# the missing data will be automatically sent to resolve it.
# The resolution is done at the target node by sending a script
Expand All @@ -1110,6 +1101,43 @@ auto.resolve.unique.index.ignore.null.values=true
# Type: boolean
auto.resolve.foreign.key.violation.reverse.reload=true

# If this is true, when a batch receives a foreign key violation due to
# the parent row being updated or deleted, all existing child rows will
# be deleted.
#
# DatabaseOverridable: true
# Tags: load
# Type: boolean
auto.resolve.foreign.key.violation.delete=true

# If this is true, when a batch receives a primary key violation
# during an update, the blocking row will be replaced with the
# updated row.
#
# DatabaseOverridable: true
# Tags: load
# Type: boolean
auto.resolve.primary.key.violation=true

# If this is true, when a batch receives a unique index violation,
# the blocking rows for each unique index will be deleted.
#
# DatabaseOverridable: true
# Tags: load
# Type: boolean
auto.resolve.unique.index.violation=true

# If this is true, when a batch receives a unique index violation,
# the blocking rows for each unique index will only be deleted
# if the unique index has a value that is not null. This only has
# an effect if the auto.resolve.unique.index.violation parameter
# is set to true.
#
# DatabaseOverridable: false
# Tags: load
# Type: boolean
auto.resolve.unique.index.ignore.null.values=true

# Indicate whether the process of inserting data, data_events and outgoing_batches for
# a reload is transactional. The only reason this might be marked as false is to reduce
# possible contention while multiple nodes connect for reloads at the same time.
Expand Down
Expand Up @@ -46,6 +46,9 @@ public class DatabaseWriterSettings {
protected boolean ignoreMissingTables = true;
protected boolean saveCurrentValueOnError = false;
protected boolean fitToColumn = false;
protected boolean autoResolveForeignKeyViolationDelete = true;
protected boolean autoResolvePrimaryKeyViolation = true;
protected boolean autoResolveUniqueIndexViolation = true;
protected boolean autoResolveUniqueIndexIgnoreNullValues = true;
protected boolean logConflictResolution = false;
protected boolean logSqlParamsOnError = true;
Expand Down Expand Up @@ -267,6 +270,30 @@ public boolean isFitToColumn() {
return fitToColumn;
}

public boolean isAutoResolveForeignKeyViolationDelete() {
return autoResolveForeignKeyViolationDelete;
}

public void setAutoResolveForeignKeyViolationDelete(boolean autoResolveForeignKeyViolationDelete) {
this.autoResolveForeignKeyViolationDelete = autoResolveForeignKeyViolationDelete;
}

public boolean isAutoResolvePrimaryKeyViolation() {
return autoResolvePrimaryKeyViolation;
}

public void setAutoResolvePrimaryKeyViolation(boolean autoResolvePrimaryKeyViolation) {
this.autoResolvePrimaryKeyViolation = autoResolvePrimaryKeyViolation;
}

public boolean isAutoResolveUniqueIndexViolation() {
return autoResolveUniqueIndexViolation;
}

public void setAutoResolveUniqueIndexViolation(boolean autoResolveUniqueIndexViolation) {
this.autoResolveUniqueIndexViolation = autoResolveUniqueIndexViolation;
}

public boolean isAutoResolveUniqueIndexIgnoreNullValues() {
return autoResolveUniqueIndexIgnoreNullValues;
}
Expand Down
Expand Up @@ -448,19 +448,29 @@ protected boolean checkForUniqueKeyViolation(AbstractDatabaseWriter writer, CsvD
isUniqueKeyBlocking = true;
}
if (isUniqueKeyBlocking) {
log.info("Unique key violation on table {} during {} with batch {}. Attempting to correct.",
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
for (IIndex index : targetTable.getIndices()) {
if (index.isUnique()) {
log.info("Correcting for possible violation of unique index {} on table {} during {} with batch {}", index.getName(),
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
count += deleteUniqueConstraintRow(platform, sqlTemplate, databaseWriter, targetTable, index, data);
if (writer.getWriterSettings().isAutoResolveUniqueIndexViolation()) {
log.info("Unique key violation on table {} during {} with batch {}. Attempting to correct.",
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
for (IIndex index : targetTable.getIndices()) {
if (index.isUnique()) {
log.info("Correcting for possible violation of unique index {} on table {} during {} with batch {}", index.getName(),
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
count += deleteUniqueConstraintRow(platform, sqlTemplate, databaseWriter, targetTable, index, data);
}
}
} else if (log.isDebugEnabled()) {
log.debug("Did not issue correction for unique key violation on table {} during {} with batch {}.",
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
}
} else if (isPrimaryKeyBlocking) {
log.info("Correcting for update violation of primary key on table {} during {} with batch {}", targetTable.getName(),
data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
count += deleteRow(platform, sqlTemplate, databaseWriter, targetTable, whereColumns, whereValues, false);
if (writer.getWriterSettings().isAutoResolvePrimaryKeyViolation()) {
log.info("Correcting for update violation of primary key on table {} during {} with batch {}", targetTable.getName(),
data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
count += deleteRow(platform, sqlTemplate, databaseWriter, targetTable, whereColumns, whereValues, false);
} else if (log.isDebugEnabled()) {
log.debug("Did not issue correction for update violation of primary key on table {} during {} with batch {}", targetTable.getName(),
data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
}
}
}
return count != 0;
Expand Down Expand Up @@ -583,6 +593,13 @@ protected boolean checkForForeignKeyChildExistsViolation(AbstractDatabaseWriter
ISqlTemplate sqlTemplate = platform.getSqlTemplate();
if (e != null && sqlTemplate.isForeignKeyChildExistsViolation(e)) {
Table targetTable = writer.getTargetTable();
if (!writer.getWriterSettings().isAutoResolveForeignKeyViolationDelete()) {
if (log.isDebugEnabled()) {
log.debug("Did not issue correction for child exists foreign key violation on table {} during {} with batch {}.",
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
}
throw new RuntimeException(e);
}
log.info("Child exists foreign key violation on table {} during {} with batch {}. Attempting to correct.",
targetTable.getName(), data.getDataEventType().toString(), writer.getContext().getBatch().getNodeBatchId());
if (deleteForeignKeyChildren(platform, sqlTemplate, databaseWriter, writer.getTargetTable(), data)) {
Expand Down

0 comments on commit 4482d7b

Please sign in to comment.