Merge remote-tracking branch 'origin/patch'

Conflicts:
	Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDatabase.java
This commit is contained in:
Ryan Kurtz
2024-03-06 13:24:56 -05:00
4 changed files with 82 additions and 98 deletions

View File

@@ -25,6 +25,7 @@ import db.buffers.BufferFileManager;
import db.buffers.LocalManagedBufferFile; import db.buffers.LocalManagedBufferFile;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.store.FileSystemInitializer;
import ghidra.framework.store.FolderItem; import ghidra.framework.store.FolderItem;
import ghidra.framework.store.db.PackedDatabaseCache.CachedDB; import ghidra.framework.store.db.PackedDatabaseCache.CachedDB;
import ghidra.framework.store.local.*; import ghidra.framework.store.local.*;
@@ -80,7 +81,7 @@ public class PackedDatabase extends Database {
* Constructor for an existing packed database which will be unpacked into * Constructor for an existing packed database which will be unpacked into
* a temporary dbDir. * a temporary dbDir.
* @param packedDbFile existing packed database file. * @param packedDbFile existing packed database file.
* @throws IOException * @throws IOException if an IO error occurs
*/ */
private PackedDatabase(ResourceFile packedDbFile) throws IOException { private PackedDatabase(ResourceFile packedDbFile) throws IOException {
super(createDBDir(), null, true); super(createDBDir(), null, true);
@@ -106,14 +107,14 @@ public class PackedDatabase extends Database {
/** /**
* Constructor for an existing packed database backed by a unpacking cache * Constructor for an existing packed database backed by a unpacking cache
* @param packedDbFile * @param cachedDb cached packed DB to be opened.
* @param packedDbFile packed DB file which corresponds to {@code cacheDb}
* @param packedDbLock read lock, null signals read only database * @param packedDbLock read lock, null signals read only database
* @param cachedDb * @param monitor unpack monitor used if refresh required
* @param monitor * @throws CancelledException is unpack is cancelled
* @throws CancelledException * @throws IOException if IO error occurs
* @throws IOException
*/ */
PackedDatabase(ResourceFile packedDbFile, LockFile packedDbLock, CachedDB cachedDb, PackedDatabase(CachedDB cachedDb, ResourceFile packedDbFile, LockFile packedDbLock,
TaskMonitor monitor) throws CancelledException, IOException { TaskMonitor monitor) throws CancelledException, IOException {
super(cachedDb.dbDir, null, false); super(cachedDb.dbDir, null, false);
this.packedDbFile = packedDbFile; this.packedDbFile = packedDbFile;
@@ -146,15 +147,15 @@ public class PackedDatabase extends Database {
/** /**
* Constructor for a new packed database which will be created from an * Constructor for a new packed database which will be created from an
* open PackedDBHandle. * open {@link PackedDBHandle dbHandle}.
* @param dbHandle * @param dbHandle packed DB handle
* @param packedDbFile * @param packedDbFile packed DB file which corresponds to {@code dbHandle}
* @param itemName * @param itemName DB name
* @param newDatabaseId database ID to be forced for new database or null to generate * @param newDatabaseId database ID to be forced for new database or null to generate
* new database ID * new database ID
* @param monitor * @param monitor DB save/pack monitor
* @throws CancelledException * @throws CancelledException if packed file creation is cancelled
* @throws IOException * @throws IOException if IO error occurs
*/ */
PackedDatabase(PackedDBHandle dbHandle, ResourceFile packedDbFile, String itemName, PackedDatabase(PackedDBHandle dbHandle, ResourceFile packedDbFile, String itemName,
Long newDatabaseId, TaskMonitor monitor) throws CancelledException, IOException { Long newDatabaseId, TaskMonitor monitor) throws CancelledException, IOException {
@@ -238,12 +239,12 @@ public class PackedDatabase extends Database {
} }
/** /**
* Get a packed database which whose unpacking will be cached if possible * Get a packed database which whose unpacking will be cached if possible.
* @param packedDbFile * @param packedDbFile packed database file to be opened
* @param monitor * @param monitor unpack/open monitor
* @return packed database which corresponds to the specified packedDbFile * @return packed database which corresponds to the specified packedDbFile
* @throws IOException * @throws IOException if IO error occurs
* @throws CancelledException * @throws CancelledException if unpack/open is cancelled
*/ */
public static PackedDatabase getPackedDatabase(File packedDbFile, TaskMonitor monitor) public static PackedDatabase getPackedDatabase(File packedDbFile, TaskMonitor monitor)
throws IOException, CancelledException { throws IOException, CancelledException {
@@ -253,12 +254,12 @@ public class PackedDatabase extends Database {
/** /**
* Get a packed database whose unpacking may be cached if possible * Get a packed database whose unpacking may be cached if possible
* provided doNotCache is false. * provided doNotCache is false.
* @param packedDbFile * @param packedDbFile packed database file to be opened
* @param neverCache if true unpacking will never be cache. * @param neverCache if true unpacking will never be cache.
* @param monitor * @param monitor unpack/open monitor
* @return packed database which corresponds to the specified packedDbFile * @return packed database which corresponds to the specified packedDbFile
* @throws IOException * @throws IOException if IO error occurs
* @throws CancelledException * @throws CancelledException if unpack/open is cancelled
*/ */
public static PackedDatabase getPackedDatabase(File packedDbFile, boolean neverCache, public static PackedDatabase getPackedDatabase(File packedDbFile, boolean neverCache,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
@@ -268,14 +269,14 @@ public class PackedDatabase extends Database {
/** /**
* Get a packed database whose unpacking may be cached if possible * Get a packed database whose unpacking may be cached if possible
* provided doNotCache is false. * provided doNotCache is false.
* @param packedDbFile * @param packedDbFile packed database resource file to be opened
* @param neverCache if true unpacking will never be cache. * @param neverCache if true unpacking will never be cache.
* @param monitor * @param monitor unpack/open monitor
* @return packed database which corresponds to the specified packedDbFile * @return packed database which corresponds to the specified packedDbFile
* @throws IOException * @throws IOException if IO error occurs
* @throws CancelledException * @throws CancelledException if unpack/open is cancelled
*/ */
public static PackedDatabase getPackedDatabase(ResourceFile packedDbFile, boolean neverCache, public static synchronized PackedDatabase getPackedDatabase(ResourceFile packedDbFile, boolean neverCache,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
if (!neverCache && PackedDatabaseCache.isEnabled()) { if (!neverCache && PackedDatabaseCache.isEnabled()) {
try { try {
@@ -291,8 +292,8 @@ public class PackedDatabase extends Database {
/** /**
* Check for the presence of directory read-only lock * Check for the presence of directory read-only lock
* @param directory * @param directory directory to check for read-only lock
* @return true if read-only lock exists+ * @return true if read-only lock exists
*/ */
public static boolean isReadOnlyPDBDirectory(ResourceFile directory) { public static boolean isReadOnlyPDBDirectory(ResourceFile directory) {
File dir = directory.getFile(false); File dir = directory.getFile(false);
@@ -324,7 +325,7 @@ public class PackedDatabase extends Database {
* Free resources consumed by this object. * Free resources consumed by this object.
* If there is an associated database handle it will be closed. * If there is an associated database handle it will be closed.
*/ */
public void dispose() { public synchronized void dispose() {
if (!isCached && dbDir != null && dbDir.exists()) { if (!isCached && dbDir != null && dbDir.exists()) {
File tmpDbDir = new File(dbDir.getParentFile(), dbDir.getName() + ".delete"); File tmpDbDir = new File(dbDir.getParentFile(), dbDir.getName() + ".delete");
if (!dbDir.renameTo(tmpDbDir)) { if (!dbDir.renameTo(tmpDbDir)) {
@@ -360,7 +361,7 @@ public class PackedDatabase extends Database {
* Creates a temporary directory which will be used for storing * Creates a temporary directory which will be used for storing
* the unpacked database files. * the unpacked database files.
* @return temporary database directory * @return temporary database directory
* @throws IOException * @throws IOException if failed to create DB directory
*/ */
private static File createDBDir() throws IOException { private static File createDBDir() throws IOException {
@@ -377,15 +378,18 @@ public class PackedDatabase extends Database {
/** /**
* Returns the update lock file for the specified packedFile. * Returns the update lock file for the specified packedFile.
* @param packedFile * @param packedFile packed DB file which requires an update lock file
* @return update lock file
*/ */
private static LockFile getUpdateLock(File packedFile) { private static LockFile getUpdateLock(File packedFile) {
return new LockFile(packedFile.getParentFile(), packedFile.getName(), UPDATE_LOCK_TYPE); return new LockFile(packedFile.getParentFile(), packedFile.getName(), UPDATE_LOCK_TYPE);
} }
/** /**
* Returns the general lock file for the specified packedFile. * Returns the general lock file for the specified packedFile needed to facilitate
* @param packedFile * unpacking and read-only use.
* @param packedFile packed DB file which requires a general lock file
* @return general lock file
*/ */
static LockFile getFileLock(File packedFile) { static LockFile getFileLock(File packedFile) {
return new LockFile(packedFile.getParentFile(), packedFile.getName()); return new LockFile(packedFile.getParentFile(), packedFile.getName());
@@ -393,6 +397,7 @@ public class PackedDatabase extends Database {
/** /**
* Returns the user defined content type associated with this database. * Returns the user defined content type associated with this database.
* @return packed DB content type
*/ */
public String getContentType() { public String getContentType() {
return contentType; return contentType;
@@ -400,6 +405,7 @@ public class PackedDatabase extends Database {
/** /**
* Returns the storage file associated with this packed database. * Returns the storage file associated with this packed database.
* @return associated packed DB file
*/ */
public ResourceFile getPackedFile() { public ResourceFile getPackedFile() {
return packedDbFile; return packedDbFile;
@@ -409,9 +415,9 @@ public class PackedDatabase extends Database {
* Deletes the storage file associated with this packed database. * Deletes the storage file associated with this packed database.
* This method should not be called while the database is open, if * This method should not be called while the database is open, if
* it is an attempt will be made to close the handle. * it is an attempt will be made to close the handle.
* @throws IOException * @throws IOException if IO error occurs (e.g., file in-use or write-protected)
*/ */
public void delete() throws IOException { public synchronized void delete() throws IOException {
if (isReadOnly) { if (isReadOnly) {
throw new ReadOnlyException( throw new ReadOnlyException(
"Read-only DB directory lock, file removal not allowed: " + packedDbFile); "Read-only DB directory lock, file removal not allowed: " + packedDbFile);
@@ -430,9 +436,11 @@ public class PackedDatabase extends Database {
/** /**
* Deletes the storage file associated with this packed database. * Deletes the storage file associated with this packed database.
* @throws IOException * @param packedDbFile packed DB file to be removed
* @throws FileInUseException if packed DB is currently locked and in use
* @throws IOException if an IO error occurs (e.g., file in-use or write-protected)
*/ */
public static void delete(File packedDbFile) throws IOException { public static synchronized void delete(File packedDbFile) throws IOException {
LockFile updateLock = getUpdateLock(packedDbFile); LockFile updateLock = getUpdateLock(packedDbFile);
lock(updateLock, false, false); lock(updateLock, false, false);
try { try {
@@ -450,7 +458,7 @@ public class PackedDatabase extends Database {
* @param lockFile general or update lock file * @param lockFile general or update lock file
* @param wait if true, block until lock is obtained. * @param wait if true, block until lock is obtained.
* @param hold if true, hold lock until released. * @param hold if true, hold lock until released.
* @throws FileInUseException * @throws FileInUseException if lock is already active and failed to acquire
*/ */
static void lock(LockFile lockFile, boolean wait, boolean hold) throws FileInUseException { static void lock(LockFile lockFile, boolean wait, boolean hold) throws FileInUseException {
if (!lockFile.createLock(wait ? LOCK_TIMEOUT : 0, hold)) { if (!lockFile.createLock(wait ? LOCK_TIMEOUT : 0, hold)) {
@@ -465,7 +473,7 @@ public class PackedDatabase extends Database {
/** /**
* Read user content type and name from packed file. * Read user content type and name from packed file.
* @throws IOException * @throws IOException if IO error occurs
*/ */
private void readContentTypeAndName() throws IOException { private void readContentTypeAndName() throws IOException {
@@ -497,7 +505,8 @@ public class PackedDatabase extends Database {
* @param checkinId the check-in id * @param checkinId the check-in id
* @param packedFile the file to unpack * @param packedFile the file to unpack
* @param monitor the task monitor * @param monitor the task monitor
* @throws CancelledException * @throws IOException if IO error occurs
* @throws CancelledException if unpack is cancelled
*/ */
public static void unpackDatabase(BufferFileManager bfMgr, long checkinId, File packedFile, public static void unpackDatabase(BufferFileManager bfMgr, long checkinId, File packedFile,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
@@ -541,11 +550,11 @@ public class PackedDatabase extends Database {
/** /**
* Refresh the temporary database from the packed file if it has been updated * Refresh the temporary database from the packed file if it has been updated
* since the previous refresh. * since the previous refresh.
* @param monitor * @param monitor unpack monitor
* @return True if refresh was successful or not required. * @return True if refresh was successful or not required.
* False may be returned if refresh failed due to unpacked files being in use. * False may be returned if refresh failed due to unpacked files being in use.
* @throws IOException * @throws IOException if IO error occurs
* @throws CancelledException * @throws CancelledException if unpack is cancelled
*/ */
private boolean refreshUnpacking(TaskMonitor monitor) throws CancelledException, IOException { private boolean refreshUnpacking(TaskMonitor monitor) throws CancelledException, IOException {
monitor.setMessage("Waiting..."); monitor.setMessage("Waiting...");
@@ -599,11 +608,13 @@ public class PackedDatabase extends Database {
/** /**
* Serialize (i.e., pack) an open database into the specified outputFile. * Serialize (i.e., pack) an open database into the specified outputFile.
* @param dbh open database handle * @param dbh open database handle
* @param itemName item name to associate with packed content * @param itemName name to associate with packed content
* @param contentType supported content type * @param contentType supported DB content type
* @param outputFile packed output file to be created * @param outputFile packed output file to be created
* @param monitor progress monitor * @param monitor save/pack monitor
* @throws IOException * @throws ReadOnlyException if {@code outputFile} location is write-protected
* @throws DuplicateFileException if {@code outputFile} already exists
* @throws IOException if IO error occurs
* @throws CancelledException if monitor cancels operation * @throws CancelledException if monitor cancels operation
*/ */
public static void packDatabase(DBHandle dbh, String itemName, String contentType, public static void packDatabase(DBHandle dbh, String itemName, String contentType,
@@ -617,34 +628,18 @@ public class PackedDatabase extends Database {
throw new DuplicateFileException(outputFile + " already exists"); throw new DuplicateFileException(outputFile + " already exists");
} }
boolean success = false; boolean success = false;
InputStream itemIn = null;
File tmpFile = null; File tmpFile = null;
try { try {
tmpFile = Application.createTempFile("pack", ".tmp"); tmpFile = Application.createTempFile("pack", ".tmp");
tmpFile.delete(); tmpFile.delete();
dbh.saveAs(tmpFile, false, monitor); dbh.saveAs(tmpFile, false, monitor);
itemIn = new BufferedInputStream(new FileInputStream(tmpFile)); try (InputStream itemIn = new BufferedInputStream(new FileInputStream(tmpFile))){
try {
ItemSerializer.outputItem(itemName, contentType, FolderItem.DATABASE_FILE_TYPE, ItemSerializer.outputItem(itemName, contentType, FolderItem.DATABASE_FILE_TYPE,
tmpFile.length(), itemIn, outputFile, monitor); tmpFile.length(), itemIn, outputFile, monitor);
} }
finally {
try {
itemIn.close();
}
catch (IOException e) {
}
}
success = true; success = true;
} }
finally { finally {
if (itemIn != null) {
try {
itemIn.close();
}
catch (IOException e) {
}
}
tmpFile.delete(); tmpFile.delete();
if (!success) { if (!success) {
outputFile.delete(); outputFile.delete();
@@ -654,15 +649,14 @@ public class PackedDatabase extends Database {
} }
/** /**
* Create a packed file from an existing Database. * Create a packed file from an existing non-packed DB file.
* @param name database name * @param name name to associate with packed content
* @param contentType user content type * @param contentType supported DB content type
* @param bfMgr buffer file manager for existing database * @param dbFile existing non-packed DB file
* @param version buffer file version to be packed * @param outputFile new packed DB file to be created or overwritten
* @param outputFile packed storage file to be created * @param monitor save/pack monitor
* @param monitor * @throws IOException if IO error occurs
* @throws IOException * @throws CancelledException if monitor cancels operation
* @throws CancelledException
*/ */
private static void packDatabase(String name, String contentType, File dbFile, File outputFile, private static void packDatabase(String name, String contentType, File dbFile, File outputFile,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
@@ -672,31 +666,20 @@ public class PackedDatabase extends Database {
} }
monitor.setMessage("Packing file..."); monitor.setMessage("Packing file...");
InputStream itemIn = new FileInputStream(dbFile); try (InputStream itemIn = new FileInputStream(dbFile)) {
try {
ItemSerializer.outputItem(name, contentType, FolderItem.DATABASE_FILE_TYPE, ItemSerializer.outputItem(name, contentType, FolderItem.DATABASE_FILE_TYPE,
dbFile.length(), itemIn, outputFile, monitor); dbFile.length(), itemIn, outputFile, monitor);
} }
catch (IOCancelledException e) {
throw new CancelledException();
}
finally {
try {
itemIn.close();
}
catch (IOException e) {
}
}
} }
/** /**
* Using the temporary unpacked database, update the packed storage file * Using the temporary unpacked database, update the packed storage file
* using the latest buffer file version. * using the latest buffer file version.
* @param monitor * @param monitor pack monitor
* @throws CancelledException * @throws CancelledException if pack is cancelled
* @throws IOException * @throws IOException if IO error occurs
*/ */
void packDatabase(TaskMonitor monitor) throws CancelledException, IOException { synchronized void packDatabase(TaskMonitor monitor) throws CancelledException, IOException {
if (isReadOnly || dbHandle == null || bfMgr == null || bfMgr.getCurrentVersion() == 0 || if (isReadOnly || dbHandle == null || bfMgr == null || bfMgr.getCurrentVersion() == 0 ||
!updateLock.haveLock()) { !updateLock.haveLock()) {
@@ -832,9 +815,9 @@ public class PackedDatabase extends Database {
} }
/** /**
* Attempt to remove all old temporary databases. * Attempt to remove all old temporary databases. This method is not intended for general use
* Those still open by an existing process should * and should only be invoked once during module initialization
* not be removed by the operating system. * (see {@link FileSystemInitializer}).
*/ */
public static void cleanupOldTempDatabases() { public static void cleanupOldTempDatabases() {
@@ -865,6 +848,7 @@ public class PackedDatabase extends Database {
} }
} }
catch (Exception e) { catch (Exception e) {
// ignore
} }
} }

View File

@@ -363,7 +363,7 @@ public class PackedDatabaseCache {
else { else {
Msg.debug(this, "Using cached packed database: " + cachedDb.packedDbFilePath); Msg.debug(this, "Using cached packed database: " + cachedDb.packedDbFilePath);
} }
return new PackedDatabase(packedDbFile, packedDbLock, cachedDb, monitor); return new PackedDatabase(cachedDb, packedDbFile, packedDbLock, monitor);
} }
finally { finally {
if (packedDbLock != null && packedDbLock.haveLock()) { if (packedDbLock != null && packedDbLock.haveLock()) {

View File

@@ -58,8 +58,8 @@ public class ItemSerializer {
* @param content content input stream * @param content content input stream
* @param packedFile output packed file to be created * @param packedFile output packed file to be created
* @param monitor task monitor * @param monitor task monitor
* @throws CancelledException * @throws CancelledException if output is cancelled
* @throws IOException * @throws IOException if IO error occurs
*/ */
public static void outputItem(String itemName, String contentType, int fileType, long length, public static void outputItem(String itemName, String contentType, int fileType, long length,
InputStream content, File packedFile, TaskMonitor monitor) throws CancelledException, InputStream content, File packedFile, TaskMonitor monitor) throws CancelledException,

View File

@@ -554,7 +554,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter
} }
try { try {
ContentHandler ch = DomainObjectAdapter.getContentHandler(this); ContentHandler<?> ch = DomainObjectAdapter.getContentHandler(this);
PackedDatabase.packDatabase(dbh, name, ch.getContentType(), outputFile, monitor); PackedDatabase.packDatabase(dbh, name, ch.getContentType(), outputFile, monitor);
// TODO :( output method will cause Redo-able transactions to be cleared // TODO :( output method will cause Redo-able transactions to be cleared