mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-1545: De-guava the Debugger
This commit is contained in:
parent
a2ae1f08ce
commit
d43b9ead66
142 changed files with 1125 additions and 1889 deletions
|
@ -17,14 +17,12 @@ package ghidra.async;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.cache.*;
|
||||
|
||||
/**
|
||||
* A cache of futures which pairs each to its result by key
|
||||
*
|
||||
* <p>
|
||||
* The cache accepts promises and results, storing unpaired entries for a timeout period. Each
|
||||
* promise is fulfilled when the cache accepts its corresponding result, determined by key.
|
||||
* Conversely, a cached result fulfills its corresponding promise, determined by key, when the cache
|
||||
|
@ -32,6 +30,7 @@ import com.google.common.cache.*;
|
|||
* given key enter the cache, they are paired, the promise is fulfilled, and both are removed from
|
||||
* the cache.
|
||||
*
|
||||
* <p>
|
||||
* If an entry is not paired within the timeout period, it is evicted. An evicted promise is likely
|
||||
* a recoverable error, e.g., a request timed out. An evicted result is likely a logic or
|
||||
* synchronization error. Requests, i.e., promises, are usually created before the result is
|
||||
|
@ -53,66 +52,26 @@ public abstract class AsyncPairingCache<K, V> {
|
|||
/**
|
||||
* Construct a new matching cache
|
||||
*
|
||||
* @param concurrencyLevel the maximum number of thread expected to simultaneously access the
|
||||
* cache
|
||||
* @param timeoutMillis the amount of time (in milliseconds) a promise or result may pend before
|
||||
* eviction
|
||||
* @param maxPending the maximum number of pending promises or results before the eldest is
|
||||
* evicted. Each is counted independently, e.g., a value of 5 permits 5 pending
|
||||
* promises and 5 pending results simultaneously.
|
||||
*/
|
||||
public AsyncPairingCache(int concurrencyLevel, int timeoutMillis, int maxPending) {
|
||||
results = CacheBuilder.newBuilder()
|
||||
.concurrencyLevel(concurrencyLevel)
|
||||
.expireAfterWrite(timeoutMillis, TimeUnit.MILLISECONDS)
|
||||
.maximumSize(maxPending)
|
||||
.removalListener(this::resultRemoved)
|
||||
.build()
|
||||
.asMap();
|
||||
public AsyncPairingCache(int maxPending) {
|
||||
results = createResultCache(maxPending);
|
||||
resultsView = Collections.unmodifiableMap(results);
|
||||
|
||||
promises = CacheBuilder.newBuilder()
|
||||
.concurrencyLevel(concurrencyLevel)
|
||||
.expireAfterWrite(timeoutMillis, TimeUnit.MILLISECONDS)
|
||||
.maximumSize(maxPending)
|
||||
.removalListener(this::promiseRemoved)
|
||||
.build()
|
||||
.asMap();
|
||||
promises = createPromiseCache(maxPending);
|
||||
promisesView = Collections.unmodifiableMap(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a result is removed
|
||||
*
|
||||
* Eviction is likely due to a logic bug or a gratuitous result from an external source.
|
||||
*
|
||||
* @param rn the removal notification for the result entry
|
||||
*/
|
||||
protected abstract void resultRemoved(RemovalNotification<K, V> rn);
|
||||
protected abstract Map<K, V> createResultCache(int max);
|
||||
|
||||
/**
|
||||
* Called when a promise is removed
|
||||
*
|
||||
* The most common implementation is to complete the future exceptionally. The default
|
||||
* implementation completes the future with a {@link RuntimeException}. Extensions should
|
||||
* override this method. Note that this method is called for removal as a result of normal
|
||||
* completion, too. In that case {@link RemovalNotification#getCause()} will return
|
||||
* {@link RemovalCause#EXPLICIT}.
|
||||
*
|
||||
* @param rn the removal notification for the promise entry
|
||||
*/
|
||||
protected void promiseRemoved(RemovalNotification<K, CompletableFuture<V>> rn) {
|
||||
if (rn.getCause() != RemovalCause.EXPLICIT) {
|
||||
rn.getValue()
|
||||
.completeExceptionally(new RuntimeException(
|
||||
"Promise with key " + rn.getKey() +
|
||||
" was evicted with the default handler"));
|
||||
}
|
||||
}
|
||||
protected abstract Map<K, CompletableFuture<V>> createPromiseCache(int max);
|
||||
|
||||
/**
|
||||
* Enter a promise for the the given key into the cache
|
||||
*
|
||||
* <p>
|
||||
* If the result for the given key is already available, the promise does not enter the cache.
|
||||
* Instead, the result is removed and the promise is completed.
|
||||
*
|
||||
|
@ -126,6 +85,7 @@ public abstract class AsyncPairingCache<K, V> {
|
|||
/**
|
||||
* Enter a promise for the the given key into the cache
|
||||
*
|
||||
* <p>
|
||||
* If the result for the given key is already available, the promise does not enter the cache.
|
||||
* Instead, the result is removed and the promise is completed.
|
||||
*
|
||||
|
@ -148,6 +108,7 @@ public abstract class AsyncPairingCache<K, V> {
|
|||
/**
|
||||
* Enter a result for the given key into the cache
|
||||
*
|
||||
* <p>
|
||||
* If a promise for the key already exists, the result does not enter the cache. Instead, the
|
||||
* promise is removed and completed.
|
||||
*
|
||||
|
@ -169,11 +130,8 @@ public abstract class AsyncPairingCache<K, V> {
|
|||
/**
|
||||
* Flush the cache, completing all pending requests exceptionally
|
||||
*
|
||||
* Both sides of the cache are cleared. Note that this will invoke the removal callback for each
|
||||
* entry giving {@link RemovalCause#EXPLICIT} as the cause. For requests, the callback ought not
|
||||
* to complete the request, exceptionally or otherwise, since the flush is about to complete it
|
||||
* with the given exception. The implementor may freely choose how to handle flushed pending
|
||||
* results.
|
||||
* <p>
|
||||
* Both sides of the cache are cleared.
|
||||
*
|
||||
* @param exc the exception for completing the requests
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue