mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-4692 Corrected post-checkin/merge update of open
database/domain-object
This commit is contained in:
parent
734ff7b669
commit
bac18feabf
3 changed files with 85 additions and 20 deletions
|
@ -78,8 +78,8 @@ public class BufferMgr {
|
||||||
*/
|
*/
|
||||||
private BufferNode cacheHead;
|
private BufferNode cacheHead;
|
||||||
private BufferNode cacheTail;
|
private BufferNode cacheTail;
|
||||||
private int cacheSize = 0;
|
private int cacheSize;
|
||||||
private int buffersOnHand = 0;
|
private int buffersOnHand;
|
||||||
private int lockCount = 0;
|
private int lockCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -235,6 +235,10 @@ public class BufferMgr {
|
||||||
|
|
||||||
private void initializeCache() throws IOException {
|
private void initializeCache() throws IOException {
|
||||||
|
|
||||||
|
if (lockCount != 0) {
|
||||||
|
throw new IOException("Unable to re-initialize buffer cache while in-use");
|
||||||
|
}
|
||||||
|
|
||||||
if (cacheFile != null) {
|
if (cacheFile != null) {
|
||||||
cacheFile.delete();
|
cacheFile.delete();
|
||||||
}
|
}
|
||||||
|
@ -245,6 +249,9 @@ public class BufferMgr {
|
||||||
cacheHead.nextCached = cacheTail;
|
cacheHead.nextCached = cacheTail;
|
||||||
cacheTail.prevCached = cacheHead;
|
cacheTail.prevCached = cacheHead;
|
||||||
|
|
||||||
|
cacheSize = 0;
|
||||||
|
buffersOnHand = 0;
|
||||||
|
|
||||||
// Create disk cache file
|
// Create disk cache file
|
||||||
cacheFile = new LocalBufferFile(bufferSize, CACHE_FILE_PREFIX, CACHE_FILE_EXT);
|
cacheFile = new LocalBufferFile(bufferSize, CACHE_FILE_PREFIX, CACHE_FILE_EXT);
|
||||||
|
|
||||||
|
@ -258,6 +265,8 @@ public class BufferMgr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetCacheStatistics();
|
||||||
|
|
||||||
if (alwaysPreCache) {
|
if (alwaysPreCache) {
|
||||||
startPreCacheIfNeeded();
|
startPreCacheIfNeeded();
|
||||||
}
|
}
|
||||||
|
@ -2058,7 +2067,7 @@ public class BufferMgr {
|
||||||
public void resetCacheStatistics() {
|
public void resetCacheStatistics() {
|
||||||
cacheHits = 0;
|
cacheHits = 0;
|
||||||
cacheMisses = 0;
|
cacheMisses = 0;
|
||||||
lowWaterMark = cacheSize;
|
lowWaterMark = cacheSize - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStatusInfo() {
|
public String getStatusInfo() {
|
||||||
|
|
|
@ -1149,7 +1149,7 @@ public class GhidraFileData {
|
||||||
|
|
||||||
if (keepCheckedOut) {
|
if (keepCheckedOut) {
|
||||||
|
|
||||||
// Maintain exclusive chekout if private repository or file is open for update
|
// Maintain exclusive checkout if private repository or file is open for update
|
||||||
boolean exclusive = !versionedFileSystem.isShared() || (inUseDomainObj != null);
|
boolean exclusive = !versionedFileSystem.isShared() || (inUseDomainObj != null);
|
||||||
|
|
||||||
ProjectLocator projectLocator = parent.getProjectLocator();
|
ProjectLocator projectLocator = parent.getProjectLocator();
|
||||||
|
@ -1169,6 +1169,11 @@ public class GhidraFileData {
|
||||||
projectLocator.isTransient()));
|
projectLocator.isTransient()));
|
||||||
folderItem.setCheckout(checkout.getCheckoutId(), exclusive,
|
folderItem.setCheckout(checkout.getCheckoutId(), exclusive,
|
||||||
checkout.getCheckoutVersion(), folderItem.getCurrentVersion());
|
checkout.getCheckoutVersion(), folderItem.getCurrentVersion());
|
||||||
|
|
||||||
|
if (inUseDomainObj != null) {
|
||||||
|
// Reset source file and change-sets for open database
|
||||||
|
getContentHandler().resetDBSourceFile(folderItem, inUseDomainObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// NOTE: file open read-only may prevent removal and result in hijack
|
// NOTE: file open read-only may prevent removal and result in hijack
|
||||||
|
@ -1181,9 +1186,6 @@ public class GhidraFileData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
|
||||||
getContentHandler().resetDBSourceFile(folderItem, inUseDomainObj);
|
|
||||||
}
|
|
||||||
} // end of synchronized block
|
} // end of synchronized block
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
if (inUseDomainObj != null) {
|
||||||
|
@ -1535,15 +1537,16 @@ public class GhidraFileData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inUseDomainObj != null) {
|
||||||
|
// Reset source file and change-sets for open database
|
||||||
|
contentHandler.resetDBSourceFile(folderItem, inUseDomainObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
undoCheckout(false, true);
|
undoCheckout(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
|
||||||
contentHandler.resetDBSourceFile(folderItem, inUseDomainObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end of synchronized block
|
} // end of synchronized block
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
if (inUseDomainObj != null) {
|
||||||
|
@ -1915,6 +1918,8 @@ public class GhidraFileData {
|
||||||
try {
|
try {
|
||||||
inUseDomainObj = getAndLockInUseDomainObjectForMergeUpdate("merge");
|
inUseDomainObj = getAndLockInUseDomainObjectForMergeUpdate("merge");
|
||||||
|
|
||||||
|
ContentHandler<?> contentHandler = getContentHandler();
|
||||||
|
|
||||||
if (!modifiedSinceCheckout()) {
|
if (!modifiedSinceCheckout()) {
|
||||||
// Quick merge
|
// Quick merge
|
||||||
folderItem.updateCheckout(versionedFolderItem, true, monitor);
|
folderItem.updateCheckout(versionedFolderItem, true, monitor);
|
||||||
|
@ -1925,8 +1930,6 @@ public class GhidraFileData {
|
||||||
throw new IOException("Merge failed, merge is not supported in headless mode");
|
throw new IOException("Merge failed, merge is not supported in headless mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentHandler<?> contentHandler = getContentHandler();
|
|
||||||
|
|
||||||
// Test versioned file for VersionException
|
// Test versioned file for VersionException
|
||||||
int mergeVer = versionedFolderItem.getCurrentVersion();
|
int mergeVer = versionedFolderItem.getCurrentVersion();
|
||||||
if (!okToUpgrade) {
|
if (!okToUpgrade) {
|
||||||
|
@ -1995,14 +1998,13 @@ public class GhidraFileData {
|
||||||
versionedFolderItem.updateCheckoutVersion(checkoutId, mergeVer,
|
versionedFolderItem.updateCheckoutVersion(checkoutId, mergeVer,
|
||||||
ClientUtil.getUserName());
|
ClientUtil.getUserName());
|
||||||
tmpItem = null;
|
tmpItem = null;
|
||||||
Msg.info(this, "Merge completed for " + name);
|
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
|
||||||
contentHandler.resetDBSourceFile(folderItem, inUseDomainObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Msg.info(this, "Updated checkout completed for " + name);
|
||||||
|
|
||||||
if (inUseDomainObj != null) {
|
if (inUseDomainObj != null) {
|
||||||
|
// Reset source file and change-sets for open database
|
||||||
|
contentHandler.resetDBSourceFile(folderItem, inUseDomainObj);
|
||||||
inUseDomainObj.invalidate();
|
inUseDomainObj.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ import generic.theme.GIcon;
|
||||||
import ghidra.framework.main.projectdata.actions.VersionControlAction;
|
import ghidra.framework.main.projectdata.actions.VersionControlAction;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.model.DomainFolder;
|
import ghidra.framework.model.DomainFolder;
|
||||||
|
import ghidra.program.database.ProgramDB;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
@ -219,7 +221,7 @@ public class VersionControlAction2Test extends AbstractVersionControlActionTest
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForTasks();
|
waitForTasks();
|
||||||
|
|
||||||
Program program = (Program) ((DomainFileNode) node).getDomainFile()
|
ProgramDB program = (ProgramDB) ((DomainFileNode) node).getDomainFile()
|
||||||
.getDomainObject(this,
|
.getDomainObject(this,
|
||||||
true, false, TaskMonitor.DUMMY);
|
true, false, TaskMonitor.DUMMY);
|
||||||
int transactionID = program.startTransaction("test");
|
int transactionID = program.startTransaction("test");
|
||||||
|
@ -254,6 +256,58 @@ public class VersionControlAction2Test extends AbstractVersionControlActionTest
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckInWhileOpen() throws Exception {
|
||||||
|
GTreeNode node = getNode(PROGRAM_A);
|
||||||
|
addToVersionControl(node, false);
|
||||||
|
|
||||||
|
selectNode(node);
|
||||||
|
DockingActionIf action = getAction("CheckOut");
|
||||||
|
runSwing(() -> action.actionPerformed(getDomainFileActionContext(node)), false);
|
||||||
|
waitForSwing();
|
||||||
|
waitForTasks();
|
||||||
|
|
||||||
|
ProgramDB program = (ProgramDB) ((DomainFileNode) node).getDomainFile()
|
||||||
|
.getDomainObject(this,
|
||||||
|
true, false, TaskMonitor.DUMMY);
|
||||||
|
int transactionID = program.startTransaction("test");
|
||||||
|
try {
|
||||||
|
// Ensure that buffer memory cache has been completely consumed
|
||||||
|
// Max BufferMgr cache size is 256*16KByte=4MByte
|
||||||
|
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
|
program.getMemory().createInitializedBlock("BigBlock", space.getAddress(0x80000000L),
|
||||||
|
4*1024*1024, (byte)0xff, TaskMonitor.DUMMY, false);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(transactionID, true);
|
||||||
|
program.save(null, TaskMonitor.DUMMY);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DockingActionIf checkInAction = getAction("CheckIn");
|
||||||
|
runSwing(() -> checkInAction.actionPerformed(getDomainFileActionContext(node)), false);
|
||||||
|
waitForSwing();
|
||||||
|
VersionControlDialog dialog = waitForDialogComponent(VersionControlDialog.class);
|
||||||
|
assertNotNull(dialog);
|
||||||
|
JTextArea textArea = findComponent(dialog, JTextArea.class);
|
||||||
|
assertNotNull(textArea);
|
||||||
|
JCheckBox cb = findComponent(dialog, JCheckBox.class);
|
||||||
|
assertNotNull(cb);
|
||||||
|
runSwing(() -> {
|
||||||
|
textArea.setText("This is a test");
|
||||||
|
cb.setSelected(false);
|
||||||
|
});
|
||||||
|
pressButtonByText(dialog, "OK");
|
||||||
|
waitForTasks();
|
||||||
|
DomainFile df = ((DomainFileNode) node).getDomainFile();
|
||||||
|
assertTrue(df.isCheckedOut());
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.release(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteVersionCheckedOut() throws Exception {
|
public void testDeleteVersionCheckedOut() throws Exception {
|
||||||
// cannot delete a version that is checked out
|
// cannot delete a version that is checked out
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue