ScutGame / Scut

Scut is a free, open source, stable game server framework, which support C#/Python/Lua script, and support Unity3d, Cocos2dx, FlashAir client access.
1.33k stars 577 forks source link

Wrong behavior when call Reload on PersonalCacheStruct #24

Open kybird opened 7 years ago

kybird commented 7 years ago

if you call reload function on PersonalCacheStruct especially entity has ReadWriteDB property

it will re-load data from Database.

and it set value by ReadEntityProperty method in SqlDataReceiver.cs

it call entity's Property function and it fire event NotifyChange event and the value will be added to SyncQueueManager. clearly not expected behavior.

moreover the "ReadEntityProperty" function set value sequencely

each set value fire event and the "not completed setting entity' will be added;

in another word.

if you have some entity like below


[EntityTable]
class someentity
{
    [EntityField(true)]
    public long userID {get;set}

    [EntityField(true)]
    public long subkey {get;set}
}

and we have one data from database as below

UserID, subKey 1, 2

now call

PersonalCacheStruct().Reload();

then we will have two DataSyncQueue item

1-0, 1-2

we don't need add this data to DataSyncQueue again. just waste performance

Jesse1205 commented 7 years ago

How about this link https://github.com/Jesse1205/ScutGame/commit/8cc4ab98aad0da68dc214fb7d8e0f2aab880b3fd can solve your problem?

kybird commented 7 years ago

this problem will happen when the entity have more than two key.. and you will see log like below.

EntitySync queue key Entity-1-0-0 faild object is null
EntitySync queue key Entity-1-1-0 faild object is null

here is my solution It delay Notify Event until finish setting data to Entity anyway i need to check your changes. thanks for share!!

SqlDataReceiver.cs

        private T ReadEntityProperty<T>(IDataReader reader, EntityPropertySetFunc<T> setFunc) where T :  new()
        {
            T entity = new T();

            var disableNotify = entity as EntityChangeEvent; //added
            if (disableNotify != null) disableNotify.DelayNotify(); //added
            var columns = _schema.GetColumns();
            foreach (var column in columns)
            {
                try
                {
                    object fieldValue = reader[column.Name];
                    if (setFunc != null) setFunc(entity, column, fieldValue);
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("read {0} table's {1} column error.", _schema.EntityName, column.Name), ex);
                }
            }
            if (disableNotify != null) disableNotify.TriggerNotify(); //added 
            return entity;
        }
kybird commented 7 years ago

@Jesse1205 Can you describe the problem that apply your solution?

i test original TryGetCacheItem. and its lazy anonymous delegate never executed.