Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 246494

Summary: Optimization for containment proxies.
Product: [Modeling] EMF Reporter: Simon Mc Duff <smcduff>
Component: CoreAssignee: Ed Merks <Ed.Merks>
Status: VERIFIED FIXED QA Contact:
Severity: enhancement    
Priority: P3 CC: Ed.Merks
Version: 2.4.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Further optimizations of contains testing for containment lists none

Description Simon Mc Duff CLA 2008-09-07 12:50:55 EDT
Simon,

With containment proxies, there's also the case where the container is null that we'd definitely need to walk the contents of the list to resolve proxies.  But if there is a non-null container,  and it's a proxy, and we can resolve that proxy, and the resolved result is the owner of the list, then I think we can avoid walking the list.   If you open a bugzilla feature request, I'll revisit the issue and consider which additional cases can avoid walking the list as an improved optimization.  EcoreEList.contains has parallel logic that would benefit from similar treatment...


Simon McDuff wrote: 
If I understand correctly...
 
If we resolve both the container and the object (if they are proxy)... we don't need to go through that list anymore ? (only for a containment relationship).
 
Simon
 
 
"Ed Merks" <Ed.Merks@gmail.com> a écrit dans le message de news: ga0u8r$3f4$1@build.eclipse.org...
Simon,

Comments below.

Simon McDuff wrote: 
Thank you Ed,
 
Tell me if I'm wrong but...Based on what you said
"Not that the object itself is a proxy but rather there being an object in the list that is a proxy for it."
 
Why we need to care where object  is in the list ?
I was just pointing out that there is no way to know which if any object in the list might be the proxy proxy. 

 
if we have the real object and the list contains the real object as well... we did look in the list for nothing. Right ?
Note thought that we called eInternalContainer, so the container object itself might be the proxy.

 
if we have the real object and the list contains the proxy... why we care... the proxy will load the real object that we already have... but it will never happen since the real object will detect that its owner is that container. Right ?
Not until the container itself is resolved, but it does make me think about checking that the container is a proxy and if so, trying to resolve it...

 
In both cases, we do that iteration through the list for nothing. Right ?
I hope not. :-P

 
My concern is more about performance. Since CDO have the possibility to have proxy objects... I'm reviewing bottleneck in the code with my performance framework and since I still do not understand that part...I'm asking a few questions. If we can avoid it.. why not :-)
I'll think about it some more as well.  With cross resource containment, it's also possible for the contained child not have have a container proxy and then it's reparent when the container actually resolves the proxy...

 
I'm also curious :-)
:-P

 
"Ed Merks" <Ed.Merks@gmail.com> a écrit dans le message de news: ga0qtt$o50$1@build.eclipse.org...
Simon,

Comments below.

Simon McDuff wrote: 
Hi Ed,
 
I have a stupid question.
 
I was looking at the following code in DelegatingEcoreEList.contains
 
else if (isContainment())
{
InternalEObject eObject = (InternalEObject)object;
boolean result =
eObject.eInternalContainer() == owner && 
(hasNavigableInverse() ? 
eObject.eContainerFeatureID() == getInverseFeatureID() :
InternalEObject.EOPPOSITE_FEATURE_BASE - eObject.eContainerFeatureID() == getFeatureID());
if (hasProxies() && !result)
{
for (int i = 0; i < size; ++i)
{
EObject containedEObject = resolveProxy((EObject)delegateGet(i));
if (containedEObject == object)
{
return true;
}
}
}
return result;
}
 
I understand this is an optimization.
 
I don't understand why we need to fetch all objects since we already looked at the containerID and the eINternalOwner to determine if object belong to that list.
Why we need to load every instance of the list in the case where it could be proxies ?
Because in that case, the list could contain a proxy instead of the real object.

 
If it is because object could be a proxy... so why not just resolve that specific object and test it after the same way we will do.
Not that the object itself is a proxy but rather there being an object in the list that is a proxy for it.

Like the following:
 
