Suggestion to increase rollback performance

Posts   
 
    
Conrad
User
Posts: 37
Joined: 11-Jan-2008
# Posted on: 22-Sep-2017 01:21:13   

I am having some performance issues when calling RollbackFields on entities with large byte array properties. The cause seems to be a result of comparing each field (specifically, byte arrary fields) to determine if OnPropertyChanged should be fired. I understand that the FieldUtilities.GetNamesOfChangedFields can be slow (see http://llblgen.com/tinyforum/Messages.aspx?ThreadID=15773&HighLight=1) due to the need to run a byte by byte comparison in FieldUtilities.CheckArraysAreEqual. Could I swap out FieldUtilities.GetNamesOfChangedFields and use a very similar function that tries to short circuit the field value comparison if currentFields.Field(A) and _fields.Field(A) are both not IsDirty. or would that be dangerous? That wouldn't solve my performance issue 100% of the time, but maybe 95%.

..from EntityCore.RollbackFields(string name)...

List<string> namesOfChangedFields = FieldUtilities.GetNamesOfChangedFields(currentFields, _fields);
            foreach(string fieldName in namesOfChangedFields)
            {
                // raise a changed event. 
                OnPropertyChanged(fieldName);
            }

I am currently using version 4.2 Adapter.

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 22-Sep-2017 11:31:32   

Do you wan tot rollback to values fetched from the database, or values recently set in memory?

Conrad
User
Posts: 37
Joined: 11-Jan-2008
# Posted on: 22-Sep-2017 17:40:36   

Values recently set in memory. We are calling the rollback when you hit a Cancel button on a form. The values on the form could have been fetched from the database or may have been recently set (and snapshotted) before the rollback.

Thanks for the quick response.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 24-Sep-2017 13:44:37   

There's at the moment no way to shortcut that, other than overriding RollbackFields in a partial class of CommonEntityBase and setting the byte array fields to null before calling the base' method. that way it will be reported as changed, but the check will be very quick.

Looking at the code, it could be a bit more clever as in: it could check whether the original field had its IsChanged flag set. If both version don't have their IsChanged flag set, they can't be changed, so it can skip the check. Currently it checks the values of byte arrays and ignores the IsChanged flag so it's the worst case scenario: long arrays are compared and they're equal so it will take O(n).

We'll look into speeding this up in the future.

Frans Bouma | Lead developer LLBLGen Pro
Conrad
User
Posts: 37
Joined: 11-Jan-2008
# Posted on: 25-Sep-2017 18:33:09   

I will consider overriding RollbackFields. Thank you for looking into it.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 26-Sep-2017 12:17:36   

In v5.3 we've optimized this in 2 ways: - as we clone the array with the values, the actual byte array values are not cloned, they're referencing the same memory address, so we added an object.ReferenceEquals() check before the value comparison. This should catch the savefields/rollback fields check so in your situation it should be very fast now. - we added a byte[] optimization for when the arrays do have a different memory address, as we only had a generic Array based comparison using .GetValue() which is slow and byte[] arrays are a common type.

Frans Bouma | Lead developer LLBLGen Pro