mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-27 23:17:03 +08:00
Merge remote-tracking branch 'origin/GP-6392_Dan_fixSaveOnCloseDeadlock-take4--SQUASHED' into patch
This commit is contained in:
+1
-1
@@ -634,7 +634,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Collection<Trace> getOpenTraces() {
|
public Collection<Trace> getOpenTraces() {
|
||||||
synchronized (listenersByTrace) {
|
synchronized (listenersByTrace) {
|
||||||
return Set.copyOf(tracesView);
|
return Set.copyOf(tracesView);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-13
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.trace.database;
|
package ghidra.trace.database;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -876,16 +875,10 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void save(String comment, TaskMonitor monitor) throws IOException, CancelledException {
|
protected void prepareToSave() {
|
||||||
objectManager.flushWbCaches();
|
try (Transaction tx = openForcedTransaction("flush for save")) {
|
||||||
super.save(comment, monitor);
|
objectManager.flushWbCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveToPackedFile(File outputFile, TaskMonitor monitor)
|
|
||||||
throws IOException, CancelledException {
|
|
||||||
objectManager.flushWbCaches();
|
|
||||||
super.saveToPackedFile(outputFile, monitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isClosing() {
|
public boolean isClosing() {
|
||||||
@@ -895,9 +888,9 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||||||
@Override
|
@Override
|
||||||
protected void close() {
|
protected void close() {
|
||||||
closing = true;
|
closing = true;
|
||||||
objectManager.flushWbCaches();
|
// NOTE: Any unsaved changes in the write-back cache are unrecoverable
|
||||||
super.close();
|
|
||||||
objectManager.waitWbWorkers();
|
objectManager.waitWbWorkers();
|
||||||
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-4
@@ -41,16 +41,16 @@ public class DBTraceContentHandler extends DBWithUserDataContentHandler<DBTrace>
|
|||||||
static final Class<DBTrace> TRACE_DOMAIN_OBJECT_CLASS = DBTrace.class;
|
static final Class<DBTrace> TRACE_DOMAIN_OBJECT_CLASS = DBTrace.class;
|
||||||
static final String TRACE_CONTENT_DEFAULT_TOOL = "Debugger";
|
static final String TRACE_CONTENT_DEFAULT_TOOL = "Debugger";
|
||||||
|
|
||||||
private static final DBTraceLinkContentHandler linkHandler = new DBTraceLinkContentHandler();
|
private static final DBTraceLinkContentHandler LINK_HANDLER = new DBTraceLinkContentHandler();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long createFile(FileSystem fs, FileSystem userfs, String path, String name,
|
public long createFile(FileSystem fs, FileSystem userfs, String path, String name,
|
||||||
DomainObject obj, TaskMonitor monitor)
|
DomainObject obj, TaskMonitor monitor)
|
||||||
throws IOException, InvalidNameException, CancelledException {
|
throws IOException, InvalidNameException, CancelledException {
|
||||||
if (!(obj instanceof DBTrace)) {
|
if (!(obj instanceof DBTrace trace)) {
|
||||||
throw new IOException("Unsupported domain object: " + obj.getClass().getName());
|
throw new IOException("Unsupported domain object: " + obj.getClass().getName());
|
||||||
}
|
}
|
||||||
return createFile((DBTrace) obj, TRACE_CONTENT_TYPE, fs, path, name, monitor);
|
return createFile(trace, TRACE_CONTENT_TYPE, fs, path, name, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -340,6 +340,6 @@ public class DBTraceContentHandler extends DBWithUserDataContentHandler<DBTrace>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceLinkContentHandler getLinkHandler() {
|
public DBTraceLinkContentHandler getLinkHandler() {
|
||||||
return linkHandler;
|
return LINK_HANDLER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -40,8 +40,9 @@ class DBTraceObjectValueWriteBehindCache {
|
|||||||
private final AsyncReference<Boolean, Void> busy = new AsyncReference<>(false);
|
private final AsyncReference<Boolean, Void> busy = new AsyncReference<>(false);
|
||||||
private volatile boolean flushing = false;
|
private volatile boolean flushing = false;
|
||||||
|
|
||||||
private final Map<DBTraceObject, Map<String, NavigableMap<Long, DBTraceObjectValueBehind>>> cachedValues =
|
private final Map<DBTraceObject,
|
||||||
new HashMap<>();
|
Map<String, NavigableMap<Long, DBTraceObjectValueBehind>>> cachedValues =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
public DBTraceObjectValueWriteBehindCache(DBTraceObjectManager manager) {
|
public DBTraceObjectValueWriteBehindCache(DBTraceObjectManager manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@@ -51,7 +52,7 @@ class DBTraceObjectValueWriteBehindCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void workLoop() {
|
private void workLoop() {
|
||||||
while (!manager.trace.isClosed()) {
|
while (!manager.trace.isClosing()) {
|
||||||
try {
|
try {
|
||||||
synchronized (cachedValues) {
|
synchronized (cachedValues) {
|
||||||
if (cachedValues.isEmpty()) {
|
if (cachedValues.isEmpty()) {
|
||||||
@@ -69,7 +70,7 @@ class DBTraceObjectValueWriteBehindCache {
|
|||||||
cachedValues.wait(left);
|
cachedValues.wait(left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (manager.trace.isClosed()) {
|
if (manager.trace.isClosing()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writeBatch();
|
writeBatch();
|
||||||
|
|||||||
+2
-2
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|||||||
+39
-26
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -55,31 +55,36 @@ abstract class AbstractTransactionManager {
|
|||||||
|
|
||||||
checkLockingTask();
|
checkLockingTask();
|
||||||
|
|
||||||
|
boolean doPrepare = false;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (getCurrentTransactionInfo() != null && !transactionTerminated) {
|
if (getCurrentTransactionInfo() != null && !transactionTerminated) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lockCount == 0) {
|
if (lockCount == 0) {
|
||||||
for (DomainObjectAdapterDB domainObj : getDomainObjects()) {
|
doPrepare = true;
|
||||||
if (domainObj.isChanged()) {
|
|
||||||
domainObj.prepareToSave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lockReason = reason;
|
lockReason = reason;
|
||||||
++lockCount;
|
++lockCount;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
if (doPrepare) {
|
||||||
|
for (DomainObjectAdapterDB domainObj : getDomainObjects()) {
|
||||||
|
if (domainObj.isChanged()) {
|
||||||
|
domainObj.prepareToSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to obtain a modification lock on the domain object when generating a
|
* Attempt to obtain a modification lock on the domain object when generating a background
|
||||||
* background snapshot.
|
* snapshot.
|
||||||
|
*
|
||||||
* @param domainObj domain object corresponding to snapshot
|
* @param domainObj domain object corresponding to snapshot
|
||||||
* @param hasProgress true if monitor has progress indicator
|
* @param hasProgress true if monitor has progress indicator
|
||||||
* @param title title to be used for monitor
|
* @param title title to be used for monitor
|
||||||
* @return monitor object if lock obtained successfully, else null which indicates that a
|
* @return monitor object if lock obtained successfully, else null which indicates that a
|
||||||
* modification is in process.
|
* modification is in process.
|
||||||
*/
|
*/
|
||||||
final synchronized LockingTaskMonitor lockForSnapshot(DomainObjectAdapterDB domainObj,
|
final synchronized LockingTaskMonitor lockForSnapshot(DomainObjectAdapterDB domainObj,
|
||||||
boolean hasProgress, String title) {
|
boolean hasProgress, String title) {
|
||||||
@@ -106,9 +111,10 @@ abstract class AbstractTransactionManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Force transaction lock and terminate current transaction.
|
* Force transaction lock and terminate current transaction.
|
||||||
|
*
|
||||||
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
||||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete transaction
|
* should be done. NOTE: it can be potentially detrimental to commit an incomplete
|
||||||
* and should be avoided.
|
* transaction and should be avoided.
|
||||||
* @param reason very short reason for requesting lock
|
* @param reason very short reason for requesting lock
|
||||||
*/
|
*/
|
||||||
final void forceLock(boolean rollback, String reason) {
|
final void forceLock(boolean rollback, String reason) {
|
||||||
@@ -131,9 +137,10 @@ abstract class AbstractTransactionManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate current transaction.
|
* Terminate current transaction.
|
||||||
|
*
|
||||||
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
||||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete transaction
|
* should be done. NOTE: it can be potentially detrimental to commit an incomplete
|
||||||
* and should be avoided.
|
* transaction and should be avoided.
|
||||||
* @param notify true for listeners to be notified else false
|
* @param notify true for listeners to be notified else false
|
||||||
*/
|
*/
|
||||||
abstract void terminateTransaction(boolean rollback, boolean notify);
|
abstract void terminateTransaction(boolean rollback, boolean notify);
|
||||||
@@ -159,8 +166,7 @@ abstract class AbstractTransactionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block on active locking task.
|
* Block on active locking task. Do not invoke this method from within a synchronized block.
|
||||||
* Do not invoke this method from within a synchronized block.
|
|
||||||
*/
|
*/
|
||||||
final void checkLockingTask() {
|
final void checkLockingTask() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -173,6 +179,7 @@ abstract class AbstractTransactionManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw lock exception if currently locked
|
* Throw lock exception if currently locked
|
||||||
|
*
|
||||||
* @throws DomainObjectLockedException if currently locked
|
* @throws DomainObjectLockedException if currently locked
|
||||||
*/
|
*/
|
||||||
final void verifyNoLock() throws DomainObjectLockedException {
|
final void verifyNoLock() throws DomainObjectLockedException {
|
||||||
@@ -194,7 +201,7 @@ abstract class AbstractTransactionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final int startTransaction(DomainObjectAdapterDB object, String description,
|
final int startTransactionChecked(DomainObjectAdapterDB object, String description,
|
||||||
AbortedTransactionListener listener, boolean notify)
|
AbortedTransactionListener listener, boolean notify)
|
||||||
throws TerminatedTransactionException {
|
throws TerminatedTransactionException {
|
||||||
|
|
||||||
@@ -222,47 +229,53 @@ abstract class AbstractTransactionManager {
|
|||||||
boolean commit, boolean notify) throws IllegalStateException;
|
boolean commit, boolean notify) throws IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the undo stack depth.
|
* Returns the undo stack depth. (The number of items on the undo stack) This method is for
|
||||||
* (The number of items on the undo stack)
|
* JUnits.
|
||||||
* This method is for JUnits.
|
*
|
||||||
* @return the undo stack depth
|
* @return the undo stack depth
|
||||||
*/
|
*/
|
||||||
abstract int getUndoStackDepth();
|
abstract int getUndoStackDepth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is at least one redo transaction to be redone.
|
* Returns true if there is at least one redo transaction to be redone.
|
||||||
|
*
|
||||||
* @return true if there is at least one redo transaction to be redone
|
* @return true if there is at least one redo transaction to be redone
|
||||||
*/
|
*/
|
||||||
abstract boolean canRedo();
|
abstract boolean canRedo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is at least one undo transaction to be undone.
|
* Returns true if there is at least one undo transaction to be undone.
|
||||||
|
*
|
||||||
* @return true if there is at least one undo transaction to be undone
|
* @return true if there is at least one undo transaction to be undone
|
||||||
*/
|
*/
|
||||||
abstract boolean canUndo();
|
abstract boolean canUndo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the next undo transaction (The most recent change).
|
* Returns the name of the next undo transaction (The most recent change).
|
||||||
|
*
|
||||||
* @return the name of the next undo transaction (The most recent change)
|
* @return the name of the next undo transaction (The most recent change)
|
||||||
*/
|
*/
|
||||||
abstract String getRedoName();
|
abstract String getRedoName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the next redo transaction (The most recent undo).
|
* Returns the name of the next redo transaction (The most recent undo).
|
||||||
|
*
|
||||||
* @return the name of the next redo transaction (The most recent undo)
|
* @return the name of the next redo transaction (The most recent undo)
|
||||||
*/
|
*/
|
||||||
abstract String getUndoName();
|
abstract String getUndoName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the names of all undoable transactions in reverse chronological order. In other
|
* Returns the names of all undoable transactions in reverse chronological order. In other words
|
||||||
* words the transaction at the top of the list must be undone first.
|
* the transaction at the top of the list must be undone first.
|
||||||
|
*
|
||||||
* @return the names of all undoable transactions in reverse chronological order
|
* @return the names of all undoable transactions in reverse chronological order
|
||||||
*/
|
*/
|
||||||
abstract List<String> getAllUndoNames();
|
abstract List<String> getAllUndoNames();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the names of all redoable transactions in chronological order. In other words
|
* Returns the names of all redoable transactions in chronological order. In other words the
|
||||||
* the transaction at the top of the list must be redone first.
|
* transaction at the top of the list must be redone first.
|
||||||
|
*
|
||||||
* @return the names of all redoable transactions in chronological order
|
* @return the names of all redoable transactions in chronological order
|
||||||
*/
|
*/
|
||||||
abstract List<String> getAllRedoNames();
|
abstract List<String> getAllRedoNames();
|
||||||
@@ -321,7 +334,7 @@ abstract class AbstractTransactionManager {
|
|||||||
abstract void doClose(DomainObjectAdapterDB object);
|
abstract void doClose(DomainObjectAdapterDB object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set instance as immutable by disabling use of transactions. Attempts to start a transaction
|
* Set instance as immutable by disabling use of transactions. Attempts to start a transaction
|
||||||
* will result in a {@link TerminatedTransactionException}.
|
* will result in a {@link TerminatedTransactionException}.
|
||||||
*/
|
*/
|
||||||
public void setImmutable() {
|
public void setImmutable() {
|
||||||
|
|||||||
+41
-24
@@ -133,7 +133,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
|||||||
* using a shared transaction manager. If either or both is already shared,
|
* using a shared transaction manager. If either or both is already shared,
|
||||||
* a transition to a single shared transaction manager will be
|
* a transition to a single shared transaction manager will be
|
||||||
* performed.
|
* performed.
|
||||||
* @param domainObj
|
* @param domainObj the domain object to synchronize with
|
||||||
* @throws LockException if lock or open transaction is active on either
|
* @throws LockException if lock or open transaction is active on either
|
||||||
* this or the specified domain object
|
* this or the specified domain object
|
||||||
*/
|
*/
|
||||||
@@ -184,7 +184,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the open handle to the underlying database.
|
* {@return the open handle to the underlying database}
|
||||||
*/
|
*/
|
||||||
public DBHandle getDBHandle() {
|
public DBHandle getDBHandle() {
|
||||||
return dbh;
|
return dbh;
|
||||||
@@ -259,17 +259,17 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
|||||||
return transactionMgr.lock(reason);
|
return transactionMgr.lock(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepareToSave() {
|
/**
|
||||||
int txId = transactionMgr.startTransaction(this, "Update Metadata", null, true, true);
|
* Prepare to save and store any last minute DB data. The default behavior is to invoke
|
||||||
try {
|
* {@link #updateMetadata()}.
|
||||||
|
*/
|
||||||
|
protected void prepareToSave() {
|
||||||
|
try (Transaction tx = openForcedTransaction("Update Metadata")) {
|
||||||
updateMetadata();
|
updateMetadata();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
dbError(e);
|
dbError(e);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
transactionMgr.endTransaction(this, txId, true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,24 +310,40 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
|||||||
transactionMgr.unlock(handler);
|
transactionMgr.unlock(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DomainObjectTransaction extends Transaction {
|
||||||
|
private final int txId;
|
||||||
|
|
||||||
|
DomainObjectTransaction(int txId) {
|
||||||
|
this.txId = txId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean endTransaction(boolean commit) {
|
||||||
|
DomainObjectAdapterDB.this.endTransaction(txId, commit);
|
||||||
|
return commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSubTransaction() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open forced transaction which bypasses any lock checking, although method should only be
|
||||||
|
* used in very controlled situations where a save lock is in place.
|
||||||
|
* @param description transaction description
|
||||||
|
* @return {@link AutoCloseable} transaction object
|
||||||
|
*/
|
||||||
|
protected Transaction openForcedTransaction(String description) {
|
||||||
|
int txId = transactionMgr.startTransaction(this, description, null, true, true);
|
||||||
|
return new DomainObjectTransaction(txId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Transaction openTransaction(String description)
|
public Transaction openTransaction(String description)
|
||||||
throws TerminatedTransactionException, IllegalStateException {
|
throws TerminatedTransactionException, IllegalStateException {
|
||||||
return new Transaction() {
|
return new DomainObjectTransaction(startTransaction(description));
|
||||||
|
|
||||||
int txId = startTransaction(description);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean endTransaction(boolean commit) {
|
|
||||||
DomainObjectAdapterDB.this.endTransaction(txId, commit);
|
|
||||||
return commit;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSubTransaction() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -348,7 +364,8 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
return transactionMgr.startTransaction(this, description, listener, true);
|
return transactionMgr.startTransactionChecked(this, description, listener,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
catch (DomainObjectLockedException e) {
|
catch (DomainObjectLockedException e) {
|
||||||
if (!exceptionHandler.apply(e)) {
|
if (!exceptionHandler.apply(e)) {
|
||||||
|
|||||||
+5
-4
@@ -103,11 +103,12 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
|
|||||||
throw new IllegalArgumentException("invalid domain object");
|
throw new IllegalArgumentException("invalid domain object");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!force) {
|
|
||||||
verifyNoLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
|
|
||||||
|
if (!force) {
|
||||||
|
verifyNoLock();
|
||||||
|
}
|
||||||
|
|
||||||
transactionTerminated = false;
|
transactionTerminated = false;
|
||||||
transaction =
|
transaction =
|
||||||
new DomainObjectDBTransaction(domainObj.dbh.startTransaction(), domainObj);
|
new DomainObjectDBTransaction(domainObj.dbh.startTransaction(), domainObj);
|
||||||
|
|||||||
@@ -1037,7 +1037,7 @@ class GhidraFolderData {
|
|||||||
if (doa.isClosed()) {
|
if (doa.isClosed()) {
|
||||||
throw new ClosedException();
|
throw new ClosedException();
|
||||||
}
|
}
|
||||||
if (!doa.lock(null)) {
|
if (!doa.lock("create file")) {
|
||||||
throw new IOException("Object is busy and can not be saved");
|
throw new IOException("Object is busy and can not be saved");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -152,11 +152,12 @@ class SynchronizedTransactionManager extends AbstractTransactionManager {
|
|||||||
synchronized int startTransaction(DomainObjectAdapterDB object, String description,
|
synchronized int startTransaction(DomainObjectAdapterDB object, String description,
|
||||||
AbortedTransactionListener listener, boolean force, boolean notify) {
|
AbortedTransactionListener listener, boolean force, boolean notify) {
|
||||||
|
|
||||||
if (!force) {
|
|
||||||
verifyNoLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
|
|
||||||
|
if (!force) {
|
||||||
|
verifyNoLock();
|
||||||
|
}
|
||||||
|
|
||||||
transactionTerminated = false;
|
transactionTerminated = false;
|
||||||
transaction = new SynchronizedTransaction(domainObjectTransactionManagers);
|
transaction = new SynchronizedTransaction(domainObjectTransactionManagers);
|
||||||
int txId = transaction.addEntry(object, description, listener);
|
int txId = transaction.addEntry(object, description, listener);
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ class FileActionManager {
|
|||||||
locked = false;
|
locked = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!domainObjects[lastIndex].lock(null)) {
|
if (!domainObjects[lastIndex].lock("save changes")) {
|
||||||
String title = "Exit Ghidra";
|
String title = "Exit Ghidra";
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
DomainObject d = domainObjects[lastIndex];
|
DomainObject d = domainObjects[lastIndex];
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ public interface DomainObject {
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param description a short description of the changes to be made.
|
* @param description a short description of the changes to be made.
|
||||||
* @return transaction object
|
* @return {@link AutoCloseable} transaction object
|
||||||
* @throws IllegalStateException if this {@link DomainObject} has already been closed.
|
* @throws IllegalStateException if this {@link DomainObject} has already been closed.
|
||||||
*/
|
*/
|
||||||
public Transaction openTransaction(String description) throws IllegalStateException;
|
public Transaction openTransaction(String description) throws IllegalStateException;
|
||||||
|
|||||||
Reference in New Issue
Block a user