Community
Participate
Working Groups
org.eclipse.emf.ecore.util.EcoreUtil provides the CrossReferencer, an utility class that, as years passed by, its use become very much widespread among other EMF-based frameworks. CrossReferencing a Resource or even just an EObject is a fairly lightweight operation when models are completely loaded in memory. However, it depends pretty much on the size of the model: as models grow, the operation becomes more intensive. Haven't calculated it, but it shouldn't be difficult to write a O() complexity formula for it. With the appearance of CDO in the modeling scene, EMF models could grow further than the JVM Heap. CDO comes into play as the favourite "memory-virtualization" framework for EMF. However, CrossReferencer current implementation doesn't go along very well with huge models stored in CDO. It implies loading the whole model in memory, and also implies a lot of round-tripping overhead. It doesn't mean CrossReferencer implementation is wrong. It means that there probably should be a CrossReferencer for each persistence scenario. At that implies that it is desirable to contribute custom CrossReferencer implementations to the EMF core. My proposal here is to provide some delegation or extensibility mechanism for the CrossReferencer class. So, pretty much the same way EMF does with other things, a CrossReferencer implementation should be selected in favor of another one, for example, depending of the type of Resource or EObject this class is actually CrossReferencing. The requirement is that this should be transparent to CrossReferencer consumers. Other frameworks should be affected by this change (so, this means, no API breakage). So, for instance, if a EMF-based framework uses CrossReferencer, it may, behind the scenes, be delegated to some custom implementation more suitable for their model (CDO, Teneo, and other scenarios...)
Please Ed, if you find any other requirements as the framework provider, feel free to add them here!
So this is mostly about the UsageCrossReferencer? The only place the EMF framework itself uses this in the DeleteCommand. Is that your primary concern? We might make the static finalAll methods (the resource and resource set ones) look for an adapter (on the resource or resource set)... Or is ECrossReferenceAdapter also a concern? It's not used in the framework... We might support some type of adapter lookup mechanism there as well, but
Ed, some comments below, (In reply to comment #2) > So this is mostly about the UsageCrossReferencer? The only place the EMF > framework itself uses this in the DeleteCommand. Is that your primary concern? DeleteCommand is a concern, yes, but not the only one. The EMF framework, as you say, does not make any extensive use of the CrossReferncing utilities provided in EcoreUtils. However, frameworks depending on EMF do make use of these utilities. Just some examples: org.eclipse.gmf.runtime.emf.core.util.CrossReferenceAdapter (extends ECrossReferenceAdapter) org.eclipse.m2m.internal.qvt.oml.ast.env.ModelParameterExtent.delete(List<EObject>, EObject) calls: org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.findAll(Collection<?>, Collection<?>) org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiff(MatchModel, boolean) calls: org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer.CrossReferencer(EObject) and I'm sure I could find more, but I dont have all EMF based frameworks in my target platform ;) So CrossReferencing is something offered in the EMF framework that ended up being a basic operation for many frameworks. This is fine, but when dealing with models persisted in a CDO repository, that implies an important performance overhead, specially with large models. The assumption of "my models are on memory" are no longer valid with CDO fine-grained and lazy-load basics. > We might make the static finalAll methods (the resource and resource set ones) > look for an adapter (on the resource or resource set)... > That sounds like a nice solution, I had doubts on how could those adapters be automatically installed (specially when those frameworks control a great deal of the execution flow), but that could be done in the Resource.Factory (right?) > Or is ECrossReferenceAdapter also a concern? It's not used in the framework... > We might support some type of adapter lookup mechanism there as well, but Yes, ECrossReferenceAdapter is a concern (as shown above) and it's also a whole different story. I had to sub-class it and substitute with specialized logic. So it looks like there should be ECrossReferenceAdapter delegation mechanism too (I guess it's late to add factories...).
So if we changed DeleteCommand.findReferences to the following then it would reuse a cross reference adapter, if there is one on the resource set protected Map<EObject, Collection<EStructuralFeature.Setting>> findReferences(Collection<EObject> eObjects) { ResourceSet resourceSet = domain.getResourceSet(); ECrossReferenceAdapter crossReferenceAdapter = ECrossReferenceAdapter.getCrossReferenceAdapter(resourceSet); if (crossReferenceAdapter != null) { Map<EObject, Collection<EStructuralFeature.Setting>> result = new HashMap<EObject, Collection<EStructuralFeature.Setting>>(); for (EObject eObject : eObjects) { result.put(eObject, crossReferenceAdapter.getInverseReferences(eObject, true)); } return result; } else { return EcoreUtil.UsageCrossReferencer.findAll(eObjects, resourceSet); } } That appears to be sufficient to address the issue in the core framework, but it's not clear that solves the downstream problems. But those are in other frameworks, so I'm not sure what to do about those. As long as they make sure they install an adapter on the resource set that derives from ECrossReferenceAdapter, it's perhaps sufficient. Does this help?
Hi Ed, sorry for not giving any feedback on this. 2013 is been a weird year :P As you said, your suggestion may help for the core framework, but it wont to any other frameworks using EcoreUtil. CrossReferencer and subclasses are API and may be used anywhere. I haven't made an analysis of how much is it used, and sure your proposal would help. Here's a simple and apparently innocuous proposal. Modification of org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.find(EObject, EObject) public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, EObject eObject) { CrossReferencerFactory factory = CrossReferencerFactory.Registry.INSTANCE.getFactoryFor(eObject); if (factory != null) { return factory.createUsageCrossReferencer(eObject).findUsage(eObjectOfInterest); } return new UsageCrossReferencer(eObject).findUsage(eObjectOfInterest); }
If it looks good to you, I have a working prototype ready for review.