Overview
We often need to cache some data during any implementation. If you are creating a C component, that may take form of a "static" variable. You could sometimes use "session variables" - if intended scope is a transaction. You could also employ "Environment Variables".
RedPrairie software itself utilizes caching in several algorithms. Most of the implementations use C static variables. This path is fine but requires a lot of housekeeping code and also prone to bugs - especially memory leaks.
As of 2011, MOCA has introduced external caching. One such caching provider that MOCA supports is "infinispan".
Possibilities
This opens up some very interesting possibilities. In this blog, I will describe a solution that we incorporate in almost all of our implementations, i.e. we cache results of an arbitrary MOCA command such that if the same command is called again - it simply returns data from the cache. The solution is quite simple - thanks to the wonderful concepts implemented in MOCA.
MOCA Command "execute ossi moca and cache"
Whenever we need to call a command whose result can be cached, we execute it via this interface. It is similar to the "execute server command" MOCA command - but the difference is that the results can be cached and if called again, it will return data from the cache.
It has following input parameters:
Argument | Description | Comments |
uc_moca_cmd | This is the exact command that needs to be executed | Similar to what you will pass to execute server command |
uc_inline | Should the command have access to stack variables? | Similar to "inline" parameter of execute server command |
uc_cache_key | The results of the execution will be saved in cache with this key | This will include some key data for the execution so that it can be looked up again. You could default it to MOCA command itself but that will not work very well for inline contexts. Most of the time you can come up with primary key of this cache node. For example policy table primary key or area key etc. |
uc_cache_grp | The cache can be made up of several groups | For example policy caches can be placed in one group, areas in another |
While such caching is often very useful in production environments - it can be a pain in development environment where we are frequently changing the data that is cached. That is why it is a good idea to support an environment variable to disable caching. When the caching is disabled - this behaves exactly like "execute server command". A sample implementation may be as follows:
publish data where uc_inhibit_ossi_cache = @@UC_INHIBIT_OSSI_CACHE | if ( @uc_inhibit_ossi_cache = '1' ) execute server command where cmd = @uc_moca_cmd and inline = @uc_inline else execute ossi moca and cache core
MOCA Command "execute ossi moca and cache core"
This is the main command that utilizes the caching functionality in MOCA. It works off the same input as the above command. It first looks up the the cache for the passed in key. If found it returns the complete result set from the cache. If not found - it will execute the command, put the result set in cache and then return the data. A sample implementation may be as follows:
publish data where uc_my_infispan_cache = nvl(@uc_cache_grp, 'OSSI__MISC' ) and uc_my_inline = string ( nvl(@uc_inline,0) ) | { [[ import com.redprairie.moca.cache.*; import com.redprairie.moca.cache.infinispan.*; //
// This creates the cache. Each cache group becomes a different cache.
// MocaCachecache = CacheManager.getCache(uc_my_infispan_cache,
new InfinispanCacheProvider(), null, null); // // First get the cache_key from the cache. We always put the full resultset in cache
// so the get is expected to return that. // my_rs = cache.get ( uc_cache_key );
//
// If we do not find resultset in cache - then we execute the command (inline or not)
// after executing, we put the whole result set in cache
// if ( my_rs == null ) { if ( uc_my_inline == "1" ) my_rs = moca.executeInline ( uc_moca_cmd ) else my_rs = moca.executeCommand ( uc_moca_cmd ) // cache.put ( uc_cache_key, my_rs ); }
//
// If we found in cache or executed - by this time we have the resultset
// [ret:my_rs] ]] |
//
// we publish the resultset publish data combination where res = @ret }
Use Cases
This comes in quite handy. For example in complex integration projects we often have lookup tables - this improves the performance significantly in that case. Similarly data in policies, area, storage polices, pick policies, etc. is quite static and can take advantage of this capability.
In addition to this, this method makes the concept quite abstract and requires minimum housekeeping. All we need to do is construct the command and execute it. MOCA allows the whole recordset to be cached so we can thus cache complex information.
Additional Documentation
For additional features and detailed documentation, refer to "MOCA Developer Guide" chapter on "Caching"
This comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete