mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GT-3604 - Threaded Tables - update tables to buffer more when in a
flurry of updates
This commit is contained in:
parent
01539bedd6
commit
3734d77bcd
1 changed files with 66 additions and 67 deletions
|
@ -15,14 +15,12 @@
|
|||
*/
|
||||
package docking.widgets.table.threaded;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.table.AddRemoveListItem;
|
||||
import docking.widgets.table.TableSortingContext;
|
||||
import generic.concurrent.ConcurrentListenerSet;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.task.*;
|
||||
|
||||
|
@ -35,9 +33,11 @@ import ghidra.util.task.*;
|
|||
* @param <T> the row type
|
||||
*/
|
||||
class ThreadedTableModelUpdateMgr<T> {
|
||||
static final int TOO_MANY_ADD_REMOVES = 3000;
|
||||
public final static int DELAY = 1000;
|
||||
|
||||
// make the delay large enough that a flurry of events will stay buffered
|
||||
public final static int DELAY = 5000;
|
||||
public final static int MAX_DELAY = 1000 * 60 * 20;
|
||||
static final int TOO_MANY_ADD_REMOVES = 3000;
|
||||
|
||||
private ThreadedTableModel<T, ?> model;
|
||||
private SwingUpdateManager addRemoveUpdater;
|
||||
|
@ -115,49 +115,11 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
return addRemoveUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the accumulated list of add/remove items.
|
||||
* Called when the swing update manager decides its time to run.
|
||||
*/
|
||||
private void processAddRemoveItems() {
|
||||
synchronized (addRemoveUpdater) {
|
||||
if (addRemoveWaitList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// too many requests for add/remove triggers a full reload for efficiency
|
||||
if (addRemoveWaitList.size() > maxAddRemoveCount) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
|
||||
pendingJob = new AddRemoveJob<>(model, addRemoveWaitList, monitor);
|
||||
addRemoveWaitList = new ArrayList<>();
|
||||
runJob();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there is work to be done. It creates a thread if none is running to do the
|
||||
* work that is built into the pending job.
|
||||
*/
|
||||
private void runJob() {
|
||||
synchronized (addRemoveUpdater) {
|
||||
if (thread != null) {
|
||||
return; // if thread exists, it will handle any pending job
|
||||
}
|
||||
|
||||
if (pendingJob == null) {
|
||||
return; // nothing to do!
|
||||
}
|
||||
|
||||
// Ok, we have to create a thread to process the pending job
|
||||
thread = new Thread(threadRunnable,
|
||||
"Threaded Table Model Update Manager: " + model.getName());
|
||||
|
||||
thread.start();
|
||||
SwingUtilities.invokeLater(notifyUpdating);
|
||||
}
|
||||
private int getMaxAddRemoveCount() {
|
||||
// have the max count grow with the size of the table to prevent too many calls to reload()
|
||||
int n = model.getRowCount();
|
||||
int cuttoff = (int) (n * .1);
|
||||
return Math.max(maxAddRemoveCount, cuttoff);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,8 +146,7 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
void reload() {
|
||||
synchronized (addRemoveUpdater) {
|
||||
cancelAllJobs();
|
||||
pendingJob = new LoadJob<>(model, monitor);
|
||||
runJob();
|
||||
runJob(new LoadJob<>(model, monitor));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,8 +154,7 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
synchronized (addRemoveUpdater) {
|
||||
cancelAllJobs();
|
||||
TableData<T> tableData = TableData.createFullDataset(data);
|
||||
pendingJob = new LoadSpecificDataJob<>(model, monitor, tableData);
|
||||
runJob();
|
||||
runJob(new LoadSpecificDataJob<>(model, monitor, tableData));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,8 +185,7 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
return;
|
||||
}
|
||||
|
||||
pendingJob = new SortJob<>(model, monitor, sortingContext, forceSort);
|
||||
runJob();
|
||||
runJob(new SortJob<>(model, monitor, sortingContext, forceSort));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,8 +212,7 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
return;
|
||||
}
|
||||
|
||||
pendingJob = new FilterJob<>(model, monitor);
|
||||
runJob();
|
||||
runJob(new FilterJob<>(model, monitor));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,17 +228,15 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
void addRemove(AddRemoveListItem<T> item) {
|
||||
synchronized (addRemoveUpdater) {
|
||||
if (pendingJob != null) {
|
||||
pendingJob.addRemove(item, maxAddRemoveCount);
|
||||
return;
|
||||
}
|
||||
pendingJob.addRemove(item, getMaxAddRemoveCount());
|
||||
|
||||
if (addRemoveWaitList.size() > maxAddRemoveCount) {
|
||||
reload();
|
||||
// push the updater back to avoid constant reloading
|
||||
addRemoveUpdater.updateLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (addRemoveWaitList.isEmpty() && thread == null) {
|
||||
SwingUtilities.invokeLater(notifyPending);
|
||||
Swing.runLater(notifyPending);
|
||||
}
|
||||
|
||||
addRemoveWaitList.add(item);
|
||||
|
@ -288,6 +244,28 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the accumulated list of add/remove items.
|
||||
* Called when the swing update manager decides its time to run.
|
||||
*/
|
||||
private void processAddRemoveItems() {
|
||||
synchronized (addRemoveUpdater) {
|
||||
|
||||
if (addRemoveWaitList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// too many requests for add/remove triggers a full reload for efficiency
|
||||
if (addRemoveWaitList.size() > getMaxAddRemoveCount()) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
|
||||
runJob(new AddRemoveJob<>(model, addRemoveWaitList, monitor));
|
||||
addRemoveWaitList = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is any scheduled work that has not been completed, including any
|
||||
* deferred add/removes.
|
||||
|
@ -356,6 +334,27 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
addRemoveUpdater.updateNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there is work to be done. It creates a thread if none is running to do the
|
||||
* work that is built into the pending job.
|
||||
*/
|
||||
private void runJob(TableUpdateJob<T> job) {
|
||||
synchronized (addRemoveUpdater) {
|
||||
// Create a thread to process the pending job
|
||||
pendingJob = Objects.requireNonNull(job);
|
||||
|
||||
if (thread != null) {
|
||||
return; // if thread exists, it will handle any pending job
|
||||
}
|
||||
|
||||
thread = new Thread(threadRunnable,
|
||||
"Threaded Table Model Update Manager: " + model.getName());
|
||||
|
||||
thread.start();
|
||||
Swing.runLater(notifyUpdating);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transitions the pending job to the current job is a thread safe way.
|
||||
* @return the new current job.
|
||||
|
@ -380,22 +379,22 @@ class ThreadedTableModelUpdateMgr<T> {
|
|||
*/
|
||||
private void jobDone() {
|
||||
|
||||
// This synchronized is not need, as this method is only called from within a
|
||||
// This synchronized is not needed, as this method is only called from within a
|
||||
// synchronized block. But, it feels better to be explicit here to signal that
|
||||
// synchronization is needed.
|
||||
synchronized (addRemoveUpdater) {
|
||||
|
||||
boolean isCancelled = monitor.isCancelled();
|
||||
if (isCancelled) {
|
||||
SwingUtilities.invokeLater(notifyCancelled);
|
||||
Swing.runLater(notifyCancelled);
|
||||
}
|
||||
else {
|
||||
SwingUtilities.invokeLater(notifyDone);
|
||||
Swing.runLater(notifyDone);
|
||||
}
|
||||
|
||||
thread = null;
|
||||
if (!addRemoveWaitList.isEmpty()) {
|
||||
SwingUtilities.invokeLater(notifyPending);
|
||||
Swing.runLater(notifyPending);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue