Cache - STARIONGROUP/COMET-SDK-Community-Edition GitHub Wiki

Introduction

Caching enables storage data in memory for rapid access. When the data is accessed again, applications can get the data from the cache instead retrieving it from the original source. This improves performance and scalability. The CDP4-COMET-SDK provides a caching mechanism for the POCOs. The cache may contain the contents of the SiteDirectory and multiple EngineeringModels and Iterations. One cache is corresponds to one data-source, e.g. the CDP4-COMET Web Services or an Exchange File.

The cache should be used for the development of end-user applications such as the CDP4-COMET-IME, it is not designed for server applications.

CDP4-COMET Caching

The CDP4-COMET cache is implemented using the ConcurrentDictionary. The ConcurrentDictionary represents a thread-safe collection of key/value pairs that can be accessed by multiple threads concurrently.

ConcurrentDictionary<CacheKey, Lazy<Thing>> cache

The Key of ConcurrentDictionary is a CacheKey that encapsulates the unique identifier of a Thing and it's container Iteration in case the Thing is contained by an Iteration, the Value is a Lazy<Thing>. If the Thing is not in the containment tree of an Iteration this Iteration is set to null.

An Iteration in an EngineeringModel is a snapshot of the state of the design at a certain point in time. When a Iteration is created all the data is copied from an existing Iteration to a new Iteration. All the unique identifiers of the objects in the Iteration are maintained. Therefore the same object (Thing) may exist in multiple Iterations with the same unique identifier. The CDP4-COMET-SDK Cache provides the capability to store data from multiple Iterations of the same EngineeringModel. To distinguish between these objects the Key of the ConcurrentDictionary is the combination of the unique identifier of the Thing and the container Iteration.

Atomicity (execution protection)

An operation acting on shared memory is atomic if it completes in a single step relative to other threads. Despite being thread-safe, the code executed by delegates of AddOrUpdate and GetOrAdd methods of the ConcurrentDictionary is not subject to the atomicity of the operation. To solve that issue we use Lazy<T> types as Value of the ConcurrentDictionary. Although in this case we are using Lazy<T> mainly to ensure operation atomicity while working with the ConcurrentDictionary, deferring the creation of an object until it is first used also improves performance, avoids wasteful computation, and reduces program memory requirements.

Notes on using the ConcurrentDictionary

To maintain performance of the ConcurrentDictionary it is important to limit the use of methods that acquire all locks on the ConcurrentDictionary. The following operations in the dictionary cause it to acquire all the locks and should be avoided:

  • Count, IsEmpty properties
  • Keys, Values properties (which create a snapshot of the dictionary keys/values)
  • CopyTo (explicit ICollection implementation)
  • Clear
  • ToArray

These functionality provided by these methods can be implemented using alternative strategies:

  • Instead of dictionary.Count() use dictionary.Skip(0).Count()
  • Instead of Keys and Values properties use a LINQ select like this: dictionary.Select(item => item.Key)

« COMETCommon-CE POCO  —  Documentation overview  —  CDP4Common-CE Types »

⚠️ **GitHub.com Fallback** ⚠️