We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 24253
    • 125 Posts
    Hello all,

    To keep threads a bit on topic, I thought it would make sense to open a new one for caching.

    Ryan asked me about my ideas on caching, which you can find in the recursive parser thread, due the fact I did a number of profiling tests.

    The discussion in the recursive parser thread was about partial caching, calling conventions etc.
    I actually would love to sit around a table with other people discussing these kind of stuff, instead of writing down into a forum, but oh well.... ;-)

    Ryan added some nice weblinks there, and one was particularly interesting:

    php scripts serve dynamic pages, but not all parts of a page are dynamic, so the non dynamic parts are cached to improve performance

    Or something similar was stated there.

    Raymond also explained nicely how partiall caching is working with the [! !] calls.

    The point is however, why do we want people to _force_ partiall caching?

    For example, in a template, we call [!DropMenu!] so we are sure if a new page is created, it will show up in the menu...

    So, in other words, we _force_ all the pages with that template to have the Menu part recreated each and every time the page is requested, even if _nothing_ in the database changed, which will be most of the times those pages are requested, no?
    This results in _significant_ performance degradation over just caching the whole page _including_ the generated menu.

    However, there are snippets/others that _needs_ to be generated each and everytime a page is requested, like snippets containing a form, or a username stored in a coockie.

    It makes sense to cache a generated page, but _not_ store the evaluated snippet, but leave the snippet call there, in whatever form (the recursive parser will catch it always, no need to have a different format)

    So what about adding a property to a snippet in the manager, or a system call a snippet creater can call from within the snippet like:
    modx->disableCaching();
    

    Or a checkbox on the snippet page in the manager.

    At page creation time, depending on this variable, the snippet ouput is stored in the cache page, or the snippetcall is put back again/left there.....

    Now, if the state of the database changes, the allready cached pages will be obsoleted, and regenerated the first time they are requested again.
    You might ask "but partial caching would improve the situation a bit, since the page content is allready in cache, and doesn’t depend on the state of the database!"
    Thats correct, but from what I’m seeing here, the snippets consume a large part of the page creation time, so the difference between a ful newly created page, or a partiall cache page isn’t really much.
    AND, after the page is created, it can be served as a true cached page, without any snippet to be evaluated for as long as the database doesn’t change!
    Compare that to the slightly faster _first_ creation of the page with partiall caching, with continuously degraded performance for all the other page requests for as long as the database doesn’t change....

    Fancy/complex/arrays of states/whatever way you want to "detect" if a page can be served from cache, partiall or not will add time to _every_ request for a page, even if it can be served _completely_ from the page cache.

    Adding one time stamp in a flat file with the time the database was lastly changed, and the page creation time stamp in the page cache file, that would be fast no?
    Just one if statement, and if true, the page is recreated from database, and not true, the page is served from cache, _and_ the recursive parser is run over the cached page to evaluate those snippets which are forced to be non cachable (given by a parameter set by the snippet _creator_, not the person who inserts the call into a template)

    Now, there is a little problem with for example this:


    [[DropMenu? startDoc=[[*lang]] ]]
    


    In this case the [[*lang]] depends on a cookie, so the creator of this snippet decided it should be non-cachable.
    Right, but the DropMenu doesn’t know this, and _is_ cachable, so we have a problem here.
    Not sure how to code it yet, but from within the recursive parser, it should be possible to return the "is cachable" bit for nested snippets, and if there is a non-cacheble nested snippet, the "parent" snippet will be set un-cachable too....

    So, this way, partiall caching works transparantly for the user, and only the snippets which are really non-cachable will not be cached.
    Pages will almost always be served from a completely cached page cache, greatly improving the parsers speed.


    Of course, I could be totally wrong smiley

    Remon
      • 1764
      • 680 Posts
      Just one quick note. I think it would be valuable to use a "Cache for ___ min" property instead of a boolean value. 0 would be no caching, a date/time snippet could cache for 1 minute, an RSS feed could cache for 15min. A "Quote of the day" snippet could cache for a few hours.
        • 24253
        • 125 Posts
        Good idea!

        Perhaps, having both options will make sense like:

        - ’non-cachable’
        - ’cache for xx seconds’

        Options in the snippets properties thingie

        Remon
          • 25663 MODX Staff
          • 12,272 Posts
          Remon,

          Thanks for the thorough analysis. I’ve long been a fan of putting the caching inside an advanced settings tab for each snippet/chunk/whatever. The average users surely don’t need to know about it or get distracted by it (oh look... it’s not cahced... I want to make my site faster, sooooooo.... tick )!

          We will loose some runtime flexibility without inline ! calls. But for the sake of standarization and a less complex implementation, and less code in the parser to check for yet another syntax, and one less thing to test and beat up prior to release, I’m for it. If we ever decide to change our minds in the future (to remove it for example), there’ll be one less thing to worry about. Besides, we can alway add it back in later, too!



            Ryan Thrash, MODX Co-Founder
            Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
            • 24253
            • 125 Posts
            Quote from: rthrash at Nov 16, 2005, 08:11 AM

            We will loose some runtime flexibility without inline ! calls.

            Well, depending on the implementation, I don’t think we loose this!

            Setting a parameter for a snippet to have a non-cached, or calling it like [! !] has the same result

            You’re right in saying, that if you call the snippet multiple times cached and non-cached (like [[ ]] and [! !]) you loose this functionality.

            But I bet it’s rather easy to override the parameter like:
            [[MySnippet? cachable=0]]

            So you’ll have best of both worlds ;-)

            Remon
              • 25663 MODX Staff
              • 12,272 Posts
              Now a special reserved &cachable call is an even better call!

              I still can’t come up with an instance of needing to call the same snippet cached in one place and uncached in another. And I’d challenge someone to come up with a sane example that couldn’t readily be achieved another way. IOW, it may be a temporary pain to loose the old friend [!, but even in the short run I think we can just look at that as growing pains... wink
                Ryan Thrash, MODX Co-Founder
                Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
                • 24253
                • 125 Posts
                Quote from: rthrash at Nov 16, 2005, 08:25 AM

                Now a special reserved &cachable call is an even better call!

                I still can’t come up with an instance of needing to call the same snippet cached in one place and uncached in another. And I’d challenge someone to come up with a sane example that couldn’t readily be achieved another way. IOW, it may be a temporary pain to loose the old friend [!, but even in the short run I think we can just look at that as growing pains... wink

                Hehe, indeed!

                But if you like the [! to still work, no problem too smiley

                However, since the format of the call’s will change anyway, it seems it doesn’t make sense to keep [! !] calls working, and all the others not....
                  • 25663 MODX Staff
                  • 12,272 Posts
                  Let’s get a quick show of hands... who’s for keeping the [! syntax (keep it!)? And who’s for loosing (loose it!) it by moving it to a checkbox on the snippet/chunk/whatever page and adding a timestamp check. (I don’t want to start another Poll topic)

                  If we do loose it, we should also weigh the performance/flexibility implications of adding support for a reserved system parameter (&cache=0|1) as well.

                  For me: loose it!
                    Ryan Thrash, MODX Co-Founder
                    Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
                    • 34162
                    • 1 Posts
                    One less syntax to remember1

                    I agree, loose it!
                      • 32963
                      • 1,732 Posts
                      IMO I think caching should be left up to the developer.

                      Another way to handle this is to do something like:
                      $modx->cache->disable(); // disable caching for the current snippet/resource
                      // check internal cache
                      $cache = $modx->cache->load('MyCacheName');
                      if(!$cache) {
                         // generate snippet code 
                      }
                      // store result in cache
                      $ttl = 60000; // time to live in seconds
                      $dependencies = array(
                         'documents'=>array($modx->documentIdentifier),
                         'chunks'=>'MyChunkName'
                      );
                      $modx->cache->save('MyCacheName',$source,$ttl,$dependencies);
                      return $source;

                      Internal cache is stored inside the database. The $dependencies is used to identify objects that the snippet depends on. If the object was updated then then the cache is removed from the system.

                      Another way to handle this is simply disable the cache:

                      $modx->cache->disable(); // this snippet will never be cached


                      By default the output of the snippet will be cached based on the cache settings of the document. The only exception is when the $modx->cache->disable(); is called from within the snippet code
                        xWisdom
                        www.xwisdomhtml.com
                        The fear of the Lord is the beginning of wisdom:
                        MODx Co-Founder - Create and do more with less.