Some doubts about AFValue

I use one cache to store some Points's snap value which are reads from PIServer.

the cache is:

Dictionary<string, AFValue> cache = new Dictionary<string, AFValue>();

add points to cache:

List<PIPoint> plst = PIPoint.FindPIPoints(this.server, TargetTag).ToList();

foreach (var point in plst)

{

  AFValue tmp = new AFValue(new AFAttribute(point), new object(), new AFTime());

  this.cache.Add($"{point.Name}", tmp);

}

update:

this.cache[rec.Item1].Value = rec.Item3;

this.cache[rec.Item1].Timestamp = new AFTime(rec.Item2.ToLocalTime());

newValues.Add(this.cache[rec.Item1]);

 

newValues is a list and will be cleaned after UpdateValuesAsync().

Update the point's value one second and after several hours(may be 72 hours), the memory of my application grows from 60MB to 500MB.

So i want to know if the cache point's store something when i update its value and time ?

  • Hi

    Thanks for providing some code, but there are some gaps in code that leave me guessing. Note: I am not suggesting that you post all of your code.

     

    Let us look at one snippet of code:

    AFValue tmp = new AFValue(new AFAttribute(point), new object(), new AFTime());

    ONE, You are using what is called a Dynamic AFAttribute that is not associated with a BaseAFElement. There are some reasons why one would want to do this, but the only time I personally would use this is to perform UOM conversions, which PIPoints cannot do but AFAttributes can. However, to perform UOM conversions with a dynamic attribute requires declaring a SourceUOM, which means manipulating each Dynamic Attribute's ConfigString, which I do not see being done in your small shared code.

     

    TWO, the new object() creates a null object, which a PIPoint generally does not like, but that an AFAttribute can tolerate - until you try to write it to the data archive.

     

    THREE, I consider myself an experienced AF SDK developer but the line new AFTime() causes me to look up the documentation to see what is returned. Is it 1970, Now in whole seconds, or Now in subseconds? Turns out it is 1970. It would be great if we could eliminate any confusion or cause someone to go lookup what happens.

     

    Suggestions

    ONE, if you are not performing UOM conversions, there is no need to use AFAttribute. Instead, I would suggest using PIPoint directly. This may require you setting the AFValue.PIPoint property correctly. In short, this means you are developing a Tag-based application as opposed to an Asset-based one.

     

    Skipping two for THREE, to eliminate any confusion of what time is returned, I would suggest using AFTime.MinValue.

     

    TWO, rather than a null new object, I would suggest a System State which (A) makes the Data Archive happy and (B) means that the AFValue.Value will never be null. There is a way to write this directly so that anyone reading the code fully understands what you are doing by using AFValue.CreateSystemStateValue with the AFSystemStateCode of your choosing.

     

    AFValue tmp = AFValue.CreateSystemStateValue(AFSystemStateCode.PointCreated, AFTime.MinValue );
    tmp.PIPoint = point;

    The tmp AFValue is (1) associated with a PIPoint with (2) a null Attribute property, (3) a Timestamp set to 1/1/1970, (4) its Value property is not null but rather is a known System State, and (5) the IsGood property is set to false.

     

    Other considerations:

    The cache dictionary is keyed by the case-sensitive Point name. You can make this case-insensitive by

    // Or perhaps OrdinalIgnoreCase
    Dictionary<string, AFValue> cache = new Dictionary<string, AFValue>(StringComparer.CurrentCultureIgnoreCase);