< Summary

Class:DCL.CRDT.CRDTProtocol
Assembly:DCL.CRDTProtocol
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/CRDTProtocol/CRDTProtocol.cs
Covered lines:47
Uncovered lines:24
Coverable lines:71
Total lines:203
Line coverage:66.1% (47 of 71)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CRDTProtocol()0%110100%
ProcessMessage(...)0%10.557058.33%
GetState(...)0%110100%
TryGetState(...)0%330100%
GetState()0%110100%
Create(...)0%220100%
Clear()0%2100%
ClearOnUpdated()0%110100%
UpdateState(...)0%550100%
IsSameData(...)0%15.389057.14%
CompareData(...)0%72800%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/CRDTProtocol/CRDTProtocol.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3
 4namespace DCL.CRDT
 5{
 6    public class CRDTProtocol
 7    {
 1878        internal readonly List<CRDTMessage> state = new List<CRDTMessage>();
 1879        private readonly Dictionary<int, Dictionary<int, int>> stateIndexer = new Dictionary<int, Dictionary<int, int>>(
 10
 11        private bool clearOnUpdated = false;
 12
 13        public CRDTMessage ProcessMessage(CRDTMessage message)
 14        {
 4615            if (clearOnUpdated)
 16            {
 017                Clear();
 18            }
 19
 4620            TryGetState(message.key1, message.key2, out CRDTMessage storedMessage);
 21
 22            // The received message is > than our current value, update our state.
 4623            if (storedMessage == null || storedMessage.timestamp < message.timestamp)
 24            {
 3225                return UpdateState(message.key1, message.key2, message.data, message.timestamp);
 26            }
 27
 28            // Outdated Message. Resend our state message through the wire.
 1429            if (storedMessage.timestamp > message.timestamp)
 30            {
 031                return storedMessage;
 32            }
 33
 34            // Same data, same timestamp. Weirdo echo message.
 1435            if (IsSameData(storedMessage.data, message.data))
 36            {
 1437                return storedMessage;
 38            }
 39
 40            // Race condition, same timestamp diff data. Should keep stored data?
 041            if (CompareData(storedMessage.data, message.data))
 42            {
 043                return storedMessage;
 44            }
 45
 046            return UpdateState(message.key1, message.key2, message.data, message.timestamp);
 47        }
 48
 49        public CRDTMessage GetState(int key1, int key2)
 50        {
 2551            TryGetState(key1, key2, out CRDTMessage crdtMessage);
 2552            return crdtMessage;
 53        }
 54
 55        public bool TryGetState(int key1, int key2, out CRDTMessage crdtMessage)
 56        {
 10557            if (stateIndexer.TryGetValue(key1, out Dictionary<int, int> innerDictionary))
 58            {
 5159                if (innerDictionary.TryGetValue(key2, out int index))
 60                {
 2961                    crdtMessage = state[index];
 2962                    return true;
 63                }
 64            }
 7665            crdtMessage = null;
 7666            return false;
 67        }
 68
 69        public IReadOnlyList<CRDTMessage> GetState()
 70        {
 271            return state;
 72        }
 73
 74        public CRDTMessage Create(int entityId, int componentId, byte[] data)
 75        {
 3476            var result = new CRDTMessage()
 77            {
 78                key1 = entityId,
 79                key2 = componentId,
 80                data = data,
 81                timestamp = 0
 82            };
 3483            if (TryGetState(result.key1, result.key2, out CRDTMessage storedMessage))
 84            {
 185                result.timestamp = storedMessage.timestamp + 1;
 86            }
 3487            return result;
 88        }
 89
 90        public void Clear()
 91        {
 092            state.Clear();
 093            stateIndexer.Clear();
 094            clearOnUpdated = false;
 095        }
 96
 97        public void ClearOnUpdated()
 98        {
 299            clearOnUpdated = true;
 2100        }
 101
 102        private CRDTMessage UpdateState(int key1, int key2, object data, long remoteTimestamp)
 103        {
 32104            long stateTimeStamp = 0;
 32105            int crdtStateIndex = 0;
 32106            bool stateExists = false;
 107
 32108            if (stateIndexer.TryGetValue(key1, out Dictionary<int, int> innerDictionary))
 109            {
 10110                stateExists = innerDictionary.TryGetValue(key2, out crdtStateIndex);
 111            }
 112
 32113            if (stateExists)
 114            {
 4115                stateTimeStamp = state[crdtStateIndex].timestamp;
 116            }
 117
 32118            long timestamp = Math.Max(remoteTimestamp, stateTimeStamp);
 32119            var newMessageState = new CRDTMessage()
 120            {
 121                key1 = key1,
 122                key2 = key2,
 123                timestamp = timestamp,
 124                data = data
 125            };
 126
 32127            if (stateExists)
 128            {
 4129                state[crdtStateIndex] = newMessageState;
 130            }
 131            else
 132            {
 28133                state.Add(newMessageState);
 28134                int newStateIndex = state.Count - 1;
 28135                if (innerDictionary != null)
 136                {
 6137                    innerDictionary.Add(key2, newStateIndex);
 138                }
 139                else
 140                {
 22141                    stateIndexer[key1] = new Dictionary<int, int>() { { key2, newStateIndex } };
 142                }
 143            }
 144
 32145            return newMessageState;
 146        }
 147
 148        internal static bool IsSameData(object a, object b)
 149        {
 14150            if (a == b)
 151            {
 0152                return true;
 153            }
 154
 14155            if (a is byte[] bytesA && b is byte[] bytesB)
 156            {
 14157                if (bytesA.Length != bytesB.Length)
 158                {
 0159                    return false;
 160                }
 161
 56162                for (int i = 0; i < bytesA.Length; i++)
 163                {
 14164                    if (bytesA[i] != bytesB[i])
 165                    {
 0166                        return false;
 167                    }
 168                }
 14169                return true;
 170            }
 171
 0172            if (a is string strA && b is string strB)
 173            {
 0174                return String.Compare(strA, strB, StringComparison.Ordinal) == 0;
 175            }
 176
 0177            return false;
 178        }
 179
 180        private static bool CompareData(object a, object b)
 181        {
 0182            if (a == null)
 0183                return true;
 184
 0185            if (a is byte[] bytesA && b is byte[] bytesB)
 186            {
 0187                return bytesA.Length > bytesB.Length;
 188            }
 189
 0190            if (a is int numberA && b is int numberB)
 191            {
 0192                return numberA > numberB;
 193            }
 194
 0195            if (a is string strA && b is string strB)
 196            {
 0197                return String.Compare(strA, strB, StringComparison.Ordinal) > 0;
 198            }
 199
 0200            return true;
 201        }
 202    }
 203}