Full page and fragment caching

The method by which the WAS caches JSP files is based on how the JSP is written. If the page output for a particular WebSphere Commerce command always produces the same result based on the URL parameters and request attributes, then this page output can be cached with the cache-entry using the property element, consume-subfragments (CSF) along with the WebSphere Commerce controller servlet (com.ibm.commerce.struts.ECActionServlet.class) as the servlet name. When the cache-entry is defined in this manner, then the page output is cached in a manner known as full page caching. The big advantage of using consume-subfragments with the controller servlet is performance, but if there is personalized information on the page, such as a mini shopping cart, then full page caching with fragments can be used.

If the page output has sections that is user-dependent, then the page output is cached in a manner known as fragment caching. That is, the JSP pages are cached as separate cache entries, and get reassembled when they are requested. For fragment (JSP) caching, WebSphere Commerce has to execute the command to determine which JSP is to be executed before the dynamic caching mechanism can determine if the JSP can be served up from cache or not. The advantage of this method is flexibility, because different cache entries can be reassembled together to form a page, based on user information.

In some cases it is practical to exclude certain fragments from being cached with an entire page. Instead of being cached with the full page, the fragments are cached separate. For example, if there is a personalized welcome message or a mini current order page, then the do-not-consume property is used. The parent entry is marked with the property consume-subfragments and the child fragment that contains the personalization area would be marked with this do-not-consume property. With this combination, the performance gain of whole page caching remains intact for the entire page excluding the child fragment that is cached separately apart from its parent.

 

Full page caching

When the property element consume-subfragments (CSF) is used, the cache entry for the parent page (the one marked with CSF) will include all the content from all fragments in its cache entry, resulting in one big cache entry that has no includes or forwards, but rather, the content from the whole tree of entries.

When a servlet is cached, only the content of that servlet is stored. The cache includes place holders for any other fragments to which it includes or forwards. Consume-subfragments (CSF) tells the cache not to stop saving content when it includes a child servlet. The parent entry (the one marked CSF) will include all the content from all fragments in its cache entry, resulting in one big cache entry that has no includes or forwards, but the content from the whole tree of entries. This can save a significant amount of application server processing, but is typically only useful when the external HTTP request contains all the information needed to determine the entire tree of included fragments.

For example, if the <cache-entry> is defined as follows:

<cache-entry>
  <class>servlet</class>
 
<name>com.ibm.commerce.struts.ECActionServlet.class</name>
  <property name="consume-subfragments">true</property>
  <property name="save-attributes">false</property>
  <property name="store-cookies">false</property>

  <!-- StoreCatalogDisplay?storeId=<storeId> -->
  <cache-id>
     <component id="" type="pathinfo">
        <required>true</required>
           <value>/StoreCatalogDisplay</value>
     </component>
     <component id="storeId" type="parameter">
        <required>true</required>
     </component>
  </cache-id>
</cache-entry>


when the save-attributes property is set to false, the request attributes are not saved with the cache entry. When the store-cookies property is set to false, the request cookies are not saved with the cache entry.

In the preceding example, the cache servlet entry will contain a consumed include of StoreCatalogDisplay.jsp which is the JSP file forwarded by the StoreCatalogDisplay command.

 

Fragment cache

For a fragment to be cacheable it needs to be self-executable. Each dynamically included JSP file has to have its own <cache-entry> defined in the cachespec.xml file in order to be served up by the dynamic cache when it receives a request. Otherwise, each dynamically included JSP file will be re-executed for each request. For example, consider if StoreCatalogDisplay.jsp dynamically includes CachedHeaderDisplay.jsp, CachedFooterDisplay.jsp and CachedStoreCatalogDisplay.jsp and you only set up a <cache-entry> for the CachedStoreCatalogDisplay.jsp. Then, when you request the StoreCatalogDisplay page, the CachedStoreCatalogDisplay.jsp, CachedHeaderDisplay.jsp and CachedFooterDisplay.jsp files will get executed if they are not cached. Here is an example of how to define the <cache-entry> for CachedStoreCatalogDisplay.jsp:

<cache-entry>
  <class>servlet</class>
 
<name>/AdvancedB2BDirect/ShoppingArea/CatalogSection/CategorySubsection/CachedStoreCatalogDisplay.jsp</name>
  <property name="save-attributes">false</property>
                
  <cache-id>
     <component      id="storeId" type="parameter">
          <required>true</required>
     </component>
     <component      id="catalogId" type="parameter">
          <required>false</required>
     </component>                    
  </cache-id>
