NCache 4.6 - Online Documentation


The data in cache can have dependency relations with items like a file on some location, a record in a database, results of a particular query or another cached item; such that any change in the item can invalidate the data in the cache. In that case, all dependent data must be reloaded or removed from cache otherwise data will become stale.
Expiration in Clustered Environment
In a clustered cache environment where multiple caching servers are involved, expiration is handled differently in various NCache topologies. In replicated cache, expiration is performed by coordinator node and operation will be then synchronized to other clustered nodes. In partitioned cache, as data is distributed on separate nodes, each node is responsible for its own items expiration. For partitioned-replica topology, expiration will be performed on active nodes and propagate to their respective replicas. Similarly in mirror active node will perform expiration and synchronies it on passive node.
Key Dependency
There are situations when it is important to maintain a relationship among the related cache data. For example, if item B depends on item A, item B has to be removed if  A no longer exists in cache. Here, key dependency can be used to maintain the relationship.
Key dependency creates a dependency relationship between cached items. For example, a key dependency can be specified on customer's data while putting his order's data. In this way, if customer is removed by the application or expired, then NCache will remove the order data too.
In NCache, the dependent items and the cache items on which they depend upon, both are aware of this relationship. So when an item on which other items depend is removed either by the application or by expiration, all the dependent items will also be removed. However vice versa is not possible i.e. on removal of an item, say Y, which has dependency on any other item, say on item X, the item X will not be removed. 
A cache item can have dependency on any number of other items in the cache. For example, an item A may depends on item X, Y and Z.  Similarly an item to which other depend upon can also depend on other cache item i.e. item X may depend on Y while items A and B depends on X. In short cascaded dependencies are allowed to nth level e.g. an item A depends on item B and B depends on item C then removal of C will result in removal of B and then C. 
Cyclic key dependency is not supported i.e. Item A depends on Item B and B depends on A. Or A depends on B and B depends on C and in turn C depends on A.
Cache Synchronization Dependency
Cache  synchronization dependency is provided by NCache to synchronize two separate caches; so that an item updated or removed from one cache have the same effect on the synchronized cache. For example, you can have a local cache that keeps the items frequently being used by your application and a clustered cache that keeps a larger number of items being shared with other applications. Let’s say this local cache is synchronized with the clustered cache to improve performance and avoid data integrity issues. Cache synchronization dependency synchronizes these two caches using item level notifications provided by NCache. Whenever an item is updated or removed from one cache, a key based notification is fired to the other cache in order to synchronize data in both caches.
Notification Based Database Dependencies
Nowadays, most of the applications that heavily use database calls are incorporating distributed caching to the cache-expensive query result set, which helps to boost application performance and scalability. For this purpose, you would like that whenever any data changes occur in the database, cache data should be invalidated and removed from the cache. NCache provides a mechanism where data can be invalidated when changes occur in the database in real time. To cater to this problem, notification based database dependencies are provided in NCache.
How It Works: In this type of database dependency, NCache uses data change notifications provided by databases servers to invalidate cache data. SQL server(2005 and 2008) and Oracle (10g or later) provide an event notification mechanism where the distributed cache like NCache can register itself for change notification through SqlDependency/OracleDependency. NCache receives notifications from database whenever underlying data changes occurs in the database. This allows NCache to immediately invalidate or reload the corresponding cached item and this keeps the cache always synchronized with the database.
Database Dependency Using SQL Server
NCache provides SqlCacheDependency for notification based dependency with SQL Server database. Internally NCache use SqlDependency provided by .NET framework to register data change notifications with SQL Server. Hence the limitations and working mechanism of SqlDependency while using this dependency needs to be understood. For example, a limited set of queries can be registered with SqlDependency. See Special Considerations Using Query Notifications and SqlDependency class for more detail.
Database Dependency Using Oracle
Similarly NCache provides OracleCacheDependency for notification based dependencies with Oracle. Internally NCache use OracleDependency to register data change notifications with Oracle database server. Hence the limitations and working mechanism of OracleDependency while using this dependency need to be understood. For example, a limited set of queries can be registered with OracleDependency. See Special Considerations Using Query Notifications and OracleDependency class for more detail.
Notification based dependency is the best option while using queries with comparatively less data changes or when a large amount of data dependencies are not involved. As notification based dependencies involve notifications to invalidate data so it can be very intensive in term of resource usage at database end. It should be carefully selected in case of creating large amounts of data dependencies as database servers need to monitor each dependency separately to track any data changes related to it. This may consume a lot of resources and hence put burden on the database servers in terms of memory and processing.
Also, database servers mostly fire separate events for each data change and NCache responds to these events accordingly.  Large amounts of these events can easily overwhelm the network traffic and the overall performance of client application and NCache servers.
To avoid this, other options like polling based database dependency provided by NCache or writing a CLR/Java procedure that communicates with NCache to invalidate cache items can be used. For this, a CLR/Java stored procedure needs to be created that connects with NCache and updates or invalidates the cached item. This procedure can be invoked on update or delete trigger of the table. In this way, data changes can be monitored and can be directly replicated to cache. This approach is more efficient as data base server do not need to monitor data changes by creating data structures related to SqlCacheDependency. And, it also does not fire .NET events to NCache. Instead, it open up an NCache client connection and directly tells NCache whether to invalidate a cached item or reload it. And, this connection with NCache is highly optimized and much faster and lighter than .NET events.
Polling Based Database Dependencies
NCache supports another database dependency called Polling Based Dependency which is basically designed to work on large scale. Notification Based Dependency only works with the database server which provides support for data change notifications i.e. either with SQL Server(2005 or above) or Oracle (10g or later). Whereas Polling Based Dependency also works with other databases which do not provide data change notifications support. Also, Notification Based Dependency is not as much resource efficient as Polling Based Dependency for using it on large scale.
In Polling Based Dependency, a table named ncache_db_sync needs to be created in database which is used by NCache to synchronize the database with cache store. Also, UPDATE and DELETE triggers need to be created for every table on which notification is required. These triggers will be scripted to invalidate corresponding cache keys in this table in case of data change.
When an item is added to the cache with dependency, a row will be created in this table for this cache key as shown:
In case of data change in table, corresponding triggers will set modified flag to true. On Cache clean up interval, NCache polls ncache_db_sync table for modified keys, collects them, sets their work in progress flag to true and finally removes all corresponding keys from cache. After successfully removing keys from cache, all those rows where work_in_progress flag is set to true are removed from the ncache_db_sync table.
In a clustered cache, if a node crashes while it was removing items from the cache, the next node in the cluster will again start the process.
File Dependency
NCache supports Database dependencies (explained later on in this chapter) to invalidate cache data when data changes occur in relational database management systems (RDBMS). On the other hand, file dependency provides a mechanism to invalidate the cache data in case of non-relational data sources. 
Here you can associate a file/folder dependency with a cache item. Whenever that file/folder is removed or modified, NCache will remove its dependent item from cache. Cache clean up (expiration) thread monitor the dependent file/folder for any change at every Clean Interval.
On cache clean up interval NCache will triggers dependency in the following scenarios:
  • Dependency file/folder is removed/modified.
  • Dependency file is replaced with directory and vice versa.
  • Dependency is created on nonexistent file/folder, but on clean up interval it is created.
Similarly multiple items can depend on a single file. Any change in file either by updating file or deletion causes cache to remove the dependent items from the cache. Also an item can create dependency on multiple files in file dependency.
A delay called "start after" can be mentioned in file dependency which indicates when to start monitoring the dependent file for any change. In this way NCache will start checking the dependant file after the "start after" time elapsed.
Custom Dependency
NCache provides flexible ways to determine data invalidation using various dependencies. However the users can implement their own custom logic for dependency if none of the built in invalidation strategy suits their environment. For example, a custom dependency can be implemented which makes call to a web service for the validation of data.
In custom dependency, a custom logic can be defined which specifies when a certain data becomes invalid. For this purpose, NCache provides an abstract class ExtensibleDependency. To write a custom logic, you need to inherit the custom dependency class from this class and override its HasChanged property. Like expiration, cache clean up thread periodically calls HasChanged property of custom dependency and if it returns true, item is removed from the cache.
Aggregate Cache Dependency
NCache also allows using different strategies in combination with the same cache data in the form of Aggregate Cache Dependency. Aggregate Cache Dependency allows associating multiple dependencies of different types with a single cached item. For example, a key dependency and file dependency can be associated with an item using aggregate dependency and data will be invalidated which ever dependency triggers first.
Aggregate Cache Dependency associates one cached item with a collection of dependency objects which can be any other dependency provided by NCache e.g. CacheDependency, DBCacheDependency or any combination of these. The AggregateCacheDependency monitors a collection of dependency objects so that when any of them changes, the cached object becomes obsolete and is removed from the cache.
Combining different invalidation strategies provides you more flexible ways to meet your application needs in different environments.
See Also