Can xCP deploy a custom DFC aspect along with its main application?

Hi.
For performance reasons I need to duplicate and keep in sync parent_id and child_id as x_parent_id and x_child_id attributes of an xCP relation type. I have created an aspect java class and a module in Composer that overrides the doSave() method of DfPersistentObject, deployed from Composer and successfully attached it to the xCP relation type as a default aspect.

Now, we have a CI/CD config that deploys our xCP app on various servers using the provided maven project

mvn -B -X -f FooApplication/pom.xml -DdesignerPath=/u01/jenkins/xCPDesigner16.4p06 xcp-import-project:run clean package
...
./deploy-xcp-application.sh

Is it possible to make our custom aspect part of the app? Or do I have to resort to using the Headless Composer on server?

Comments

  • Curious, why are you trying to do this using aspect when you can set up a business event in xCP that will get triggered when parent and child objects get versioned? Presumably this is what you are trying to maintained in your relationship.

  • @DCTM_Guru said:
    Curious, why are you trying to do this using aspect when you can set up a business event in xCP that will get triggered when parent and child objects get versioned? Presumably this is what you are trying to maintained in your relationship.

    The relation may created without altering the parent and child objects. There won't be any business events. The relation itself does not produce business events. It already has a default aspect defaultrelationaspect, but its purpose is unknown.

    The database stats on the table dm_relation_s is imprecise. Some relations are 1:1 others are 1:many. The query optimizer can't choose the best plan.

  • If you are not altering parent and child objects, what are you trying to keep in sync "... duplicate and keep in sync parent_id and child_id as x_parent_id and x_child_id attributes"? An example would be helpful in the discussion.

  • ![](https://us.v-cdn.net/6030023/uploads/editor/3w/ay7na28ob51d.png "")

    _

    public class SyncXRelationAspectImpl extends DfPersistentObject implements SyncXRelationAspect {

    private static final String CHILD_ID = "child_id";
    private static final String PARENT_ID = "parent_id";
    private static final String X_CHILD_ID = "x_child_id";
    private static final String X_PARENT_ID = "x_parent_id";

    public void dummy(Object param) throws DfException {
    }

    @Override
    protected synchronized void doSave(boolean arg0, String arg1, Object[] arg2)
    throws DfException {
    if (isSyncXRelationSupported()) {
    syncXRelation();
    }
    super.doSave(arg0, arg1, arg2);
    }

    private boolean isSyncXRelationSupported() throws DfException {
    if (!(this instanceof IDfRelation)) {
    return false;
    }
    for (int i = 0, sz = getAttrCount();i < sz; i++) {
    if (X_PARENT_ID.equals(getAttr(i).getName())) {
    return true;
    }
    }
    return false;
    }

    private void syncXRelation() throws DfException {
    setString(X_PARENT_ID, getString(PARENT_ID));
    setString(X_CHILD_ID, getString(CHILD_ID));
    }

    }
  • Your code only shows me how you are syncing - not why. I may be able to provide alternate solution if I know what you are trying to (ie why are you syncing). Are you trying to keep history of what the relation was?

  • > @DCTM_Guru said:
    > Your code only shows me how you are syncing - not why. I may be able to provide alternate solution if I know what you are trying to (ie why are you syncing). Are you trying to keep history of what the relation was?

    No. We have a dql query for searching. In it we join tst_par2chld. It gets converted to SQL that actually joins 2 tables: dm_relation_s and tst_par2chld_s.

    dm_relation_s is huge and has imprecise stats. We want to join only tst_par2chld_s.
  • Why don't you create a view for your JOIN and register it? Once its registered, you can query against it using DQL. We do this all the time and if you look at the system objects in the database, you can see that Documentum also takes advantage of views for performance reasons.

  • @DCTM_Guru said:
    Why don't you create a view for your JOIN and register it? Once its registered, you can query against it using DQL. We do this all the time and if you look at the system objects in the database, you can see that Documentum also takes advantage of views for performance reasons.

    What do you think should be in this view? If it's on dm_relation_s the query optimizer won't perform any better than querying it directly.

  • You said that you have DQL search query that you join with tst_par2chld. I am proposing that you eliminate the creation of tst_par2chld and create a view that between child object type and the dm_relation_s to avoid doing the JOIN at run-time.

  • @DCTM_Guru said:
    Why don't you create a view for your JOIN and register it? Once its registered, you can query against it using DQL. We do this all the time and if you look at the system objects in the database, you can see that Documentum also takes advantage of views for performance reasons.

    A view generally doesn't improve performance (unless it's a materialized view). They allow you to simplify queries or bypass DQL-limitations (e.g. outer joins before they were supported in DQL).

  • Thanks Hicham, as you can tell I'm not a dba :smile: Do you any suggestions for OP to avoid sync'ing relation?

    basinilya - are you using custom relation types? This might help you filter down the number relations when relating to the parent/child types.

  • @DCTM_Guru said:
    basinilya - are you using custom relation types?

    Yes. There's the type tst_par2chld in which I added the attributes x_parent_id and x_child_id.

  • If you already have a custom relation type, then why aren't you using just using out of box parent_id and child_id for that type (e.g tst_par2chld). I can see if you were using generic dm_relation (w/o explicit relation_name), that querying it might not be performant.

    How many relation object do you have for tst_par2chld? We have over 1M relations and have no performance with querying it, since all of our relations are custom relation types.

  • @DCTM_Guru said:
    If you already have a custom relation type, then why aren't you using just using out of box parent_id and child_id for that type

    Because these two attributes reside in dm_relation_s. This is how inheritance works in Documentum. tst_par2chld_s only contains the attributes that I defined explicitly for that type.

  • DCTM_Guru
    edited May 2, 2019 #16

    You are missing my point - I know how inheritance works. If you run this DQL - select * from tst_par2chld, you will see parent_id, child and your custom x_parent_id and x_child_id. What I am asking is instead of trying to sync parent_id to x_parent_id and child_id to x_child_id, why aren't you using just using parent_id and child for tst_par2chld?

    When you query for relation, just use custom relation name (tst_par2chld vs dm_relation) and you will get better performance.

  • @DCTM_Guru said:
    When you query for relation, just use custom relation name (tst_par2chld vs dm_relation) and you will get better performance.

    When we use the custom relation name in DQL it converts to SQL that joins two tables: tst_par2chld_s and dm_relation_s.
    It would be more efficient, if we could join just tst_par2chld_s. This is why we're trying to copy the attributes there.

  • Can you provide sample DQL using your custom relation? When I run DQL with our custom relation in DA and Show the SQL [output], I don't see join to dm_relation_s.

  • The exec> @DCTM_Guru said:

    Can you provide sample DQL using your custom relation? When I run DQL with our custom relation in DA and Show the SQL [output], I don't see join to dm_relation_s.

    You don't see it, because there's a view with the "_sp" suffix in your SQL. This view selects from dm_relation_s.

    My dql

    select 1 from tst_par2chld p2c,tst_fparent p, tst_fchild c where parent_id = p.r_object_id 
    and child_id = c.r_object_id;
    

    sql:

    select all 1 from tst_par2chld_sp  p2c, tst_fparent_sp  p, tst_fchild_sp  c 
    where ((p2c.parent_id= p.r_object_id) and (p2c.child_id= c.r_object_id)) 
    and (p.i_has_folder = 1 and p.i_is_deleted = 0) 
    and (c.i_has_folder = 1 and c.i_is_deleted = 0);
    

    See the attached execution plan that proves that dm_relation_s is part of it.

  • After seeing your DQL, it looks similar to what we have. That being said, how many dm_relation objects do you have? We have almost a million and don't have any issues that requires us to "sync" from parent_id and child_id from dm_relation_s.

    Have you tried checking if the all the dm_relation objects are still valid (ie prune the invalid relationship)? If parent or child ID doesn't exist anymore, you don't need dm_relation object that references it.

  • @basinilya said:
    The relation itself does not produce business events.

    Somebody should have told me that the relation's business events can be defined in the "Source Model" (parent) type.

    Now, the business events have a drawback: they're triggered from XcpTransactionListener.onPreCommit. That is, if you want to update another attribute of a changed persistent object:

    • Additional database operation UPDATE is performed before commit, while a simple aspect overriding doSave() will do its work within the same database operation
    • DQL SELECT that you run in the same session before and after commit may give different results, if it queries database columns that are not yet updated by the business event.