/// <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))); }
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))); } }