else if (isContainment())
{
InternalEObject eObject = (InternalEObject)object;
if (object.eIsProxy())
{
    // resolve object
}
 
return 
eObject.eInternalContainer() == owner && 
(hasNavigableInverse() ? 
eObject.eContainerFeatureID() == getInverseFeatureID() :
InternalEObject.EOPPOSITE_FEATURE_BASE - eObject.eContainerFeatureID() == getFeatureID());
 
I'm sure I overlooked something!! :-)
Resolving one end of the proxy doesn't resolve the other end. I.e., if A has a proxy reference to B' then B will have a proxy reference to A', but resolving A's proxy reference from B' to be the real B doesn't cause B's proxy reference to A' to also be resolved and we don't even know where in B's list A' actually appears.  I suppose we could avoid doing the resolves if the object itself is a proxy...  Is that really the case you are encountering though?

Usually resolveProxies is set to false containment features.  Do you have a specific need for containment proxies that are causing issues or you're just generally curious?

 
Thank you.
Comment 1 Ed Merks CLA 2008-09-08 12:35:03 EDT
Created attachment 111969 [details]
Further optimizations of contains testing for containment lists

The idea here is that I resolve the container if it's a proxy.  If the regular test as before doesn't yield true, then we do additional checking only if we're resolving proxies, the container is null (if it's in a different non-null container then it can't be contained in the list) and if the object is directly in a resource (if it isn't in a resource, a proxy can't resolve to it, so no point in checking the proxies).  And if the container itself is an unresolved proxy, it hard to imagine that the proxies in the "real container" could resolve themselves to the object.  I think this change is especially nice because it allows new detached objects to be added to a containment list, even a proxy resolving one, without an O(n) test.

I've not tested it very well beyond the normal tests, which do include cross resource containment tests, but it's early in the release cycle so there will be plenty of time to detect any major mistakes in my though processes...

Does this look good to you?
Comment 2 Simon Mc Duff CLA 2008-09-08 13:15:45 EDT
Question:

Why in one you used "owner" and the other you used "eContainer" ?

if (hasProxies() && !result && >>owner<< == null && eObject.eDirectResource)

and yes it will solve my problem. when result == false and the eContainer != null... it will not test it again through the list !! :-) This will improve our code a lot.

Thank you
Comment 3 Ed Merks CLA 2008-09-09 11:21:50 EDT
Because I didn't test it and I'm not good at copying code.  Laziness and stupidity in other words. :-P
Comment 4 Ed Merks CLA 2008-09-12 10:33:31 EDT
The changes have been committed to CVS for 2.5.
Comment 5 Simon Mc Duff CLA 2008-09-12 11:25:26 EDT
(In reply to comment #4)
> The changes have been committed to CVS for 2.5.

Thank you Ed,

Do you know when 2.5 will be released ?
Can we put that change to 2.4 as well ?

Simon
Comment 6 Ed Merks CLA 2008-09-12 13:37:07 EDT
Releases happen each year at the end of June.  I need to be very careful what kinds of changes happen in a maintenance stream.  The fact that we're resolving the container reference could potentially have an adverse impact on some application that's not currently expecting this.  I don't generally like to take risks with the maintenance stream...
Comment 7 Simon Mc Duff CLA 2008-09-13 21:37:42 EDT
Can we add the same technics for Resource.getCOntents ?
Right now we are doing the following:

  public boolean contains(Object object) 
  {
    if (useEquals() && object != null)
    {
      for (int i = 0; i < size; ++i)
      {
        if (object.equals(data[i]))
        {
          return true;
        }
      }
    }
    else
    {
      for (int i = 0; i < size; ++i)
      {
        if (data[i] == object)
        {
          return true;
        }
      }
    }

    return false;
  }

We could do the following:

boolean contains(object)
return object.eDirectResource() == resource;



Comment 8 Ed Merks CLA 2008-09-14 06:37:16 EDT
Simon,

That's an excellent idea.  Please open a bugzilla for that.

I imagine we could do a similar thing for ResourceSet.getResources given that Resource.getResourceSet is the inverse.
Comment 9 Nick Boldt CLA 2008-10-30 23:10:00 EDT
Fix available in HEAD: 2.5.0.I200809161800.
Comment 10 Dave Steinberg CLA 2009-06-25 02:57:29 EDT
Fix available in HEAD: 2.5.0 (R200906151043).