CACHE IS CASH

If time is money, then caching your lookup in Notes agents is cash in your pocket. An agent that repeatedly makes network requests such as view lookups to read document objects for processing data and needs to find the same object over and over can benefit greatly from caching the found object to avoid the network and lookup bottleneck for future requests. I get order-of-magnitude increases in agent performance using the techniques described below in agents that I have deemed network intensive in this manner and have implemented caching strategies for. I’ve been using these caching practices in my Notes dev for as long as there’s been a LotusScript.

Of course, this is CSCI 201 for most programmers, the question is how best –read: easiest way- to accomplish this in Notes? For much of my development in Java or other languages, a hashtable of hashtables, known as a hash-of-hashes or HoH is easily implemented to store cached values in a randomly accessible data structure and retrieved using a key, which in our case would be a representation of the keys we use to make the lookup. The value retrieved would then similarly be another hash of keyword value pairs that we need in our program. In Java, this is accomplished with a Hashmap of Hashmaps. In LotusScript, it’s not so simple. To begin with, we have the ever-useful but–underutilized-in-general-practice Notes dev List. A list is LS’s analog to VB’s Dictionary object. By declaring a structure a list of datatype x, you can access the elements of the structure using a key string. You can also walk the list with a ForAll statement and retrieve its key using the ListTag function. For simple caching, a list containing primitives such as Strings or Integers may suffice. The problem arises hen you want to cache more sophisticated data. As mentioned previously, other languages allow you to hash complex objects, but the List modifier in LS doesn’t allow you to declare a List of Lists. That’s where some Object 101 comes in.You can create an arbitrary object in your agent that contains the properties you are storing in your cache and create a list of the object. User-defined objects are a pain in Notes Designer as they all have to be lumped into the Declarations section of your agent and there is (currently) no awareness in the Script editor of user defined objects for code completion, but it’s still relatively straightforward. Here’s a simple example cache object in an agent:

  1. Class projectConsultantCacheObj
  2. 'consultant name/project code combo is key
  3. Public startDate As String
  4. Public endDate As String
  5. Public rate As Integer
  6. End Class

When the agent needs a particular project’s consultant, it calls the getProjectConsultant function with the parameters of a lookup in an array. The function first concatenates the lookup values to use as the cache key and sees is there’s a cached copy of the desired object to return to the caller before falling back on doing the lookup, creating a new projectConsultantCacheObj with the results, seeding the cache with the object and returning the object to the caller:

  1. Function getProjectConsultant(pcLookupArr() As String) As projectConsultantCacheObj
  2. key$ = Join(pcLookupAr1,"::")
  3. If Iselement(pCCache(key$)) Then 'cache hit. Yay!
  4. Set getProjectConsultant = pcCache(key$)
  5. Exit Function
  6. End If
  7. 'no cache hit, perform lookup, create new object, seed cache and return object…

A good strategy to follow is to seed the cache with Nulls for lookup keys that don’t return results so the expensive lookup doesn’t get repeated.