Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 330812 - [Validation] Don't resolve proxies if not necessary
Summary: [Validation] Don't resolve proxies if not necessary
Status: CLOSED FIXED
Alias: None
Product: TMF
Classification: Modeling
Component: Xtext (show other bugs)
Version: 2.0.0   Edit
Hardware: PC Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: M7   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-22 10:36 EST by Sven Efftinge CLA
Modified: 2017-09-19 18:12 EDT (History)
3 users (show)

See Also:
sven.efftinge: indigo+


Attachments
patch for many references (5.63 KB, patch)
2010-11-22 17:23 EST, Knut Wannheden CLA
no flags Details | Diff
resolve references patch (1.86 KB, patch)
2011-03-11 01:13 EST, Knut Wannheden CLA
no flags Details | Diff
lazy resolution of references in DefaultResourceDescriptionStrategy (4.60 KB, patch)
2011-04-14 02:23 EDT, Knut Wannheden CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sven Efftinge CLA 2010-11-22 10:36:41 EST
The default strategy to check, whether all links are resolvable is to rely on EcoreUtil.resolveAll.

This enforces all proxies to be resolved. However when working with the index we often know about the existence of an EObject without having to load it into memory. 
We should come up with an explicit linking validation, which is based on ILinkingService but takes
any returned EObjects or Proxies as valid cross references without trying to resolve the returned proxies.
Comment 1 Sven Efftinge CLA 2010-11-22 15:36:34 EST
Added a method to LazyLinkingResource, which is capable of resolving lazy links only and not transitively.
It optionally also replaces lazy linking proxies with the resolved elements, but as it does it from outside the notification fired is a Notficiation.SET and not a Notification.RESOLVE (which would be wrong anyway, since the new element might be a proxy as well). 
I tried to make that explicit through JavaDoc and the additional parameter. The only client for this code is ResourceValidatorImpl, which uses this approach and replaces the resolved elements. 
I suspect that most clients don't rely on the notifications and if they rely on it, they need to change the ResourceValidatorImpl to fall back to the old more expensive EcoreUtil.resolveAll. I've disabled the cache eviction for the resolution of lazy links.

Pushed to master.
Comment 2 Sebastian Zarnekow CLA 2010-11-22 15:40:04 EST
Any words about the impact on the performance of the linking validation phase?
Comment 3 Knut Wannheden CLA 2010-11-22 17:23:41 EST
Created attachment 183619 [details]
patch for many references

It doesn't look like the new parameter replaceResolvedElements is being used.

I also found a problem with how the code deals with many references. Whether eGet() is called with "resolve" set to true or false doesn't make a difference. Important is how the list elements are subsequently accessed. See attached patch and test case for details.

Further I don't think that a RESOLVE event would be wrong even if the returned object is still a proxy. That's after all also what EMF normally would do if it could resolve a proxy to another proxy only. So another solution would be to during validation resolve the lazy link proxies only and then block EMF's recursive proxy resolution from resolving any further. This behavior would of course be specific to IResourceValidator#resolveProxies() only (or any other clients specifically requesting that behavior).
Comment 4 Sven Efftinge CLA 2010-11-23 07:25:16 EST
Thanks, I've applied the patch. I also deactivated notification.

Regarding performance: It is as fast as the old approach in most scenarios. Only if loading a referenced resource would be time consuming, because it is super large or not locally available it would make a noticeable difference I guess.
Comment 5 Knut Wannheden CLA 2010-11-24 13:35:00 EST
What about the EcoreUtil.resolveAll() call in DefaultResourceDescription#getImportedNames()? I suppose that could also be changed to use LazyLinkingResource#resolveLazyCrossReferences(), or did I miss something?
Comment 6 Sven Efftinge CLA 2010-11-25 02:50:36 EST
Yes, of course. Could you take care of it?
Comment 7 Knut Wannheden CLA 2010-11-25 06:09:02 EST
OK. I will move the logic of ResourceValidatorImpl#resolveProxies() into EcoreUtil2#resolveAll() unless you can see a problem with that approach. The only other client of EcoreUtil2#resolveAll() is ReconcilingUnitOfWork#exec(), but I can't see how that would hurt there.
Comment 8 Sven Efftinge CLA 2010-11-25 07:18:08 EST
(In reply to comment #7)
> OK. I will move the logic of ResourceValidatorImpl#resolveProxies() into
> EcoreUtil2#resolveAll() unless you can see a problem with that approach. The
> only other client of EcoreUtil2#resolveAll() is ReconcilingUnitOfWork#exec(),
> but I can't see how that would hurt there.

The logic doesn't "resolve all", hence it shouldn't be part of a method which is named that way.
I'ld prefer adding a method 'resolveLazyReferences' to EcoreUtil2.
Comment 9 Sebastian Zarnekow CLA 2010-11-25 08:50:41 EST
Hi Knut,

the ReconcilingUnitOfWork should resolve the proxies instead of ensuring that they exist. I'd assume that some fragile or offset / list index sensitive fragment provider implementations may not be able to resolve platform:/resource/... uris after something has been modified in the resource itself.

Regards,
Sebastian
Comment 10 Knut Wannheden CLA 2010-11-25 10:14:10 EST
Pushed fix as discussed to master.
Comment 11 Knut Wannheden CLA 2010-12-02 00:11:21 EST
Just as a note: This enhancement lowered our build times by about 10%.
Comment 12 Knut Wannheden CLA 2011-02-23 07:19:15 EST
I'm reopening this one for the following reasons:

1. The custom EObjectValidator added by the CompositeEValidator still causes all cross references to be resolved. That is because of the inherited check validate_EveryReferenceIsContained(). I suggest we override that one just like we do with validate_EveryProxyResolves().

2. ClusteringBuilderState#doUpdate() still calls EcoreUtil2.resolveAll(). We should replace this with EcoreUtil2.resolveLazyCrossReferences().

Also note that DefaultResourceDescriptionStrategy.createReferenceDescriptions() (which is of course called during the build) will also cause all cross references to be (fully) resolved, as it calls EObject.eGet() for all cross references. This one is although a bit tougher to solve: We would have to adapt DefaultResourceDescriptionStrategy.isResolvedAndExternal() to check if the target object is an unresolved lazy linking proxy (e.g. using LazyLinkingResource.getEncoder().isCrossLinkFragment()), in which case no reference description should be created.

Further it is of course possible that the linking service returns proxies which are intended to be further resolved (automatically by EcoreUtil.resolve()) and the reference description should then refer to the fully resolved target. But I think in that case the user would have override the default implementation to deal with that.

I suppose it might make sense to add a method like LazyLinkingResource.isUnresolvedReference(EObject, EReference, EObject) (or simply LazyLinkingResource.isUnresolvedReference(URI)) for this purpose.
Comment 13 Knut Wannheden CLA 2011-03-11 01:13:52 EST
Created attachment 190955 [details]
resolve references patch

The attached patch solves the first two issues described in my last comment: It replaces the call to EcoreUtil2#resolveAll() in ClusteredBuilderState and it overrides the EObjectValidator#validate_EveryReferenceIsContained() method in CompositeEValidator.

Any thoughts on what could / should be done with DefaultResourceDescriptionStrategy#isResolvedAndExternal() ?
Comment 14 Sebastian Zarnekow CLA 2011-04-05 05:17:31 EDT
(In reply to comment #13)
> Any thoughts on what could / should be done with
> DefaultResourceDescriptionStrategy#isResolvedAndExternal() ?

We could try to resolve it with the same logic as in resolveLazyCrossReferences and check the resulting URI. If it is a platform:/ uri and points to another resource, it's safe to assume that it's resolved and external.
Comment 15 Sebastian Zarnekow CLA 2011-04-05 05:19:37 EDT
Knut, I don't like the idea to override #validate_EveryReferenceIsContained as it misses important problems. Do you mind to override this one for your specific project by means of #isUseEObjectValidator == false and providing your own EObject validator?
Comment 16 Knut Wannheden CLA 2011-04-05 08:53:34 EDT
(In reply to comment #15)
> Knut, I don't like the idea to override #validate_EveryReferenceIsContained as
> it misses important problems. Do you mind to override this one for your
> specific project by means of #isUseEObjectValidator == false and providing your
> own EObject validator?

That sounds reasonable. Although it sounds like a quite esoteric use case for a reference in an Xtext resource to reference a non-contained object.
Comment 17 Sebastian Zarnekow CLA 2011-04-11 11:39:28 EDT
(In reply to comment #16)
> That sounds reasonable. Although it sounds like a quite esoteric use case for a
> reference in an Xtext resource to reference a non-contained object.

Exactly. That's why I'd like to have the appropriate validation rule available by default. Power users are free to override it and others won't be harmed when referenced resources are loaded in the validation stage.

Knut, could you please update the suggested patches and apply them?
Comment 18 Knut Wannheden CLA 2011-04-14 02:23:38 EDT
Created attachment 193220 [details]
lazy resolution of references in DefaultResourceDescriptionStrategy

(In reply to comment #14)
> (In reply to comment #13)
> > Any thoughts on what could / should be done with
> > DefaultResourceDescriptionStrategy#isResolvedAndExternal() ?
> 
> We could try to resolve it with the same logic as in resolveLazyCrossReferences
> and check the resulting URI. If it is a platform:/ uri and points to another
> resource, it's safe to assume that it's resolved and external.

IMO the URI check should by default instead check if the URI is not a lazy proxy URI. See attached patch for details.

Further I think it would be cleaner to add something like a XtextResource#isResolved() method to encapsulate this bit.
Comment 19 Sebastian Zarnekow CLA 2011-04-14 04:41:15 EDT
Hi Knut,

the patch looks good to me. Please apply.

I wouldn't introduce a dependency to the XtextResource to encapsulate this information. I like the fact that the default resource description strategy works nicely with all kinds of emf resources.
Comment 20 Sebastian Zarnekow CLA 2011-04-14 04:48:32 EDT
Would it be possible to add a test case that documents the lazy cross reference resolution in the default resource description strategy, e.g. one that shows that a referenced resource will not be loaded into the resource set for the sake of creating reference descriptions?
Comment 21 Knut Wannheden CLA 2011-04-14 05:59:45 EDT
(In reply to comment #20)
> Would it be possible to add a test case that documents the lazy cross reference
> resolution in the default resource description strategy, e.g. one that shows
> that a referenced resource will not be loaded into the resource set for the
> sake of creating reference descriptions?

Yes, I will add a test case for that. That will be useful.
Comment 22 Knut Wannheden CLA 2011-04-14 11:14:40 EDT
pushed to master.
Comment 23 Karsten Thoms CLA 2017-09-19 18:01:47 EDT
Closing all bugs that were set to RESOLVED before Neon.0
Comment 24 Karsten Thoms CLA 2017-09-19 18:12:07 EDT
Closing all bugs that were set to RESOLVED before Neon.0