mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-4351: More thorough synchronization, esp., with streams.
This commit is contained in:
parent
ddf4d15327
commit
5a0b262df4
5 changed files with 290 additions and 59 deletions
|
@ -422,7 +422,8 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager
|
|||
public Stream<DBTraceObjectValue> getAllValues() {
|
||||
return Stream.concat(
|
||||
valueMap.values().stream().map(v -> v.getWrapper()),
|
||||
valueWbCache.streamAllValues().map(v -> v.getWrapper()));
|
||||
StreamUtils.lock(lock.readLock(),
|
||||
valueWbCache.streamAllValues().map(v -> v.getWrapper())));
|
||||
}
|
||||
|
||||
protected Stream<DBTraceObjectValueData> streamValuesIntersectingData(Lifespan span,
|
||||
|
@ -672,7 +673,7 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager
|
|||
return new UnionAddressSetView(
|
||||
valueMap.getAddressSetView(Lifespan.at(snap),
|
||||
v -> acceptValue(v.getWrapper(), key, ifaceCls, predicate)),
|
||||
valueWbCache.getObjectsAddresSet(snap, key, ifaceCls, predicate));
|
||||
valueWbCache.getObjectsAddressSet(snap, key, ifaceCls, predicate));
|
||||
}
|
||||
|
||||
public <I extends TraceObjectInterface> I getSuccessor(TraceObject seed,
|
||||
|
|
|
@ -176,28 +176,30 @@ class DBTraceObjectValueWriteBehindCache {
|
|||
}
|
||||
|
||||
public Stream<DBTraceObjectValueBehind> streamAllValues() {
|
||||
return doStreamAllValues();
|
||||
return StreamUtils.sync(cachedValues, doStreamAllValues());
|
||||
}
|
||||
|
||||
public DBTraceObjectValueBehind get(DBTraceObject parent, String key, long snap) {
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return null;
|
||||
}
|
||||
var values = keys.get(key);
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
synchronized (cachedValues) {
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return null;
|
||||
}
|
||||
var values = keys.get(key);
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var floor = values.floorEntry(snap);
|
||||
if (floor == null) {
|
||||
return null;
|
||||
}
|
||||
var floor = values.floorEntry(snap);
|
||||
if (floor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!floor.getValue().getLifespan().contains(snap)) {
|
||||
return null;
|
||||
if (!floor.getValue().getLifespan().contains(snap)) {
|
||||
return null;
|
||||
}
|
||||
return floor.getValue();
|
||||
}
|
||||
return floor.getValue();
|
||||
}
|
||||
|
||||
public Stream<DBTraceObjectValueBehind> streamParents(DBTraceObject child, Lifespan lifespan) {
|
||||
|
@ -236,25 +238,29 @@ class DBTraceObjectValueWriteBehindCache {
|
|||
}
|
||||
|
||||
public Stream<DBTraceObjectValueBehind> streamValues(DBTraceObject parent, Lifespan lifespan) {
|
||||
// TODO: Better indexing?
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return Stream.of();
|
||||
synchronized (cachedValues) {
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return Stream.of();
|
||||
}
|
||||
return StreamUtils.sync(cachedValues,
|
||||
keys.values().stream().flatMap(v -> streamSub(v, lifespan, true)));
|
||||
}
|
||||
return keys.values().stream().flatMap(v -> streamSub(v, lifespan, true));
|
||||
}
|
||||
|
||||
public Stream<DBTraceObjectValueBehind> streamValues(DBTraceObject parent, String key,
|
||||
Lifespan lifespan, boolean forward) {
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return Stream.of();
|
||||
synchronized (cachedValues) {
|
||||
var keys = cachedValues.get(parent);
|
||||
if (keys == null) {
|
||||
return Stream.of();
|
||||
}
|
||||
var values = keys.get(key);
|
||||
if (values == null) {
|
||||
return Stream.of();
|
||||
}
|
||||
return StreamUtils.sync(cachedValues, streamSub(values, lifespan, forward));
|
||||
}
|
||||
var values = keys.get(key);
|
||||
if (values == null) {
|
||||
return Stream.of();
|
||||
}
|
||||
return streamSub(values, lifespan, forward);
|
||||
}
|
||||
|
||||
static boolean intersectsRange(Object value, AddressRange range) {
|
||||
|
@ -265,14 +271,16 @@ class DBTraceObjectValueWriteBehindCache {
|
|||
private Stream<DBTraceObjectValueBehind> streamValuesIntersectingLifespan(Lifespan lifespan,
|
||||
String entryKey) {
|
||||
// TODO: In-memory spatial index?
|
||||
var top = cachedValues.values().stream();
|
||||
var keys = entryKey == null
|
||||
? top.flatMap(v -> v.values().stream())
|
||||
: top.flatMap(v -> v.entrySet()
|
||||
.stream()
|
||||
.filter(e -> entryKey.equals(e.getKey()))
|
||||
.map(e -> e.getValue()));
|
||||
return keys.flatMap(v -> streamSub(v, lifespan, true));
|
||||
synchronized (cachedValues) {
|
||||
var top = cachedValues.values().stream();
|
||||
var keys = entryKey == null
|
||||
? top.flatMap(v -> v.values().stream())
|
||||
: top.flatMap(v -> v.entrySet()
|
||||
.stream()
|
||||
.filter(e -> entryKey.equals(e.getKey()))
|
||||
.map(e -> e.getValue()));
|
||||
return StreamUtils.sync(cachedValues, keys.flatMap(v -> streamSub(v, lifespan, true)));
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<DBTraceObjectValueBehind> streamValuesIntersecting(Lifespan lifespan,
|
||||
|
@ -302,38 +310,46 @@ class DBTraceObjectValueWriteBehindCache {
|
|||
return null;
|
||||
}
|
||||
|
||||
public <I extends TraceObjectInterface> AddressSetView getObjectsAddresSet(long snap,
|
||||
public <I extends TraceObjectInterface> AddressSetView getObjectsAddressSet(long snap,
|
||||
String key, Class<I> ifaceCls, Predicate<? super I> predicate) {
|
||||
return new AbstractAddressSetView() {
|
||||
AddressSet collectRanges() {
|
||||
AddressSet result = new AddressSet();
|
||||
for (DBTraceObjectValueBehind v : StreamUtils
|
||||
.iter(streamValuesIntersectingLifespan(Lifespan.at(snap), key))) {
|
||||
AddressRange range = getIfRangeOrAddress(v.getValue());
|
||||
if (range == null) {
|
||||
continue;
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
synchronized (cachedValues) {
|
||||
for (DBTraceObjectValueBehind v : StreamUtils
|
||||
.iter(streamValuesIntersectingLifespan(Lifespan.at(snap), key))) {
|
||||
AddressRange range = getIfRangeOrAddress(v.getValue());
|
||||
if (range == null) {
|
||||
continue;
|
||||
}
|
||||
if (!DBTraceObjectManager.acceptValue(v.getWrapper(), key, ifaceCls,
|
||||
predicate)) {
|
||||
continue;
|
||||
}
|
||||
result.add(range);
|
||||
}
|
||||
}
|
||||
if (!DBTraceObjectManager.acceptValue(v.getWrapper(), key, ifaceCls,
|
||||
predicate)) {
|
||||
continue;
|
||||
}
|
||||
result.add(range);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Address addr) {
|
||||
for (DBTraceObjectValueBehind v : StreamUtils
|
||||
.iter(streamValuesIntersectingLifespan(Lifespan.at(snap), key))) {
|
||||
if (!addr.equals(v.getValue())) {
|
||||
continue;
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
synchronized (cachedValues) {
|
||||
for (DBTraceObjectValueBehind v : StreamUtils
|
||||
.iter(streamValuesIntersectingLifespan(Lifespan.at(snap), key))) {
|
||||
if (!addr.equals(v.getValue())) {
|
||||
continue;
|
||||
}
|
||||
if (!DBTraceObjectManager.acceptValue(v.getWrapper(), key, ifaceCls,
|
||||
predicate)) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!DBTraceObjectManager.acceptValue(v.getWrapper(), key, ifaceCls,
|
||||
predicate)) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue