From 47391028d8b90f284592a7cda7102b9b87bdef2d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 2 Mar 2024 16:21:32 -0600 Subject: [PATCH] Prevent re-saving unmodified full data --- .../sources/CompleteFullDataSource.java | 2 +- .../fullData/sources/NewFullDataSource.java | 52 +++++++++++++++---- .../render/ColumnRenderSource.java | 7 ++- .../file/AbstractNewDataSourceHandler.java | 22 ++++---- .../core/file/IDataSource.java | 3 +- 5 files changed, 62 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java index 4ed5e4cc7..7b52a298f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java @@ -99,7 +99,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IDa @Deprecated @Override - public void update(NewFullDataSource dataSource, IDhLevel level) { throw new UnsupportedOperationException("Deprecated"); } + public boolean update(NewFullDataSource dataSource, IDhLevel level) { throw new UnsupportedOperationException("Deprecated"); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/NewFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/NewFullDataSource.java index 8eddbcc50..b6b9c2deb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/NewFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/NewFullDataSource.java @@ -37,6 +37,7 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.concurrent.locks.ReentrantLock; /** @@ -150,8 +151,8 @@ public class NewFullDataSource implements IDataSource public SingleColumnFullDataAccessor get(int relX, int relZ) { return new SingleColumnFullDataAccessor(this.mapping, this.dataPoints, relativePosToIndex(relX, relZ)); } @Override - public void update(NewFullDataSource inputDataSource, @Nullable IDhLevel level) { this.update(inputDataSource); } - public void update(NewFullDataSource inputDataSource) + public boolean update(NewFullDataSource inputDataSource, @Nullable IDhLevel level) { return this.update(inputDataSource); } + public boolean update(NewFullDataSource inputDataSource) { byte thisDetailLevel = this.pos.getDetailLevel(); byte inputDetailLevel = inputDataSource.pos.getDetailLevel(); @@ -160,7 +161,7 @@ public class NewFullDataSource implements IDataSource // determine the mapping changes necessary for the input to map onto this datasource int[] remappedIds = this.mapping.mergeAndReturnRemappedEntityIds(inputDataSource.mapping); - boolean dataChanged = false; + boolean dataChanged; if (inputDetailLevel == thisDetailLevel) { dataChanged = this.updateFromSameDetailLevel(inputDataSource, remappedIds); @@ -171,13 +172,11 @@ public class NewFullDataSource implements IDataSource } else { - // TODO what should happen here? - // other detail levels aren't supported since it would be more difficult to maintain // and would lead to edge cases that don't necessarily need to be supported // (IE what do you do when the input is smaller than a single datapoint in the receiving data source?) // instead it's better to just percolate the updates up - //throw new UnsupportedOperationException("Unsupported data source update. Expected input detail level of ["+thisDetailLevel+"] or ["+(thisDetailLevel+1)+"], received detail level ["+inputDetailLevel+"]."); + throw new UnsupportedOperationException("Unsupported data source update. Expected input detail level of ["+thisDetailLevel+"] or ["+(thisDetailLevel+1)+"], received detail level ["+inputDetailLevel+"]."); } if (dataChanged && this.pos.getDetailLevel() < NewFullDataFileHandler.TOP_SECTION_DETAIL_LEVEL) @@ -185,6 +184,8 @@ public class NewFullDataSource implements IDataSource // mark that this data source should be applied to its parent this.applyToParent = true; } + + return dataChanged; } public boolean updateFromSameDetailLevel(NewFullDataSource inputDataSource, int[] remappedIds) { @@ -212,13 +213,22 @@ public class NewFullDataSource implements IDataSource if (inputGenState != EDhApiWorldGenerationStep.EMPTY.value && thisGenState <= inputGenState) { + long[] oldDataArray = this.dataPoints[index]; + + // copy over the new data this.dataPoints[index] = new long[newDataArray.length]; System.arraycopy(newDataArray, 0, this.dataPoints[index], 0, newDataArray.length); this.remapDataColumn(index, remappedIds); - this.columnGenerationSteps[index] = inputGenState; + // we only need to see if the data was changed in one column + if (!dataChanged) + { + // needs to be done after the ID's have been remapped otherwise the ID's won't match even if the data is the same + dataChanged = areDataColumnsDifferent(oldDataArray, this.dataPoints[index]); + } - dataChanged = true; // TODO contents of the arrays should be compared to prevent re-writing the same data + this.columnGenerationSteps[index] = inputGenState; + this.isEmpty = false; } } } @@ -265,13 +275,20 @@ public class NewFullDataSource implements IDataSource int recipientZ = (z / 2) + recipientOffsetZ; int recipientIndex = relativePosToIndex(recipientX, recipientZ); + long[] oldDataArray = this.dataPoints[recipientIndex]; + this.columnGenerationSteps[recipientIndex] = inputGenStep; this.dataPoints[recipientIndex] = inputDataArray; this.remapDataColumn(recipientIndex, remappedIds); - this.isEmpty = false; + // we only need to see if the data was changed in one column + if (!dataChanged) + { + // needs to be done after the ID's have been remapped otherwise the ID's won't match even if the data is the same + dataChanged = areDataColumnsDifferent(oldDataArray, this.dataPoints[recipientIndex]); + } - dataChanged = true; // TODO contents of the arrays should probably be compared or something + this.isEmpty = false; } } } @@ -291,6 +308,21 @@ public class NewFullDataSource implements IDataSource dataColumn[i] = FullDataPointUtil.remap(remappedIds, dataColumn[i]); } } + private static boolean areDataColumnsDifferent(long[] oldDataArray, long[] newDataArray) + { + if (oldDataArray == null || oldDataArray.length != newDataArray.length) + { + // new data was added/removed + return true; + } + else + { + // check if the new column data is different + int oldArrayHash = Arrays.hashCode(oldDataArray); + int newArrayHash = Arrays.hashCode(newDataArray); + return (newArrayHash != oldArrayHash); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index fdebf427e..42870ff5d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -290,7 +290,7 @@ public class ColumnRenderSource implements IDataSource } @Override - public void update(NewFullDataSource inputDataSource, IDhClientLevel level) + public boolean update(NewFullDataSource inputDataSource, IDhClientLevel level) { final String errorMessagePrefix = "Unable to complete update for RenderSource pos: [" + this.sectionPos + "] and pos: [" + inputDataSource.getSectionPos() + "]. Error:"; @@ -302,7 +302,7 @@ public class ColumnRenderSource implements IDataSource if (Thread.interrupted()) { LOGGER.warn(errorMessagePrefix + "write interrupted."); - return; + return false; } @@ -340,11 +340,14 @@ public class ColumnRenderSource implements IDataSource } + if (dataChanged) { this.localVersion.incrementAndGet(); this.markNotEmpty(); } + + return dataChanged; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractNewDataSourceHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractNewDataSourceHandler.java index ac003e9f4..8978ae0af 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractNewDataSourceHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/AbstractNewDataSourceHandler.java @@ -210,19 +210,21 @@ public abstract class AbstractNewDataSourceHandler // get or create the data source TDataSource dataSource = this.get(pos); - dataSource.update(inputData, this.level); // TODO only write to database and send update signal if data was changed + boolean dataModified = dataSource.update(inputData, this.level); - - // save the updated data to the database - TDTO dto = this.createDtoFromDataSource(dataSource); - this.repo.save(dto); - - - for (IDataSourceUpdateFunc listener : this.dateSourceUpdateListeners) + if (dataModified) { - if (listener != null) + // save the updated data to the database + TDTO dto = this.createDtoFromDataSource(dataSource); + this.repo.save(dto); + + + for (IDataSourceUpdateFunc listener : this.dateSourceUpdateListeners) { - listener.OnDataSourceUpdated(dataSource); + if (listener != null) + { + listener.OnDataSourceUpdated(dataSource); + } } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java index 5a61dd2e7..c4ae71ee1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java @@ -25,7 +25,8 @@ public interface IDataSource extends IBaseDTO