You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by Fernando Padilla <fe...@alum.mit.edu> on 2006/04/12 20:12:24 UTC

[Discuss] the future

Howard Lewis Ship wrote:

> I suspect that, going forward, full page renders will often be the
> exception, rather than the rule. That is, you'll have a full page
> render, then a series of partial renders. In many cases, the result
> sent back to the client will not even be HTML markup, but will be an
> (XML?) data stream interpreted by JavaScript running in the browser.

** client-side-inclde
Interesting.  I have been waiting for the concept of Client-Side-Include 
for a while, and maybe tapestry will be build totally around this 
concept in the future.  For now I just created tapestry components to do 
so client-side-include, but then I had to create simple pages just to 
render the desired html fragment.


** last-modified
I am not sure if I have mentioned it before, but please as you guys are 
thinking about the framework please work in proper support for 
last-modified checking! and expires setting! for any render/request. 
This simple technique can easy multiply the number of users the system 
can handle, for zero cost ( if you were already planning on rendering 
everything anyhow ).

I have been dreaming of refactoring the rewind cycle operation to add a 
last-modified cycle, that would walk through the tree and ask each 
component it's last-modified time, and then aggregate that information 
somehow to determine the page's last-modified time.  Then determine 
after that if we actually go through the final render step.  This saves 
resources all around ( cpu, memory, response time, bandwidth ).

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [Discuss] the future

Posted by Fernando Padilla <fe...@alum.mit.edu>.
I was talking about the first step.

Just a nice consistent way to calculate last-modified, for dynamic pages 
with complex components and different data streams.  Because the only 
way to do that right now is for me to put a filter which does all 
last-mod logic: calculate last-modified and handle the if-modified-since 
headers.  But then how it calculates the last-modified must be kept in 
sync with the page is actually rendering.  And then the right filter has 
to be placed infront of the right page, etc, etc.  That's fine for a few 
pages, but sadly it'll get onerous quickly.

but of course, as we start down this path, it won't take long for 
someone to experiment with caching layers around each component render 
call, so that tapestry could cache each component render, just as you 
were talking about (this would probably be configurable per component, 
or something).  But I see that as secondary.  Though interesting, 
tapestry would then just be a framework to composition and piece 
together renderings from different components, and it could do this on 
the server-side or from the clent-side as Howard was alluding to 
earlier.  interesting, full circle.

so, I am just asking for leaders to keep in mind the last-modified and 
expires attributes for pages/components as you evolve on tapestry code. 
  they're useful.



Gordon Henriksen wrote:
> On Apr 12, 2006, at 3:42 PM, Fernando Padilla wrote:
> 
>> right.  the issue/goal with 'last-modified' is that calculating  
>> 'last-modified' will be cheaper than rebuilding the whole output.
> 
> 
> Indeed, just returning a cached rendering of a component can be  
> valuable, but I'm not sure the last-modified model is the best one  for 
> server-side cache validation. Most operating systems now support  
> filesystem change notifications; SQL Server 2005 can even notify  
> clients when a query's results would change. These are fundamentally  
> "push" models. To support both push and pull, how about something  like 
> this:
> 
>     public interface Dependency {
>         boolean isInvalid();
>     }
> 
>     void SimpleFileDependency implements Dependency {
>         File file;
>         long cachedModificationTime;
>         public SimpleFileDependency(File file) {
>             this.file = file;
>             cachedModificationTime = file.lastModified();
>         }
>         public boolean isInvalid() {
>             return cachedModificationTime != file.lastModified();
>         }
>     }
> 
>     class NotificationFileDependency implements Dependency {
>         FileChangeNotification notification;
>         boolean isInvalid;
>         public NotificationFileDependency(File file) {
>             notification = new MysicalMagicalFileChangeNotification {
>                 public void fileChanged() {
>                     isInvalid = true;
>                 }
>             };
>         }
>         public boolean isInvalid() {
>             return isInvalid;
>         }
>         public static boolean isSupported() {
>             magic!
>         }
>     }
> 
>     public class CacheEntry {
>         ...
>         public void addDependency(File file) {
>             if (NotificationFileDependency.isSupported())
>                 addDependency(new NotificationFileDependency(file));
>             else
>                 addDependency(new SimpleFileDependency(file));
>         }
>         public void addDependency(Dependency dependency) {
>             ...
>         }
>     }
> 
> A CacheEntry can easily know when it was generated, and can simply  
> report that as its modification date for the Last-Modified HTTP  header 
> field. Thus, dependencies don't need to calculate that data.
> 
> Generically determining whether something is cacheable in Tapestry  
> strikes me as harder, though.
> 
> — G
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [Discuss] the future

Posted by Gordon Henriksen <go...@mac.com>.
On Apr 12, 2006, at 3:42 PM, Fernando Padilla wrote:

> right.  the issue/goal with 'last-modified' is that calculating  
> 'last-modified' will be cheaper than rebuilding the whole output.