</cache-entry>


Note: If consume-subfragments is set to true, then each dynamically included JSP file does not require it's own <cache-entry>.

Consider a sample Web page. The following figure shows a personalized Item Display page for the Advanced B2B Direct store, that contains user-specific information. There is not much value to caching this whole page.

Example of a personalized page

The next figure shows the same page broken down into fragments based on reusability and cacheability. In this example, the page can be broken into different fragments:

Example of a personalized page fragmented for caching

In this case, all of the fragments become reusable or cacheable for a larger audience. Only fragments that are not cacheable need to be fetched from the backend, reducing server-side workload and improving performance.

 

Cache whole page excluding certain fragments

In some cases it is practical to exclude certain fragments from being cached with an entire page. Instead of being cached with the full page, the fragments are cached separate. For example, if there is a personalized welcome message or a mini current order page, then the do-not-consume property is used. The parent entry is marked with the property consume-subfragments and the child fragment that contains the personalization area would be marked with this do-not-consume property. With this combination, the performance gain of whole page caching remains intact for the entire page excluding the child fragment that is cached separately apart from its parent.

The following Web page which is a common product page and its sidebar dynamically includes a fragment (MiniCurrentOrderDisplay.jsp) that displays a personalized mini current order page.

Construct cache ID rules in order to cache the product page and the mini current order page. The mini current order page is unique for each user, therefore in order to cache it, the user's ID is the cache ID. Create a request attribute DC_userId so the user ID is used as the cache ID.

Here is an example of the cachespec.xml:

<cache-entry>        
        <class>servlet</class>         
       
<name>/AdvancedB2BDirect/ShoppingArea/CurrentOrderSection/MiniCurrentOrderDisplay.jsp</name>
   
        <property name="do-not-consume">true</property>
    
        <property
name="save-attributes">false</property>     
        <cache-id>         
                <component id="DC_userId" type="attribute">  
          
                        
<required>false</required>
                       
<not-value>-1002</not-value>
                </component> 
        </cache-id> 
</cache-entry> 


<cache-entry> 
        <class>servlet</class> 
       
<name>com.ibm.commerce.struts.ECActionServlet.class</name>

        <property name="store-cookies">false</property>

        <property
name="save-attributes">false</property> 
        <property
name="consume-subfragments">true</property> 
        <cache-id> 
                <component id="" type="pathinfo"> 
                        <required>true</required> 
                       
<value>/StoreCatalogDisplay</value> 
                </component>
                <component id="storeId" type="parameter">
                        <required>true</required>
                </component>
                <component id="catalogId" type="parameter">
                        <required>true</required>
                </component>
        </cache-id>
</cache-entry>


When using the DC_userId request attribute to construct the cache ID for the fragment cache entry in a full page with fragment caching scenario, use the snippet above in the component ID. This prevents the full page entry to consume the fragment incorrectly resulting from a cache miss on the cacheable fragment by the generic user. If the full page consumes the fragment by the generic user, then any subsequent hits to this full page by other users will incorrectly get a cache hit on the full page.

The following image shows what the cache entries look like:

The following is the content of the MiniCurrentOrderDisplay cache entry:

 

The following is the MiniCurrentOrderDisplay which is excluded in the StoreCatalogDisplay cache entry:


 

Use the DC_userId in a Full Page with Fragment Caching

When using the DC_userId request attribute to construct the cache ID for the fragment cache entry in a full page with fragment caching scenario, use the following snippet in the component ID. This prevents the full page entry to consume the fragment incorrectly resulting from a cache miss on the cacheable fragment by the generic user. If the full page consumes the fragment by the generic user, then any subsequent hits to this full page by other users will incorrectly get a cache hit on the full page. This will also improve system performance because it enables the generic user to obtain cache hits on the first request, instead of on the second hit where the DC_userId is populated with the value of -1002 from the session cookie.

<cache-entry>
<class>servlet</class>
<name>/path_to_JSP/mini-cart.jsp</name>
<property name="do-not-consume">true</property>
<property name="save-attributes">false</property>
<cache-id>
<component id="storeId" type="parameter">
<required>true</required>
</component>
<component id="DC_userId" type="attribute">
<required>false</required>
<not-value>-1002</not-value>
</component>


 

Related tasks


Configure cacheable objects

 

Related Reference


Caching defaults