Cache - STARIONGROUP/COMET-SDK-Community-Edition GitHub Wiki
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
cacheshould be used for the development of end-user applications such as the CDP4-COMET-IME, it is not designed for server applications.
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>> cacheThe 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
Iterationin anEngineeringModelis a snapshot of the state of the design at a certain point in time. When aIterationis created all the data is copied from an existingIterationto a newIteration. All the unique identifiers of the objects in theIterationare maintained. Therefore the same object (Thing) may exist in multipleIterations with the same unique identifier. The CDP4-COMET-SDK Cache provides the capability to store data from multipleIterations of the sameEngineeringModel. To distinguish between these objects theKeyof theConcurrentDictionaryis the combination of the unique identifier of theThingand the containerIteration.
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.
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()usedictionary.Skip(0).Count() - Instead of
KeysandValuesproperties use a LINQ select like this:dictionary.Select(item => item.Key)
« COMETCommon-CE POCO — Documentation overview — CDP4Common-CE Types »