Indeed, just returning a cached rendering of a component can be  
valuable, but I'm not sure the last-modified model is the best one  
for server-side cache validation. Most operating systems now support  
filesystem change notifications; SQL Server 2005 can even notify  
clients when a query's results would change. These are fundamentally  
"push" models. To support both push and pull, how about something  
like this:

     public interface Dependency {
         boolean isInvalid();
     }

     void SimpleFileDependency implements Dependency {
         File file;
         long cachedModificationTime;
         public SimpleFileDependency(File file) {
             this.file = file;
             cachedModificationTime = file.lastModified();
         }
         public boolean isInvalid() {
             return cachedModificationTime != file.lastModified();
         }
     }

     class NotificationFileDependency implements Dependency {
         FileChangeNotification notification;
         boolean isInvalid;
         public NotificationFileDependency(File file) {
             notification = new MysicalMagicalFileChangeNotification {
                 public void fileChanged() {
                     isInvalid = true;
                 }
             };
         }
         public boolean isInvalid() {
             return isInvalid;
         }
         public static boolean isSupported() {
             magic!
         }
     }

     public class CacheEntry {
         ...
         public void addDependency(File file) {
             if (NotificationFileDependency.isSupported())
                 addDependency(new NotificationFileDependency(file));
             else
                 addDependency(new SimpleFileDependency(file));
         }
         public void addDependency(Dependency dependency) {
             ...
         }
     }

A CacheEntry can easily know when it was generated, and can simply  
report that as its modification date for the Last-Modified HTTP  
header field. Thus, dependencies don't need to calculate that data.

Generically determining whether something is cacheable in Tapestry  
strikes me as harder, though.

— G
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [Discuss] the future

Posted by Fernando Padilla <fe...@alum.mit.edu>.
right.  the issue/goal with 'last-modified' is that calculating 
'last-modified' will be cheaper than rebuilding the whole output.  This 
has to be application specific, it can not do this without application 
specific intervention.

Most components have no concept of what data they are rendering or 
doesn't know how to calculate last-modified efficiently, so they have to 
return "null" or "now", the cycle would continue down the tree. 
Eventually this cycle will ask one of the application components which 
does know about the data that it is rendering and knows how to calculate 
the 'last-modified' in a more efficient manner than rendering the whole 
output.  That then components returns the appropriate last-modified 
value.  Then cycle would then return the latest value, and use that for 
the whole page.

The last-modified strategy requires application specific knowledge about 
what the page/component is rendering and how to calculate last-modified 
in an efficient manner, else there is no way to calculate it, then you 
might as well disable calculation of last-modified all together.



Brian K. Wallace wrote:
> The problem with your description of a 'last-modified' process of asking
> each component what it's last-modified time was is:
>   1. With caching enabled, the question is irrelevant.
>   2. With caching disabled, the question could be irrelevant - it
> depends on what the component does. If the component retrieves the
> latest entries from a database, the component may not have changed - but
> the entries may have. This would require the component to build itself
> in order to know if it had truly changed. Past that, you aren't saving much.

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [Discuss] the future

Posted by "Brian K. Wallace" <br...@transmorphix.com>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Fernando Padilla wrote:
> 
> Howard Lewis Ship wrote:
> 
>> I suspect that, going forward, full page renders will often be the
>> exception, rather than the rule. That is, you'll have a full page
>> render, then a series of partial renders. In many cases, the result
>> sent back to the client will not even be HTML markup, but will be an
>> (XML?) data stream interpreted by JavaScript running in the browser.
> 
> ** client-side-inclde
> Interesting.  I have been waiting for the concept of Client-Side-Include
> for a while, and maybe tapestry will be build totally around this
> concept in the future.  For now I just created tapestry components to do
> so client-side-include, but then I had to create simple pages just to
> render the desired html fragment.
> 
> 
> ** last-modified
> I am not sure if I have mentioned it before, but please as you guys are
> thinking about the framework please work in proper support for
> last-modified checking! and expires setting! for any render/request.
> This simple technique can easy multiply the number of users the system
> can handle, for zero cost ( if you were already planning on rendering
> everything anyhow ).
> 
> I have been dreaming of refactoring the rewind cycle operation to add a
> last-modified cycle, that would walk through the tree and ask each
> component it's last-modified time, and then aggregate that information
> somehow to determine the page's last-modified time.  Then determine
> after that if we actually go through the final render step.  This saves
> resources all around ( cpu, memory, response time, bandwidth ).
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> 
> 
> 

I have no comment on client-side-includes - outside of js I must admit
I've either never had the need for them and/or I just don't quite grasp
the concept. Full vs. partial renderers, yes. Much past that and I think
I must be missing a point or two somewhere.

As for last-modified... I have two separate thoughts. I'd definitely
like to be able to put a cache pragma on a page and have that page
"built once, displayed over and over" (little borrowing of the Java
mantra with a tweak for caching purposes :-)). Delivering a cached page
will (should?) always be faster than a completely generated page. I'd
also like to be able to go back in time and resurrect the 'generate
static HTML from Tapestry application' thought. Having a web-server
deliver static content will usually (usual caveats: config, load, etc)
be faster and less resource intensive than asking a servlet container to
do so. I view both of these as separate 'wishes', but both designed to
do two things: speed up delivery of content to the client, and reduce
load on the server.

The problem with your description of a 'last-modified' process of asking
each component what it's last-modified time was is:
  1. With caching enabled, the question is irrelevant.
  2. With caching disabled, the question could be irrelevant - it
depends on what the component does. If the component retrieves the
latest entries from a database, the component may not have changed - but
the entries may have. This would require the component to build itself
in order to know if it had truly changed. Past that, you aren't saving much.

Brian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (MingW32)

iD8DBQFEPVItaCoPKRow/gARAoJtAJ9016W1pKpu98OYX8TsErUUW7L9yQCglhj5
TXv16cN2F6blStzQbYBdLFw=
=AnOO
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org