Since its initial release, the Domino HTTP server has had the ability to keep a volatile, in-memory cache of requested HTML pages called the Command Cache. The very nature of a dynamic Web applications server would preclude the caching of all Web pages. Some Web pages, however, are "static enough" that they can be reused when the same URL or command is issued from a browser. This article describes how the Command Cache works so that you can design applications that take advantage of its capabilities -- and the performance gains it provides.
Command Cache fundamentals
The Command Cache saves Web pages in memory in the hopes that the same Web page URL will be requested in the future, and that the cached page will still be valid to serve for that URL. To do this correctly, the cache must understand the nature of the page being saved, and it must know how to determine if that page is still valid for serving. While the Command Cache has been part of Domino since its inception, the role of the Command Cache is continually expanding as we make it more and more capable of understanding pages and determining their validity.
Caching URL commands
The following types of Domino URL commands (and the HTML that they generate) are currently the only candidates for the Command Cache:
Other commands (for example, ?EditDocument) are not considered for caching.
Domino only serves pages from the Command Cache if the URL request exactly matches the URL of the cached pages, even though Domino URL syntax allows multiple ways to specify the same URL command (by using replica IDs instead of database names, or view names instead of view UNIDs).
Determining the algorithm to make an accurate and timely decision as to which Web pages are cacheable is one stumbling block to making a very useful caching system. In 4.6, we considered the very presence of @functions (among others) too volatile, and thus, did not consider any pages with @functions as candidates for caching. Unfortunately, this meant that many Web pages could not take advantage of caching and the performance gains that it provides.
In 4.61, much has changed. As part of the on-going effort to provide performance improvements in the Domino server, we now provide the ability to cache Web pages that contain @functions. This is a very simple statement with very powerful implications for the Web site administrator, the Web application designer and the Web application user.
Domino 4.61 now has the ability to analyze all macro language (@function) formulas for their dependencies through the Formula Analyzer. Rather than exclude all pages that contain any @function formulas from the Command Cache, the Formula Analyzer intelligently examines the formula on the page and decides its level of volatility. By doing this first, Domino can decide immediately whether the command is too volatile to be cached (for example, the Web page contains @Now) and, perhaps more importantly, under what conditions a cached command becomes invalid.
The logic for these caching schemes is based on very conservative thinking. In all cases where the slightest bit of ambiguity exists, Domino will not cache the page. We considered the performance loss of re-rendering the resultant HTML to be a small tradeoff to the possibility of sending out-of-date, incorrect, or inappropriate information to the requesting user.
The Formula Analyzer is turned OFF by default in 4.61, meaning that any @function will result in the page not being cached. To enable the Formula Analyzer, place the following line in your NOTES.INI file:
It is important to note that without this setting, the Command Cache behaves exactly the way that it did in 4.6; you will still get the benefit of command caching, just without the expanded usefulness of caching Web pages where @formulas were used in the process.
When the Formula Analyzer examines a command invoking @formulas, flags are assigned to that cache candidate based on the evaluation of the @formula(s), among other things. The following flags are used by the Domino HTTP server to determine the cache strategy, explained in the next section. (A cache candidate can and often does have multiple flags.)
- OffDb -- The page uses data outside the current database. This includes the use of CGI variables.
- TimeVariant -- The page uses time-variant data (such as @Now).
- HadEffect -- The page has an important side-effect (such as @DialogBox).
- UsedEnv -- The page uses the environment (NOTES.INI). This does not include CGI variables.
- UserVariant -- The page is dependent on the user's identity. This includes using any data or design note that includes Read ACLs, Readers fields, Authors fields or controlled access sections.
- DesignUserVariant -- The page is from a database that has protected design elements.
- DbData -- The page uses data in the database other than the referenced document. This includes all views, embedded views in forms, and so on.
- UsedDocId -- The page uses the document's ID.
- UsedNewDoc -- The page uses a newly-created in-memory note.
- Unknown -- The page does something that couldn't be analyzed (such as executed LotusScript).
- Error -- The page generated an error of some sort.
Domino uses the cache flags to determine the cache strategy for a given command. A cached command can have multiple cache strategies. The most restrictive strategy wins. The strategy is stored with the command if it is cached, and is used to help determine whether the command is still valid each time it is retrieved from the cache. The cache strategies are:
- DontCache -- Don't cache the response at all.
- Document -- Invalidate the cached response when the document changes.
- DbDesign -- Invalidate the cached response when the database design changes.
- DbData -- Invalidate the cached response when any of the data in the database changes.
- OnlyAnonymous -- Cache the response, but only serve it when the user is anonymous.
Any commands with the following flags are not cached (the DontCache strategy):
- UserVariant (if authenticated)
- DesignUserVariant (if authenticated)
Here is an example of how command flags set the cache strategy. We will annotate the cache flags Flag(flag) where flag refers to the flags above. The cache strategy will be annotated as Strategy(strategy) where strategy refers to the strategies above. Using this notation, cached commands are assigned a cache strategy that defines how the cache is invalidated. This is illustrated by the following pseudocode:
Sub CACHESTRATEGY CASE OPENDOCUMENT CACHESTRATEGY = Document If Flag(OffDb) or Flag(TimeVariant) or Flag(HadEffect) or Flag(UsedEnv) then CACHESTRATEGY = DontCache //don't cache return CACHESTRATEGY //we're done End If If Flag(UsedDocId) and Flag(UsedNewDoc) then CACHESTRATEGY = DontCache //don't cache return CACHESTRATEGY //we're done End If If Flag(UserVariant) or Flag(DesignUserVariant) then If USER_AUTHENTICATED then CACHESTRATEGY = DontCache //don't cache return CACHESTRATEGY //we're done End If //not authenticated CACHESTRATEGY = CACHESTRATEGY + OnlyAnonymous //continue End If CACHESTRATEGY = CACHESTRATEGY + DbDesign //continue If Flag(DbData) then //remove Document strategy and add DbData strategy CACHESTRATEGY = CACHESTRATEGY - Document + DbData //continue End If return CACHESTRATEGY CASE OPENFORM // etc. End Sub
You are smarter than your server
The Command Cache does a good job understanding the page creation process and automatically invalidating pages, but it is not perfect. Because of its conservative nature, it errs on the side of not caching pages in order to guarantee the correctness of the page returned. You may decide that certain pages can be cached where the server determines that they cannot be. We've provided controls so that you can override the cache behavior where appropriate. The following fields can control the use of the cache to some extent:
- $CacheOptions -- If the value of this field is the text string "0", then the response is not cached.
- $CacheValid -- The value of the numeric text string N will be evaluated and will protect the response from validity checks for N seconds. This setting can be globally set by using the NOTES.INI setting "DominoDefaultCacheValid=N." The default for the HTTP server is N=0.
The $CacheValid The $CacheValidfield lets you tell the cache that this page should be considered valid for a certain number of seconds regardless of what Domino determines the cache strategy to be. Consider a simple home page that is being continually edited. As this page would be given the "Document" strategy, the cache entry would become invalid each time the page is edited. You consider it acceptable that the home page is not continually updated as a tradeoff for performance. You can communicate this to Domino by creating a $CacheValid field on the document with a value of "180." This means that the results of the page should be considered valid for 180 seconds. After that time, the normal validity checks will take place.
Viewing the cache strategy and flags for a page
If the NOTES.INI variable "DominoTraceCmdCache=1" is set, the cache strategy and the cache flags will be included in the HTTP header information that is sent to the browser when a page is served. To view this information, you can use a tool that displays this information (such as a wire-sniffer) or download the following Java application (9Kb) written by Bob Congdon at Iris from the Sandbox. This tool is not a supported product; it's just intended to be a useful utility.
Make sure that CLASSPATH has "." on it, and run the application by entering "java SpyFrame" at the command line. While Bob developed the application using the JDK 1.1.1, it should run fine with JDK1.0x since it doesn't use any JDK 1.1.1-specific classes.
The following header information is sent:
- X-DominoCmdCache-EvalInfo -- Following this is a comma-separated list of flag words (information pieces) that the Formula Analyzer set in the process of evaluating the page (see above).
- X-Domino-CmdCache-Strategy -- Following this is a comma-separated list of flag words that denotes the cache strategy that was assigned to the command based on the inspection of the EvalInfo (see above).
- X-Domino-CmdCache-ValidSeconds -- This is the number of seconds that the response will be assumed to be valid without the benefit of a validity check. This is the time set in either the $CacheValid field of the DominoDefaultCacheValid NOTES.INI variable.
- X-Domino-CmdCache-CheckValid -- This is the clock time that states when the validity check will again be allowed.
- X-Domino-CmdCache-DataMod -- This is the recorded data modification date that is used for the validity checking.
- X-Domino-CmdCache-DesignMod -- This is the recorded design modification date used for validity checking.
You can check the efficacy of your Command Cache by monitoring the following server statistics:
- Domino.Cache.Command.Count -- This is the actual number of commands that are contained in the Command Cache.
- Domino.Cache.Command.MaxSize -- This is the maximum number of commands that can be cached. This is the number configured from the Server document in the Public Address Book using the "Maximum Cached Commands" field.
- Domino.Cache.Command.HitRate -- This is the percentage-ratio of the number of times a valid cache entry is found in the cache to the number of times the cache was investigated for a cache entry.
- Domino.Cache.Command.DisplaceRate -- This is the percentage-ratio of the number of times that a new cached command displaces an aged command to the number of times the cache was investigated for a cache entry.
The following is a list of @functions and the Eval flags that are set at compute time. If a function is not listed here, safely assume that there is no associated Eval flag set. The Eval flag Depends means that the evaluation of the entire formula will determine the Eval flag set. If the @function says "Fallback", that means that there is an evaluation that is Web server-specific and this is the non-Web version. Its converse is "Web."
- @Accessed -- OffDatabase,UsedDocId
- @Certificate -- OffDatabase
- @Command - Web -- Depends
- @Command([Compose]) -- Depends,DbDesign,OffDatabase
- @Command([FileSave]) -- HadEffect
- @Created -- UsedDocId
- @DbColumn - Fallback --UserVariant,DbDesign,DbData,Unknown, Depends,OffDatabase
- @DbCommand - Fallback -- Unknown
- @DbCommand - Web -- Depends
- @DbLookup - Fallback -- Depends,Unknown,DbData,DbDesign, UserVariant,OffDatabase
- @DbManager -- DbDesign
- @DbTitle -- DbDesign
- @DocumentUniqueID -- UsedDocId
- @Environment -- HadEffect,UsedEnvironment
- @GetDocField -- DbData,UserVariant
- @GetPortsList -- UsedEnvironment
- @GetProfileField -- DbData,UserVariant
- @InheritedDocumentUniqueID -- UsedDocId
- @MailEncryptSavedPreference - Fallback -- UsedEnvironment
- @MailEncryptSentPreference - Fallback -- UsedEnvironment
- @MailSavePreference - Fallback -- UsedEnvironment
- @MailSend - Fallback -- HadEffect
- @MailSignPreference - Fallback -- UsedEnvironment
- @Modified -- UsedDocId
- @NoteID -- UsedDocId
- @Now -- TimeVariant
- @PostedCommand - Web -- Depends
- @Random -- OffDatabase
- @Responses -- DbData
- @SetDocField -- HadEffect,UserVariant
- @SetProfileField -- HadEffect,UserVariant
- @TextToTime -- TimeVariant
- @Today -- TimeVariant
- @Tomorrow -- TimeVariant
- @Unique -- None,Depends,OffDatabase
- @URLGetHeader - Fallback -- OffDatabase
- @URLOpen - Fallback -- OffDatabase,HadEffect
- @UserAccess - Web -- OffDatabase,UserVariant,DbDesign
- @UserName -- UserVariant
- @UserPrivileges -- DbDesign,UserVariant
- @UserRoles - Fallback -- DbDesign,UserVariant
- @UserRoles - Web -- DbDesign,UserVariant
- @V3UserName -- UserVariant
- @ViewTitle -- DbDesign
- @Yesterday -- TimeVariant
- @Zone -- TimeVariant
Copyright 1998 Iris Associates, Inc. All rights reserved.