Access checking takes more then 1 second - 1 minute load time umbracoMacro Options
astuanax
Posted: Monday, February 11, 2008 5:44:51 PM

Rank: Devotee

Joined: 7/20/2006
Posts: 85
Hi,

I am having a performance problem with checking access to member protected pages.
I have over 1000 members and they all belong to a group.

Each page is protected by a group, and the main navigation should not
reveal any pages that people shouldn't see.
I have tried caching the macor, but after a while it doesn't change anymore.

I am running the umbDebugShowTrace on the website and it returns this in the stack trace:

umbTemplate Outputting item: <?UMBRACO_MACRO macroAlias="MainNavigation" > 1.32483563810237 0.000293
renderMacro Rendering started (macro: Main Navigation, type: 1, cacheRate: 0) 1.33430615046879 0.009471
umbracoMacro Before adding extensions 1.34482584286182 0.010520
umbracoXsltExtension Extension added: urn:astuanax, Library 1.34533370244388 0.000508
umbracoMacro After adding extensions 1.34536757162237 0.000034
umbracoMacro Before performing transformation 1.34540537994774 0.000038
umbracoMacro After performing transformation 60.9123697348285 59.566964

The urn:astuanax xslt extension is not used in this macro, so I find this very strange that this is loaded (though it is specified as an extension and used on some macro's).
But it takes 1 minute to transform this ..., this really isn't a big navigation list...

Any ideas would be much appreciated,
Len

drobar
Posted: Monday, February 11, 2008 6:01:18 PM

Rank: Umbracoholic

Joined: 9/8/2006
Posts: 1,285
Location: KY, USA
Hi, Len,

That is veeery slow. Let's see if we can narrow down the culprit...

1. Did this performance problem begin recently, or has it always been slow? If recently, what's changed?

2. What happens to the timing if you remove the check for member permission? If the performance is still slow then it isn't the permission check and we can rule that out. If it is fast then it is entirely in the permission checking.

3. If the issue is in the permission checking, what happens if you create a member group with only a few members? If it is still slow then we know it isn't related to the number of members but to some overhead in the permission checking generally. If it is fast for a few members then perhaps you can optimize the loop that checks every one's permission?

4. Any other behavior pattern you can see?


Let us know what you find out.

cheers,
doug.



MVP 2007-2009 - Official Umbraco Trainer for North America - Percipient Studios
drobar
Posted: Monday, February 11, 2008 6:04:51 PM

Rank: Umbracoholic

Joined: 9/8/2006
Posts: 1,285
Location: KY, USA
Actually, now that I think about it a bit more...

I wonder if the number of members is the issue and if performance might slow in direct relation to the number of members in a group. If there is a database call for each member (rather than cached xml) that would slow things down considerably as the member count increased. I know that happens in the media section, but I don't recall off the top of my head if that's also true of the member area.


Maybe John Cruz or someone else can confirm or deny this?

cheers,
doug.

MVP 2007-2009 - Official Umbraco Trainer for North America - Percipient Studios
mortenbock
Posted: Monday, February 11, 2008 6:22:24 PM

Rank: Addict

Joined: 7/19/2006
Posts: 706
Location: Århus, Denmark
Just wondering if you are using the xslt function to get all members? That is known to be quite ressource intensive... Could we see your xslt file?

Morten Bock - Level 2 certified - My danish blog with a few english posts | CodeGarden on Facebook
astuanax
Posted: Tuesday, February 12, 2008 10:19:24 AM

Rank: Devotee

Joined: 7/20/2006
Posts: 85
Hi,

Here are the answers, will test these things and let you know

1. Did this performance problem begin recently, or has it always been slow? If recently, what's changed?
It was from the start, that is, with a database with very few members.

2. What happens to the timing if you remove the check for member permission? If the performance is still slow then it isn't the permission check and we can rule that out. If it is fast then it is entirely in the permission checking.

I tested this and it goes down to 3 seconds. For all entries in the trace "umbracoMacro After performing transformation" it takes about 0,5 to 1 second. Which is of course much better then the 60 seconds I had before.

3. If the issue is in the permission checking, what happens if you create a member group with only a few members? If it is still slow then we know it isn't related to the number of members but to some overhead in the permission checking generally. If it is fast for a few members then perhaps you can optimize the loop that checks every one's permission?

When I started I had 10 members, even then it was slow, but nog as it is now, this is unbearable.
I guess it is in the access checking code. I think I need to write my own xslt help or do the navigation from a user control.
Where I can do some caching as well, I guess ...

4. Any other behavior pattern you can see?
No, that is it.

For the code , teh hasaccesss check has been commented
Code:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:Stylesheet [
<!ENTITY nbsp "&#x00A0;">
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxml="urn:schemas-microsoft-com:xslt" xmlns:umbraco.library="urn:umbraco.library" version="1.0" exclude-result-prefixes="msxml umbraco.library">
  <xsl:output method="html" indent="yes"/>
  <xsl:param name="currentPage"/>
<!-- Input the documenttype you want here -->
  <xsl:variable name="documentTypeAlias" select="string('WebPage')"/>
  <xsl:variable name="source" select="$currentPage//ancestor::node[@nodeName = 'Intranet']/@id"/>
  <xsl:template match="/">
<!-- no UL element coming from the template ? -->
<!-- Home Button -->
<!-- Add current when at home-->
    <li>
      <xsl:if test="$currentPage/@id = number($source)">
        <xsl:attribute name="class">
          <xsl:value-of select="'current'"/>
        </xsl:attribute>
      </xsl:if>
      <a href="/intranet.aspx">Home</a>
    </li>
<!-- Added naviHide option to hide the page from teh navigation -->
<!-- Top Level -->
    <xsl:for-each select="umbraco.library:GetXmlNodeById($source)/node [@nodeTypeAlias = $documentTypeAlias and string(data [@alias='umbracoNaviHide']) != '1']">
<!--xsl:if test="umbraco.library:HasAccess(@id, @path)"-->
      <li id="z{@id}">
        <xsl:if test="contains($currentPage/@path,@id)">
          <xsl:attribute name="class">
            <xsl:value-of select="'current'"/>
          </xsl:attribute>
        </xsl:if>
        <a href="{umbraco.library:NiceUrl(@id)}">
          <xsl:value-of select="@nodeName"/>
        </a>
        <xsl:if test="./node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1']">
          <ul>
<!-- Divisions -->
            <xsl:for-each select="./node[@nodeTypeAlias = 'WebPage']">
<!--xsl:if test="umbraco.library:HasAccess(@id, @path) and string(data [@alias='umbracoNaviHide']) != '1'"-->
              <li>
                <a href="{umbraco.library:NiceUrl(@id)}">
                  <xsl:value-of select="@nodeName"/>
                </a>
                <xsl:if test="./node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1']">
                  <ul>
<!-- Countries -->
                    <xsl:for-each select="./node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1'] ">
<!--xsl:if test="umbraco.library:HasAccess(@id, @path)"-->
                      <li>
                        <a class="cLevel" href="{umbraco.library:NiceUrl(@id)}">
                          <xsl:value-of select="@nodeName"/>
                        </a>
<!-- Business Unit Cluser: do not show -->
                        <xsl:if test="./node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1']">
                          <ul>
                            <xsl:for-each select="./node[@nodeTypeAlias = 'WebPage']/node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1'] ">
<!--xsl:if test="umbraco.library:HasAccess(@id, @path)"-->
                              <li>
                                <a class="buLevel" href="{umbraco.library:NiceUrl(@id)}">
                                  <xsl:value-of select="@nodeName"/>
                                </a>
                              </li>
<!--/xsl:if-->
                            </xsl:for-each>
                          </ul>
                        </xsl:if>
                      </li>
<!--/xsl:if-->
                    </xsl:for-each>
                  </ul>
                </xsl:if>
              </li>
<!--/xsl:if-->
            </xsl:for-each>
          </ul>
        </xsl:if>
      </li>
<!--/xsl:if-->
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>


Any ideas on how to do the navigation with a usercontrol / or a better has access method?
It seems that the hasAccess code is looping over all the groups of the member, and I have a lot of members
that have over 30 groups assigned to them.
Maybe that causes a problem?
Code:

        public static bool HasAccess(int DocumentId, string Path, cms.businesslogic.member.Member Member)
        {
            bool hasAccess = false;

            if (!IsProtected(DocumentId, Path))
                hasAccess = true;
            else
            {
                XmlNode currentNode = getPage(getProtectedPage(Path));
                if (Member != null)
                {
                    IDictionaryEnumerator ide = Member.Groups.GetEnumerator();
                    while(ide.MoveNext())
                    {
                        cms.businesslogic.member.MemberGroup mg = (cms.businesslogic.member.MemberGroup) ide.Value;
                        if (currentNode.SelectSingleNode("./group [@id=" + mg.Id.ToString() + "]") != null)
                        {
                            hasAccess = true;
                            break;
                        }
                    }
                }
            }

            return hasAccess;
        }







astuanax
Posted: Thursday, February 21, 2008 2:37:32 PM

Rank: Devotee

Joined: 7/20/2006
Posts: 85
For those who are interested, I solved my problem by writing a few
xslt help methods that dump the list of groups a member belongs to into the XSLT
and use XSLT to check if the member has access or not.
This dropped the respone time to nothing.

For those who want the dll, please let me know.

Here is the code for the xslt helper dll, getMemberGroups and getAccesXml
Code:


public static string getMemberGroups()
        {
            int mId = Member.CurrentMemberId();
            try{
            Member m = Member. GetCurrentMember();
               if( m.Id != mId){
                   Member.RemoveMemberFromCache(m);
                   getMemberGroups();
                   return "";
               }
               else
               {
                   IDictionaryEnumerator g = m.Groups.GetEnumerator();
                   string result = "";
                   while (g.MoveNext())
                   {
                       result += g.Entry.Key.ToString() + ",";
                   }
                   return result;
               }
            }
            catch {
              return "";
            }
        }

        public static XPathNodeIterator getAccesXml()
        {
            XmlDocument a = umbraco.cms.businesslogic.web.Access.AccessXml;
            XPathNavigator xp = a.CreateNavigator();
            return xp.Select(".");
        }



And the example xslt:
Code:

<?xml version="1.0"?>
<!DOCTYPE xsl:Stylesheet [
<!ENTITY nbsp "&#x00A0;">
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxml="urn:schemas-microsoft-com:xslt" xmlns:umbraco.library="urn:umbraco.library" xmlns:astuanax="urn:astuanax" version="1.0" exclude-result-prefixes="astuanax msxml umbraco.library">
      <xsl:output method="html" indent="yes"/>
      <xsl:param name="currentPage"/>
      <!-- Input the documenttype you want here -->
      <xsl:variable name="documentTypeAlias" select="string('WebPage')"/>
      <xsl:variable name="source" select="$currentPage//ancestor::node[@nodeName = 'Intranet']/@id"/>
      <xsl:variable name="accessXml" select="astuanax:getAccesXml()"/>
      <xsl:variable name="mgroups" select="astuanax:getMemberGroups()"/>
      <xsl:template match="/">      
            <!-- no UL element coming from the template ? -->
            <!-- Home Button -->
            <!-- Add current when at home-->
            <li>
                  <xsl:if test="$currentPage/@id = number($source)">
                        <xsl:attribute name="class">
                              <xsl:value-of select="'current'"/>
                        </xsl:attribute>
                  </xsl:if>
                  <a href="/intranet.aspx">Home</a>
            </li>
            <!-- Added naviHide option to hide the page from teh navigation -->
            <!-- Top Level -->
            <xsl:for-each select="umbraco.library:GetXmlNodeById($source)/node [@nodeTypeAlias = $documentTypeAlias and string(data [@alias='umbracoNaviHide']) != '1']">
                  <li id="z{@id}">
                        <xsl:if test="contains($currentPage/@path,@id)">
                              <xsl:attribute name="class">
                                    <xsl:value-of select="'current'"/>
                              </xsl:attribute>
                        </xsl:if>
                        <a href="{umbraco.library:NiceUrl(@id)}">
                              <xsl:value-of select="@nodeName"/>
                        </a>
                        <xsl:if test="./node[@nodeTypeAlias = 'WebPage' and string(data [@alias='umbracoNaviHide']) != '1']">
                              <ul>
                                    <!-- Divisions -->
                                    <xsl:for-each select="./node[@nodeTypeAlias = 'WebPage']">
                                          <xsl:variable name="nodeId" select="@id"/>
                                          <xsl:if test="true() = boolean($accessXml/access/page[@id = $nodeId]//group[contains($mgroups, ./@id)]/@id)">
                                                <li>
                                                      <a href="{umbraco.library:NiceUrl(@id)}">
                                                            <xsl:value-of select="@nodeName"/>
                                                      </a>
                                                </li>
                                          </xsl:if>
                                    </xsl:for-each>
                              </ul>
                        </xsl:if>
                  </li>
            </xsl:for-each>
      </xsl:template>
</xsl:stylesheet>


Users browsing this topic
Guest


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.