You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-issues@jackrabbit.apache.org by "Tomek Rękawek (JIRA)" <ji...@apache.org> on 2019/04/02 12:03:00 UTC

[jira] [Comment Edited] (OAK-8185) Improve CompositeNodeStore performance

    [ https://issues.apache.org/jira/browse/OAK-8185?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16807672#comment-16807672 ] 

Tomek Rękawek edited comment on OAK-8185 at 4/2/19 12:02 PM:
-------------------------------------------------------------

Let me elaborate a bit on the way how the Composite Node Store works with regards to the mount support. We have a single writeable mount {{/}} and a number of read-only mounts. For the production purposes we usually have a single read-only mount, called {{libs}}. This mount is available under a few paths:

* /libs
* /apps
* /jcr:system/rep:permissionStore/oak:mount-libs-crx.default

Apart from that there's something called "path-fragments", which allows to have dynamically mounted paths. If, in the global mount, we have a node named {{oak:mount-libs-...}}, its subtree will be also taken from the {{libs}} mount.

Now, in order to make the composite node store performant, we need to minimize the number of places where we have the CompositeNodeState/Builder wrappers. For instance, we need to have such a wrapper for the {{/}}, because calling {{getChild("libs")}} should give us a node from one node store while calling {{getChild("content")}} should redirect us to another. The path fragments makes this task a bit difficult, because the {{oak:mount-...}} may appear anywhere. In order to mitigate this issue, the mount configuration has one more property: {{pathsSupportingFragments}}. This way we can define the subtrees supporting potential dynamic mounts. The {{pathsSupportingFragments}} supports pattern, so we can also define the depth of this tree. For instance, the for the production we use:

{noformat}
/oak:index/*$
{noformat}

This way, the pathSupportingFragments are only supported under the direct children of the /oak:index. See OAK-6585 for more info on the patterns.

With this setup, we were able to limit the instances of CompositeNodeState/Builder wrappers only to following paths:

* /
* /jcr:system
* /jcr:system/rep:permissionStore
* /oak:index
* /oak:index/[index-name]

Now, about the benchmarks. Since the Composite Node Store requires a few repositories that are joined together, it's quite hard to prepare a fixture that'll match the production env with all the benchmarks. The current Oak-Composite-Store fixture mounts a few read-only repositories under a few paths using the pattern {{mount-%d-path-%d}}. However, they are not used for reading. The {{pathsSupportingFragments}} is set to {{/}}, therefore the Composite Node Store doesn't use the skip-to-native-store optimization described above. After switching the {{pathSupportingFragments}} to something more restrictive, like {{/oak:index/*$}}, the only composite-wrapped node will be {{/}}. See  [^OAK-8185-update-fixture.patch]. The numbers looks as follows:

{noformat}
Apache Jackrabbit Oak 1.12-SNAPSHOT
# GetDeepNodeTest                  C     min     10%     50%     90%     max       N
Oak-Segment-Tar                    1      49      51      54      59      76    1095
Oak-Composite-Store                1      57      59      63      69     105     936
{noformat}

I'm open to suggestions on how to reflect the Composite Node Store performance better in the oak-benchmarks. I feel that right now (before or after applying the patch) the numbers are not really relevant for the real-life usage.


was (Author: tomek.rekawek):
Let me elaborate a bit on the way how the Composite Node Store works with regards to the mount support. We have a single writeable mount {{/}} and a number of read-only mounts. For the production purposes we usually have a single read-only mount, called {{libs}}. This mount is available under a few paths:

* /libs
* /apps
* /jcr:system/rep:permissionStore/oak:mount-libs-crx.default

Apart from that there's something called "path-fragments", which allows to have dynamically mounted paths. If, in the global mount, we have a node named {{oak:mount-libs-...}}, its subtree will be also taken from the {{libs}} mount.

Now, in order to make the composite node store performant, we need to minimize the number of places where we have the CompositeNodeState/Builder wrappers. For instance, we need to have such a wrapper for the {{/}}, because calling {{getChild("libs")}} should give us a node from one node store while calling {{getChild("content")}} should redirect us to another. The path fragments makes this task a bit difficult, because the {{oak:mount-...}} may appear anywhere. In order to mitigate this issue, the mount configuration has one more property: {{pathsSupportingFragments}}. This way we can define the subtrees supporting potential dynamic mounts. The {{pathsSupportingFragments}} supports pattern, so we can also define the depth of this tree. For instance, the for the production we use:

{noformat}
/oak:index/*$
{noformat}

This way, the pathSupportingFragments are only supported under the direct children of the /oak:index. See OAK-6585 for more info on the patterns.

With this setup, we were able to limit the instances of CompositeNodeState/Builder wrappers only to following paths:

* (will complete this list in a few minutes)

Now, about the benchmarks. Since the Composite Node Store requires a few repositories that are joined together, it's quite hard to prepare a fixture that'll match the production env with all the benchmarks. The current Oak-Composite-Store fixture mounts a few read-only repositories under a few paths using the pattern {{mount-%d-path-%d}}. However, they are not used for reading. The {{pathsSupportingFragments}} is set to {{/}}, therefore the Composite Node Store doesn't use the skip-to-native-store optimization described above. After switching the {{pathSupportingFragments}} to something more restrictive, like {{/oak:index/*$}}, the only composite-wrapped node will be {{/}}. See  [^OAK-8185-update-fixture.patch]. The numbers looks as follows:

{noformat}
Apache Jackrabbit Oak 1.12-SNAPSHOT
# GetDeepNodeTest                  C     min     10%     50%     90%     max       N
Oak-Segment-Tar                    1      49      51      54      59      76    1095
Oak-Composite-Store                1      57      59      63      69     105     936
{noformat}

I'm open to suggestions on how to reflect the Composite Node Store performance better in the oak-benchmarks. I feel that right now (before or after applying the patch) the numbers are not really relevant for the real-life usage.

> Improve CompositeNodeStore performance
> --------------------------------------
>
>                 Key: OAK-8185
>                 URL: https://issues.apache.org/jira/browse/OAK-8185
>             Project: Jackrabbit Oak
>          Issue Type: Improvement
>          Components: store-composite
>            Reporter: Marcel Reutegger
>            Assignee: Tomek Rękawek
>            Priority: Minor
>         Attachments: OAK-8185-update-fixture.patch, composite-node-builder.txt
>
>
> While working on OAK-8141 I noticed the benchmark numbers for GetDeepNodeTest on Oak-Composite-Store are rather low compared to Oak-Segment-Tar.
> {noformat}
> Apache Jackrabbit Oak 1.12-SNAPSHOT
> # GetDeepNodeTest                  C     min     10%     50%     90%     max       N 
> Oak-Segment-Tar                    1      35      37      39      41      64    1524
> Oak-Composite-Store                1     203     204     208     214     236     288
> {noformat}
> In an offline conversation [~tomek.rekawek] mentioned the overhead shouldn't be that big because the implementation should switch to the non-composite implementation as soon as the read operation traverses into the global/writable node store. It seems however, this is not the case  when running GetDeepNodeTest. So, this may well be a bug and not an improvement, as filed at the moment.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)