Permalink
Browse files

Fix a minor performance bug related to calculating inverse cascades.

When inverting cascaded references, we only need to consider fields
(and their containing types) that could possibly refer to the target
object.

Also, precalculate the KeyRanges object that defines the restriction to
the containing types.
  • Loading branch information...
archiecobbs committed Jun 29, 2018
1 parent ff852bd commit 741c5f820438c46fc0ef8957125ef100cb1a4d44
@@ -1,3 +1,7 @@
Version Next
- Minor performance improvement in calculating inverse cacades
Version 4.1.1 Released June 5, 2018
- Fixed timeout bug in Raft commit when leader has zero followers
@@ -17,6 +17,7 @@
import io.permazen.core.MapField;
import io.permazen.core.SetField;
import io.permazen.core.UnknownFieldException;
import io.permazen.kv.KeyRanges;
import io.permazen.schema.SchemaCompositeIndex;
import io.permazen.schema.SchemaField;
import io.permazen.schema.SchemaObjectType;
@@ -59,6 +60,7 @@
final ArrayList<JCompositeIndex> uniqueConstraintCompositeIndexes = new ArrayList<>();
final ArrayList<JField> upgradeConversionFields = new ArrayList<>(); // contains only simple and counter fields
final HashMap<String, List<JReferenceField>> forwardCascadeMap = new HashMap<>();
final HashMap<String, Map<Integer, KeyRanges>> inverseCascadeMap = new HashMap<>();
Set<FollowPathScanner<T>.MethodInfo> followPathMethods;
Set<OnCreateScanner<T>.MethodInfo> onCreateMethods;
@@ -915,19 +915,23 @@ private void gatherForwardCascadeRefs(ObjId id, String cascadeName, ObjIdSet vis
}
private void gatherInverseCascadeRefs(ObjId id, String cascadeName, ObjIdSet visitedIds, ObjIdSet toVisitIds) {
final List<JReferenceField> fieldList = this.jdb.inverseCascadeMap.get(cascadeName);
if (fieldList == null)
final JClass<?> jclass = this.jdb.jclasses.get(id.getStorageId());
if (jclass == null)
return;
for (JReferenceField field : fieldList) {
final JClass<?> jclass = field.getJClass();
final Map<Integer, KeyRanges> incomingCascades = jclass.inverseCascadeMap.get(cascadeName);
if (incomingCascades == null)
return;
for (Map.Entry<Integer, KeyRanges> entry : incomingCascades.entrySet()) {
final int referenceFieldStorageId = entry.getKey();
final KeyRanges cascadeReferringTypeRanges = entry.getValue();
// Access the index associated with the reference field's storage ID
CoreIndex<?, ?> index = this.tx.queryIndex(field.storageId);
// Access the index associated with the reference field
CoreIndex<?, ?> index = this.tx.queryIndex(referenceFieldStorageId);
// Restrict to references coming from objects having the type containing the particular reference field in question
index = index.filter(1, new KeyRanges(ObjId.getKeyRange(jclass.storageId)));
// Restrict index to references from objects containing the field with the cascade (their ranges already precomputed)
index = index.filter(1, cascadeReferringTypeRanges);
// Find objects of that type referring to "id" through the field and add them to our cascade
// Find objects referring to "id" through the field and add them to our cascade
final NavigableSet<?> refs = index.asMap().get(id);
if (refs != null)
this.gatherRefs(refs.iterator(), visitedIds, toVisitIds);
@@ -129,7 +129,6 @@
final ClassLoader loader;
final Database db;
final StorageIdGenerator storageIdGenerator;
final HashMap<String, List<JReferenceField>> inverseCascadeMap = new HashMap<>();
final boolean hasOnCreateMethods;
final boolean hasOnDeleteMethods;
@@ -354,18 +353,33 @@ public Loader run() {
}
}
// Populate jclass.forwardCascadeMap and this.inverseCascadeMap
// Populate jclass forwardCascadeMap and inverseCascadeMap
for (JClass<?> jclass0 : this.jclasses.values()) {
final JClass<?> jclass = jclass0;
for (JField jfield : jclass.jfields.values()) {
jfield.visit(new JFieldSwitchAdapter<Void>() {
@Override
public Void caseJReferenceField(JReferenceField field) {
for (String cascadeName : field.forwardCascades)
this.addCascade(jclass.forwardCascadeMap, cascadeName, field);
for (String cascadeName : field.inverseCascades)
this.addCascade(Permazen.this.inverseCascadeMap, cascadeName, field);
// Do forward cascades
for (String cascadeName : field.forwardCascades) {
if (cascadeName == null)
continue;
jclass.forwardCascadeMap.computeIfAbsent(cascadeName, s -> new ArrayList<>()).add(field);
}
// Do inverse cascades
for (String cascadeName : field.inverseCascades) {
if (cascadeName == null)
continue;
for (JClass<?> targetClass : Permazen.this.getJClasses(field.typeToken.getRawType())) {
targetClass.inverseCascadeMap
.computeIfAbsent(cascadeName, s -> new HashMap<>())
.computeIfAbsent(field.storageId, i -> new KeyRanges())
.add(ObjId.getKeyRange(jclass.storageId));
}
}
return null;
}
@@ -389,11 +403,6 @@ protected Void caseJCollectionField(JCollectionField field) {
protected Void caseJField(JField field) {
return null;
}
private void addCascade(Map<String, List<JReferenceField>> map, String cascadeName, JReferenceField field) {
if (cascadeName != null)
map.computeIfAbsent(cascadeName, s -> new ArrayList<>()).add(field);
}
});
}
}

0 comments on commit 741c5f8

Please sign in to comment.