GP-4615 Corrected source archive transaction error for various archive

operations (Closes #6503)
This commit is contained in:
ghidra1 2024-05-20 12:42:07 -04:00 committed by Ryan Kurtz
parent 5beb81f8c9
commit 72d9d0eeb2
4 changed files with 76 additions and 68 deletions

View file

@ -84,7 +84,7 @@ import ghidra.util.task.TaskMonitor;
)
//@formatter:on
public class DataTypeManagerPlugin extends ProgramPlugin implements DomainObjectListener,
DataTypeManagerService, DataTypeArchiveService, PopupActionProvider {
DataTypeManagerService, PopupActionProvider {
private static final String EXTENSIONS_PATH_PREFIX = Path.GHIDRA_HOME + "/Extensions";

View file

@ -17,6 +17,7 @@ package ghidra.app.plugin.core.datamgr;
import java.awt.FontMetrics;
import java.util.*;
import java.util.function.Consumer;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
@ -31,8 +32,8 @@ import ghidra.app.util.html.MissingArchiveDataTypeHTMLRepresentation;
import ghidra.program.database.data.*;
import ghidra.program.model.data.*;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.*;
import utility.function.ExceptionalConsumer;
/**
* Class for performing basic functions related to synchronizing data types between a program and
@ -43,8 +44,6 @@ public class DataTypeSynchronizer {
private final DataTypeManager dataTypeManager;
private final SourceArchive sourceArchive;
private final DataTypeManager sourceDTM;
private int sourceTransactionID;
private int localTransactionID;
/**
* Creates a DataTypeSynchronizer to be used for synchronizing data types between a program
@ -63,12 +62,7 @@ public class DataTypeSynchronizer {
}
public List<DataTypeSyncInfo> findOutOfSynchDataTypes() {
// long lastChangeTimeForSource = sourceDTM.getLastChangeTimeForMyManager();
// long lastSyncTimeForSource = sourceArchive.getLastSyncTime();
//
// if (lastChangeTimeForSource == lastSyncTimeForSource && !sourceArchive.isDirty()) {
// return new ArrayList<DataTypeSyncInfo>();
// }
List<DataType> dataTypes = dataTypeManager.getDataTypes(sourceArchive);
List<DataTypeSyncInfo> dataTypeSyncInfo = new ArrayList<>();
@ -91,7 +85,7 @@ public class DataTypeSynchronizer {
return dataTypeSyncInfo;
}
public static void commit(DataTypeManager sourceDTM, DataType refDT) {
private static void commit(DataTypeManager sourceDTM, DataType refDT) {
DataTypeManager refDTM = refDT.getDataTypeManager();
int sourceTransactionID = sourceDTM.startTransaction("Commit Datatype Changes");
int refTransactionID = refDTM.startTransaction("Update DataType Sync Time");
@ -104,7 +98,7 @@ public class DataTypeSynchronizer {
}
}
public static void update(DataTypeManager refDTM, DataType sourceDT) {
private static void update(DataTypeManager refDTM, DataType sourceDT) {
int transactionID = refDTM.startTransaction("Update Datatype");
try {
updateAssumingTransactionsOpen(refDTM, sourceDT);
@ -114,7 +108,7 @@ public class DataTypeSynchronizer {
}
}
public static void commitAssumingTransactionsOpen(DataTypeManager sourceDTM, DataType refDT) {
static void commitAssumingTransactionsOpen(DataTypeManager sourceDTM, DataType refDT) {
// Must refresh associations of refDt and its dependencies to ensure that any
// non-sourced datatype is properly associated to the sourceDTM
@ -138,7 +132,7 @@ public class DataTypeSynchronizer {
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
}
public static void updateAssumingTransactionsOpen(DataTypeManager refDTM, DataType sourceDT) {
static void updateAssumingTransactionsOpen(DataTypeManager refDTM, DataType sourceDT) {
long lastChangeTime = sourceDT.getLastChangeTime();
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
if (!isPointerOrArray(sourceDT)) {
@ -215,20 +209,20 @@ public class DataTypeSynchronizer {
return sourceArchive.getName();
}
public void openTransactions() {
if (sourceDTM != null) {
sourceTransactionID = sourceDTM.startTransaction("Data Type Synchronization");
}
localTransactionID = dataTypeManager.startTransaction("Data Type Synchronization");
}
public void closeTransactions() {
dataTypeManager.endTransaction(localTransactionID, true);
if (sourceDTM != null) {
sourceDTM.endTransaction(sourceTransactionID, true);
}
}
// public void openTransactions() {
//// if (sourceDTM != null) {
//// sourceTransactionID = sourceDTM.startTransaction("Data Type Synchronization");
//// }
// localTransactionID = dataTypeManager.startTransaction("Data Type Synchronization");
// }
//
// public void closeTransactions() {
// dataTypeManager.endTransaction(localTransactionID, true);
//// if (sourceDTM != null) {
//// sourceDTM.endTransaction(sourceTransactionID, true);
//// }
//
// }
/**
* If the indicated data type is associated with a source archive, this will remove the
@ -544,4 +538,33 @@ public class DataTypeSynchronizer {
dataTypeManager.endTransaction(transactionID, true);
}
}
public void performBulkOperation(String actionName, List<DataTypeSyncInfo> selectedList,
ExceptionalConsumer<DataTypeSyncInfo, CancelledException> infoApplier,
Consumer<List<DataTypeSyncInfo>> handleOutOfSync,
boolean sourceRequiresTransaction) throws CancelledException {
if (sourceDTM == null) {
throw new RuntimeException("Source archive required");
}
int sourceTransactionId = sourceRequiresTransaction ?
sourceDTM.startTransaction(actionName) : 0;
int transactionID = dataTypeManager.startTransaction(actionName);
try {
for (DataTypeSyncInfo info : selectedList) {
infoApplier.accept(info);
}
List<DataTypeSyncInfo> outOfSyncList = findOutOfSynchDataTypes();
handleOutOfSync.accept(outOfSyncList);
if (outOfSyncList.isEmpty()) {
markSynchronized();
}
}
finally {
dataTypeManager.endTransaction(transactionID, true);
if (sourceRequiresTransaction) {
sourceDTM.endTransaction(sourceTransactionId, true);
}
}
}
}

View file

@ -229,7 +229,7 @@ public class DisassociateDataTypeAction extends DockingAction {
private void disassociate(DataTypeSynchronizer synchronizer, DataTypeManager dtm,
List<DataType> types, TaskMonitor monitor) throws CancelledException {
synchronizer.openTransactions();
int txId = dtm.startTransaction(getName());
try {
for (DataType dt : types) {
monitor.checkCancelled();
@ -241,7 +241,7 @@ public class DisassociateDataTypeAction extends DockingAction {
synchronizer.reSyncOutOfSyncInTimeOnlyDataTypes();
}
finally {
synchronizer.closeTransactions();
dtm.endTransaction(txId, true);
}
}
}

View file

@ -129,10 +129,9 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
tree.collapseAll(archiveNode);
monitor.setMessage("Finding out-of-sync types");
Set<DataTypeSyncInfo> outOfSynchDataTypes =
new HashSet<>(synchronizer.findOutOfSynchDataTypes());
List<DataTypeSyncInfo> outOfSynchDataTypes = synchronizer.findOutOfSynchDataTypes();
removeAndUpdateOutOfSyncInTimeOnlyDataTypes(synchronizer, outOfSynchDataTypes);
removeAndUpdateOutOfSyncInTimeOnlyDataTypes(synchronizer, synchronizer.findOutOfSynchDataTypes());
if (outOfSynchDataTypes.isEmpty()) {
showNoDataTypesToSyncMessage();
return;
@ -159,11 +158,8 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
monitor.initialize(selectedList.size());
processSelectedDataTypes(synchronizer, selectedList, outOfSynchDataTypes, monitor);
Set<DataTypeSyncInfo> outOfSynchDataTypesAfterProcessed =
new HashSet<>(synchronizer.findOutOfSynchDataTypes());
reportAnyLeftOverOutOfSyncDataTypes(sourceArchive.getName(),
outOfSynchDataTypesAfterProcessed);
synchronizer.findOutOfSynchDataTypes());
}
catch (CancelledException e) {
// nothing to report
@ -184,7 +180,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
}
private void reportAnyLeftOverOutOfSyncDataTypes(String archiveName,
Set<DataTypeSyncInfo> outOfSynchDataTypes) {
List<DataTypeSyncInfo> outOfSynchDataTypes) {
if (outOfSynchDataTypes.isEmpty()) {
return;
}
@ -195,35 +191,24 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
}
private void processSelectedDataTypes(DataTypeSynchronizer synchronizer,
List<DataTypeSyncInfo> selectedList, Set<DataTypeSyncInfo> outOfSynchDataTypes,
protected void processSelectedDataTypes(DataTypeSynchronizer synchronizer,
List<DataTypeSyncInfo> selectedList, List<DataTypeSyncInfo> outOfSynchDataTypes,
TaskMonitor monitor) throws CancelledException {
synchronizer.openTransactions();
try {
for (DataTypeSyncInfo info : selectedList) {
monitor.checkCancelled();
monitor.setMessage("Syncing " + info.getName());
applyOperation(info);
outOfSynchDataTypes.remove(info);
monitor.incrementProgress(1);
}
synchronizer.performBulkOperation(getName(), selectedList, info -> {
monitor.checkCancelled();
monitor.setMessage("Syncing " + info.getName());
applyOperation(info);
outOfSynchDataTypes.remove(info);
monitor.incrementProgress(1);
}, outOfSyncList -> {
// dataTypeChanged can cause other related data types to become updated
// and their times will appear out of sync. So clean up any that actually
// are the same.
Set<DataTypeSyncInfo> outOfSynchDataTypesAfterProcessed =
new HashSet<>(synchronizer.findOutOfSynchDataTypes());
removeAndUpdateOutOfSyncInTimeOnlyDataTypes(synchronizer,
outOfSynchDataTypesAfterProcessed);
if (outOfSynchDataTypesAfterProcessed.isEmpty()) {
synchronizer.markSynchronized();
}
}
finally {
synchronizer.closeTransactions();
}
removeAndUpdateOutOfSyncInTimeOnlyDataTypes(synchronizer, outOfSyncList);
}, requiresArchiveOpenForEditing());
}
private boolean confirmOperation(List<DataTypeSyncInfo> selectedList) {
@ -246,7 +231,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
}
private void showNoDataTypesForThisOperationMessage(String archiveName,
Set<DataTypeSyncInfo> outOfSyncInfos) {
List<DataTypeSyncInfo> outOfSyncInfos) {
String status = getStatusMessage(outOfSyncInfos);
Msg.showInfo(getClass(), plugin.getTool().getToolFrame(), "No Data Type Changes",
"No data types found to " + getOperationName() + " for archive \"" + archiveName +
@ -258,7 +243,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
"Archive \"" + archiveName + "\" must be open for editing.");
}
private String getStatusMessage(Set<DataTypeSyncInfo> outOfSyncInfos) {
private String getStatusMessage(List<DataTypeSyncInfo> outOfSyncInfos) {
int orphanCount = 0;
int conflictCount = 0;
int updateCount = 0;
@ -307,7 +292,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
return getMenuOrder() - o.getMenuOrder();
}
protected List<DataTypeSyncInfo> filterList(Set<DataTypeSyncInfo> allOutOfSyncDataTypes) {
protected List<DataTypeSyncInfo> filterList(List<DataTypeSyncInfo> allOutOfSyncDataTypes) {
List<DataTypeSyncInfo> filteredList = new ArrayList<>();
for (DataTypeSyncInfo dataTypeSyncInfo : allOutOfSyncDataTypes) {
if (isAppropriateForAction(dataTypeSyncInfo)) {
@ -324,7 +309,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
* @param outOfSynchDataTypes list of all datatypes that are marked as "out of sync".
*/
private void removeAndUpdateOutOfSyncInTimeOnlyDataTypes(DataTypeSynchronizer synchronizer,
Set<DataTypeSyncInfo> outOfSynchDataTypes) {
List<DataTypeSyncInfo> outOfSynchDataTypes) {
List<DataTypeSyncInfo> list = new ArrayList<>();
Iterator<DataTypeSyncInfo> iterator = outOfSynchDataTypes.iterator();