AFDataCache Class
- Last UpdatedNov 18, 2025
- 13 minute read
- PI System
- AF SDK 2024 R2
- Developer

Inheritance Hierarchy
OSIsoft.AF.DataAFDataCache
Namespace: OSIsoft.AF.Data
Assembly: OSIsoft.AFSDK (in OSIsoft.AFSDK.dll) Version: 3.1.1.1182
Syntax
public sealed class AFDataCache : IDisposable, IAFDataProvider
Public NotInheritable Class AFDataCache Implements IDisposable, IAFDataProvider Dim instance As AFDataCache
public ref class AFDataCache sealed : IDisposable, IAFDataProvider
[<SealedAttribute>] type AFDataCache = class interface IDisposable interface IAFDataProvider end
The AFDataCache type exposes the following members.
Constructors
| Name | Description | |
|---|---|---|
| AFDataCache |
Create new instance of AFDataCache.
| |
| AFDataCache(Int32) |
Create new instance of AFDataCache with a initial capacity set.
|
Properties
| Name | Description | |
|---|---|---|
| Attributes |
The list of AFAttribute items being cached.c
| |
| CacheHitCount |
Returns the total number of data calls that retrieved data from the cache since the counter was reset.
| |
| CacheTimeSpan |
The minimum amount of time series data to be kept for each AFAttribute in the cache, as measured by time span.
| |
| DataPipeStatistics |
Contains statistics for the most recent signup or event scan for attributes updated by data pipe.
| |
| EventHorizonMode |
EventHorizonMode specifies what events are returned by the datapipe at the GetUpdateEvent call based on the timestamp of the events.
| |
| EventHorizonOffset |
EventHorizonOffset allows the pipe to return events in the future. The pipe would fetch events with timestamps
up to current time + EventHorizonOffset when calling the GetUpdateEvents/GetObserverEvents methods
| |
| EventsCached |
The total number of events currently in the cache.
| |
| EventsProcessed |
The total number of events that have passed through the cache since the counter was reset.
| |
| IsSuspendedSignupEnabled |
If IsSuspendedSignupEnabled is set, the data pipe will suspend signups that are currently invalid but might become valid with changes outside of AF.
| |
| MaxCacheEventsPerAttribute |
The maximum number of cache events to be kept for each AFAttribute in the cache.
| |
| MinCacheEventsPerAttribute |
The minimum number of cache events to be kept for each AFAttribute in the cache.
| |
| MissedHitCount |
The total number of data calls that did not get data from the cache.
| |
| PIServers |
Methods
| Name | Description | |
|---|---|---|
| Add |
Adds a list of AFAttribute objects to be managed by AFDataCache. The AFAttributes are
reference counted. Adding AFAttribute that is already in the AFDataCache will increment the reference count and not
generate error. Adding the same AFAttribute multiple times will require the same number of Remove call to actually
remove the AFAttribute from the AFDataCache.
| |
| Dispose |
Release all the resources associated with this AFDataCache, including the AFDataPipe
used to populate the cached data.
| |
| Equals | Determines whether the specified object is equal to the current object. (Inherited from Object.) | |
| GetDataPipeItemsByPIServer |
Get the list of the AFAttribute objects managed by AFDataCache with
DataPipe that get data from the passed PIServer.
| |
| GetHashCode | Serves as the default hash function. (Inherited from Object.) | |
| GetItemUpdateOption | ||
| GetRelatedAttributes |
For each AFChangeInfo, finds the subscribed AFAttributes that might be impacted by the change.
| |
| GetType | Gets the Type of the current instance. (Inherited from Object.) | |
| ObservePendingChanges |
Observes a set of changes from the server and prepares to update the AFDataPipe to reflect them.
| |
| ProcessAppliedChanges |
Updates the AFDataPipe to reflect previously observed changes.
| |
| Remove |
Remove a list of AFAttribute objects from the data cache.
| |
| ResetCounters |
Reset AFDataCache statistic counters.
| |
| Subscribe |
Register an IObserver to receive AFDataPipeEvents that are a result of the internal
AFDataPipe used within the data cache for auto-monitored attributes.
| |
| ToString | Returns a string that represents the current object. (Inherited from Object.) | |
| TrimData(AFAttribute, AFTime) |
Trims any cached data for the AFAttribute at or before the specified AFTime.
| |
| TrimData(AFAttribute, AFTime, Int32) |
Trims cached data for the AFAttribute while maintaining coverage for events from a specified time.
| |
| TryGetItem |
Returns the cache enabled AFData object for a given AFAttribute.
| |
| UpdateData |
Update the time series cache for the attributes managed by this AFDataCache.
| |
| UpdateData(Boolean) |
Update the time series cache for the attributes managed by this AFDataCache.
| |
| UpdateData(AFTime) |
Update the time series cache for the attributes managed by this AFDataCache.
| |
| UpdateData(AFTime, Boolean) |
Update the time series cache for the attributes managed by this AFDataCache.
| |
| WriteToCache(AFAttribute, IListAFValue) |
Initialize the data cache of the AFAttribute with passed values. The AFAttribute
must already be added to the AFDataCache with Manual
or ManualRange.
| |
| WriteToCache(AFValue, AFUpdateOption) |
Writes value to the data cache. The AFAttribute property of the passed AFValue is the key
to lookup the data cache. This AFAttribute must already be added to the
AFDataCache with Manual or ManualRange.
|
Remarks
An AFDataCache manages a collection of AFAttributes via cache enabled AFData objects. To enable run time event caching for a list of AFAttributes, call the Add method and passed the list of AFAttributes. AFDataCache will generate and return the corresponding list of cached enabled AFData. Be default, AFDataCache uses AFDataPipe to populate the run time events in the cache. As a result, AFAttributes monitored by the AFDataCache must support AFDataPipe. The use of AFDataPipe to populate the cache can be turned off at the time of adding the AFAttribute using Manual or ManualRange. See the Add(IListAFAttribute, AFDataCacheUpdateOption) method for details.
AFDataCache will trim the cached events based on both event count and timespan. Trimming is done when the application calls the UpdateData Overload method to update the cache. Just like AFDataPipe, AFDataCache does not poll the data automatically in the background. This allows an application to have complete control over when and which thread will be used, making synchronization across threads simpler.
Single event data access queries made with the cache enabled AFData are much faster. For data access queries not supporting data cache or if the requested range exceeds the amount on data in cache, the data cache will make the normal data access query so no functionality is lost. Hence, AFDataCache is ideal for high performance applications working with streaming data while maintaining the functionality of the Rich Data Access through AFData.
Note that only data access queries made against the cached enabled AFData objects get the benefit of the cache. The cached enabled AFData objects are returned when application calls the Add(IListAFAttribute, AFDataCacheUpdateOption) or TryGetItem(AFAttribute, AFData)method of the AFDataCache. The AFData object obtained from Data is not cached enabled.
For data sources such as the PI Data Archive, where data could be compressed, it is possible for the AFDataCache to have higher resolution data (more events within the same time range) than a direct data access call to the source.
Examples
// This example demonstrates how to create an AFDataPipe // and how to use it to get new events for an attribute // Get the Database PISystems myPISystems = new PISystems(); PISystem myPISystem = myPISystems.DefaultPISystem; AFDatabase myDB = myPISystem.Databases.DefaultDatabase; AFValue inputValue1; AFValue inputValue2; long numEventsCached0 = 0; long numEventsProcessed0 = 0; long numEventsCached1 = 0; long numEventsProcessed1 = 0; long numEventsCached2 = 0; long numEventsProcessed2 = 0; long numHitCount = 0; long numMissedHitCount = 0; // Create an Element with some attributes AFElement myElement = myDB.Elements.Add("MyElement*"); AFAttribute myAttribute1 = myElement.Attributes.Add("MyAttribute1"); AFAttribute myAttribute2 = myElement.Attributes.Add("MyAttribute2"); // Create PIPoints to Update PIServer piServer = PIServers.GetPIServers().DefaultPIServer; PIPoint point; if (!PIPoint.TryFindPIPoint(piServer, "testfloat1", out point)) { point = piServer.CreatePIPoint("testfloat1", null); } if (!PIPoint.TryFindPIPoint(piServer, "testfloat2", out point)) { point = piServer.CreatePIPoint("testfloat2", null); } myAttribute1.DefaultUOM = myPISystem.UOMDatabase.UOMs["kelvin"]; myAttribute1.DataReferencePlugIn = AFDataReference.GetPIPointDataReference(myPISystem); myAttribute1.ConfigString = @"\\%Server%\testfloat1;ReadOnly=false"; myAttribute2.DefaultUOM = myPISystem.UOMDatabase.UOMs["kelvin"]; myAttribute2.DataReferencePlugIn = AFDataReference.GetPIPointDataReference(myPISystem); myAttribute2.ConfigString = @"\\%Server%\testfloat2;ReadOnly=false"; // Send some values to tags to initialize them for (int i = 1; i <= 2; i++) { AFTime tmptime = new AFTime("*"); inputValue1 = new AFValue(5 * i, tmptime); inputValue2 = new AFValue(10 * i, tmptime); myAttribute1.SetValue(inputValue1); myAttribute2.SetValue(inputValue2); Thread.Sleep(1000); } // Sleep for a minute Thread.Sleep(60000); // Create data cache object and sign up the attributes for the cache AFDataCache myAFDataCache = new AFDataCache(1000); AFKeyedResults<AFAttribute, AFData> addResult = myAFDataCache.Add(myElement.Attributes); numEventsCached0 = myAFDataCache.EventsCached; numEventsProcessed0 = myAFDataCache.EventsProcessed; // Cache only last minute worth of data myAFDataCache.CacheTimeSpan = new TimeSpan(0, 1, 0); // Send values to tags for (int i = 1; i <= 10; i++) { AFTime tmptime = new AFTime("*"); inputValue1 = new AFValue(5 * i, tmptime); inputValue2 = new AFValue(10 * i, tmptime); myAttribute1.SetValue(inputValue1); myAttribute2.SetValue(inputValue2); Thread.Sleep(1000); } // Get data for cache // Sleep a little to make sure all events get through update manager Thread.Sleep(100); myAFDataCache.UpdateData(); numEventsCached1 = myAFDataCache.EventsCached; numEventsProcessed1 = myAFDataCache.EventsProcessed; // Sleep for a minute Thread.Sleep(60000); // Send values to tags after a minute so that these events replace the old ones for (int i = 1; i <= 10; i++) { AFTime tmptime = new AFTime("*"); inputValue1 = new AFValue(5 * i, tmptime); inputValue2 = new AFValue(10 * i, tmptime); myAttribute1.SetValue(inputValue1); myAttribute2.SetValue(inputValue2); Thread.Sleep(1000); } // Get data for cache Thread.Sleep(100); myAFDataCache.UpdateData(); numEventsCached2 = myAFDataCache.EventsCached; numEventsProcessed2 = myAFDataCache.EventsProcessed; int numInterpolatedCalls = 100; if (!addResult.HasErrors) { AFData tmpData1 = myAttribute1.Data; AFTime tmpTime = new AFTime("*-30s"); // Call made to regular Data object so therefore cache not used for (int i = 0; i < numInterpolatedCalls; i++) tmpData1.InterpolatedValue(tmpTime, null); AFData tmpData2 = addResult[myAttribute1]; // Call made to cache Data object so cache is used for (int i = 0; i < numInterpolatedCalls; i++) tmpData2.InterpolatedValue(tmpTime, null); numHitCount = myAFDataCache.CacheHitCount; // Call made to a time period not covered by the cache and therefore missed hit count should increment by numInterpolatedCalls AFTime tmpTimediff = new AFTime(addResult[myAttribute1].CacheStartTime.UtcSeconds - 2); for (int i = 0; i < numInterpolatedCalls; i++) tmpData2.InterpolatedValue(tmpTimediff , null); numMissedHitCount = myAFDataCache.MissedHitCount; }
' This example demonstrates how to create the DataReference configuration ' for all attributes with a PIPoint DataReference. ' Get the Database Dim myPISystems As New PISystems Dim myPISystem As PISystem = myPISystems.DefaultPISystem Dim myDB As AFDatabase = myPISystem.Databases.DefaultDatabase Dim inputValue1 As AFValue Dim inputValue2 As AFValue Dim numEventsCached0 As Long = 0 Dim numEventsProcessed0 As Long = 0 Dim numEventsCached1 As Long = 0 Dim numEventsProcessed1 As Long = 0 Dim numEventsCached2 As Long = 0 Dim numEventsProcessed2 As Long = 0 Dim numHitCount As Long = 0 Dim numMissedHitCount As Long = 0 ' Create an Element with an Attribute Dim myElement As AFElement = myDB.Elements.Add("MyElement*") Dim myAttribute1 As AFAttribute = myElement.Attributes.Add("MyAttribute1") Dim myAttribute2 As AFAttribute = myElement.Attributes.Add("MyAttribute2") ' Create PIPoints to Update Dim piServer As PIServer = PIServers.GetPIServers().DefaultPIServer Dim point As PIPoint = Nothing If (Not PIPoint.TryFindPIPoint(piServer, "testfloat1", point)) Then point = piServer.CreatePIPoint("testfloat1", Nothing) End If If (Not PIPoint.TryFindPIPoint(piServer, "testfloat2", point)) Then point = piServer.CreatePIPoint("testfloat2", Nothing) End If myAttribute1.DefaultUOM = myPISystem.UOMDatabase.UOMs("kelvin") myAttribute1.DataReferencePlugIn = AFDataReference.GetPIPointDataReference(myPISystem) myAttribute1.ConfigString = "\\%Server%\testfloat1;ReadOnly=false" myAttribute2.DefaultUOM = myPISystem.UOMDatabase.UOMs("kelvin") myAttribute2.DataReferencePlugIn = AFDataReference.GetPIPointDataReference(myPISystem) myAttribute2.ConfigString = "\\%Server%\testfloat2;ReadOnly=false" ' Send some values to tags to initialize them For i As Integer = 1 To 2 Step 1 Dim tmptime As AFTime = New AFTime("*") inputValue1 = New AFValue(5 * i, tmptime) inputValue2 = New AFValue(10 * i, tmptime) myAttribute1.SetValue(inputValue1) myAttribute2.SetValue(inputValue2) Thread.Sleep(1000) Next ' Sleep for a minute Thread.Sleep(60000) ' Create data cache object and sign up the attributes for the cache Dim myAFDataCache As AFDataCache = New AFDataCache(1000) Dim addResult As AFKeyedResults(Of AFAttribute, AFData) = myAFDataCache.Add(myElement.Attributes) numEventsCached0 = myAFDataCache.EventsCached numEventsProcessed0 = myAFDataCache.EventsProcessed 'Cache only last minute worth of data myAFDataCache.CacheTimeSpan = New TimeSpan(0, 1, 0) ' Send values to tags For i As Integer = 1 To 10 Step 1 Dim tmptime As AFTime = New AFTime("*") inputValue1 = New AFValue(5 * i, tmptime) inputValue2 = New AFValue(10 * i, tmptime) myAttribute1.SetValue(inputValue1) myAttribute2.SetValue(inputValue2) Thread.Sleep(1000) Next ' Get data for cache ' Sleep a little to make sure all events get through update manager Thread.Sleep(100) myAFDataCache.UpdateData() numEventsCached1 = myAFDataCache.EventsCached numEventsProcessed1 = myAFDataCache.EventsProcessed ' Sleep for a minute Thread.Sleep(60000) ' Send values to tags after a minute so that these events replace the old ones For i As Integer = 1 To 10 Step 1 Dim tmptime As AFTime = New AFTime("*") inputValue1 = New AFValue(5 * i, tmptime) inputValue2 = New AFValue(10 * i, tmptime) myAttribute1.SetValue(inputValue1) myAttribute2.SetValue(inputValue2) Thread.Sleep(1000) Next ' Get data for cache Thread.Sleep(100) myAFDataCache.UpdateData() numEventsCached2 = myAFDataCache.EventsCached numEventsProcessed2 = myAFDataCache.EventsProcessed Dim numInterpolatedCalls As Integer = 100 If (Not addResult.HasErrors) Then Dim tmpData1 As AFData = myAttribute1.Data Dim tmpTime As AFTime = New AFTime("*-30s") ' Call made to regular Data object so therefore cache not used For i As Integer = 1 To numInterpolatedCalls Step 1 tmpData1.InterpolatedValue(tmpTime, Nothing) Next i Dim tmpData2 As AFData = addResult(myAttribute1) ' Call made to cache Data object so cache is used For i As Integer = 1 To numInterpolatedCalls Step 1 tmpData2.InterpolatedValue(tmpTime, Nothing) Next i numHitCount = myAFDataCache.CacheHitCount ' Call made to a time period not covered by the cache and therefore missed hit count should increment by numInterpolatedCalls Dim tmpTimediff As AFTime = New AFTime(addResult(myAttribute1).CacheStartTime.UtcSeconds - 2) For i As Integer = 1 To numInterpolatedCalls Step 1 tmpData2.InterpolatedValue(tmpTimediff, Nothing) Next i numMissedHitCount = myAFDataCache.MissedHitCount End If
No code example is currently available or this language may not be supported.
No code example is currently available or this language may not be supported.