Esempio n. 1
0
        /// <summary>
        /// Adds an entry to the map.
        /// Note that the new <paramref name="value"/> will be merged with existing values
        /// on other nodes and the outcome depends on what <see cref="IReplicatedData"/>
        /// type that is used.
        ///
        /// Consider using <see cref="AddOrUpdate(Akka.Cluster.Cluster, TKey, TValue, Func{TValue, TValue})">AddOrUpdate</see> instead of <see cref="SetItem(UniqueAddress,TKey,TValue)"/> if you want modify
        /// existing entry.
        ///
        /// <see cref="ArgumentException"/> is thrown if you try to replace an existing <see cref="ORSet{T}"/>
        /// value, because important history can be lost when replacing the `ORSet` and
        /// undesired effects of merging will occur. Use <see cref="ORMultiValueDictionary{TKey,TValue}"/> or <see cref="AddOrUpdate(Akka.Cluster.Cluster, TKey, TValue, Func{TValue, TValue})">AddOrUpdate</see> instead.
        /// </summary>
        public ORDictionary <TKey, TValue> SetItem(UniqueAddress node, TKey key, TValue value)
        {
            if (value is IORSet && ValueMap.ContainsKey(key))
            {
                throw new ArgumentException("ORDictionary.SetItems may not be used to replace an existing ORSet", nameof(value));
            }

            var newKeys = KeySet.ResetDelta().Add(node, key);
            var delta   = new PutDeltaOperation(newKeys.Delta, key, value);

            // put forcibly damages history, so we propagate full value that will overwrite previous values
            return(new ORDictionary <TKey, TValue>(newKeys, ValueMap.SetItem(key, value), NewDelta(delta)));
        }
Esempio n. 2
0
        internal ORDictionary <TKey, TValue> AddOrUpdate(UniqueAddress node, TKey key, TValue initial, bool valueDeltas,
                                                         Func <TValue, TValue> modify)
        {
            bool hasOldValue;

            if (!ValueMap.TryGetValue(key, out var oldValue))
            {
                oldValue    = initial;
                hasOldValue = false;
            }
            else
            {
                hasOldValue = true;
            }

            // Optimization: for some types - like GSet, GCounter, PNCounter and ORSet  - that are delta based
            // we can emit (and later merge) their deltas instead of full updates.
            // However to avoid necessity of tombstones, the derived map type needs to support this
            // with clearing the value (e.g. removing all elements if value is a set)
            // before removing the key - like e.g. ORMultiMap does
            var newKeys = KeySet.ResetDelta().Add(node, key);

            if (valueDeltas && oldValue is IDeltaReplicatedData deltaOldValue)
            {
                var newValue      = modify((TValue)deltaOldValue.ResetDelta());
                var newValueDelta = ((IDeltaReplicatedData)newValue).Delta;
                if (newValueDelta != null && hasOldValue)
                {
                    var op = new UpdateDeltaOperation(newKeys.Delta, ImmutableDictionary.CreateRange(new[] { new KeyValuePair <TKey, IReplicatedData>(key, newValueDelta) }));
                    return(new ORDictionary <TKey, TValue>(newKeys, ValueMap.SetItem(key, newValue), NewDelta(op)));
                }
                else
                {
                    var op = new PutDeltaOperation(newKeys.Delta, key, newValue);
                    return(new ORDictionary <TKey, TValue>(newKeys, ValueMap.SetItem(key, newValue), NewDelta(op)));
                }
            }
            else
            {
                var newValue = modify(oldValue);
                var delta    = new PutDeltaOperation(newKeys.Delta, key, newValue);
                return(new ORDictionary <TKey, TValue>(newKeys, ValueMap.SetItem(key, newValue), NewDelta(delta)));
            }
        }