private void OnPacketReceived(Packet packet) { if (packet is FragmentPacket fragmentPacket) { FragmentKey key = fragmentKeyFactory.FromBytes(fragmentPacket.GetKey()); state = state.CloneWith(key, fragmentFactory.FromBytes(fragmentPacket.GetPayload())); } else if (packet is MutationPacket mutationPacket) { // If mutation was requested by me, then this request is no longer pending if (mutationPacket.GetRequester().Equals(client.id)) { pending.Remove(mutationPacket.GetId()); } if (!TryApply(mutationPacket, out Mutation mutation, out MutationResult result)) { // This should never happen since the mutation has already been succesfully applied at the Oracle. This // indicates that replication state is corrupt. This is a good reason to directly disconnect from the server. string message = "Fatal Karmax replication failure"; log.Error($"{message}. Corrupt state detected while applying {mutation.GetType().Name} on fragment[{fragmentKeyFactory.FromBytes(mutationPacket.GetKey()).AsString()}]. Reason: {result.GetFailureReason()}"); client.Leave(message); return; } } else if (packet is MutationFailedPacket mutationFailedPacket) { var mutationId = mutationFailedPacket.GetId(); log.Warning($"Mutation[{mutationId}] failed. Reason: {mutationFailedPacket.GetFailureReason()}. Details: {pending[mutationId]}"); pending.Remove(mutationId); SafeInvoker.Invoke(log, OnMutationFailedCallback, mutationId, mutationFailedPacket.GetFailureReason()); } }
protected bool TryApply(MutationPacket mutationPacket, out Mutation mutation, out MutationResult result) { FragmentKey key = fragmentKeyFactory.FromBytes(mutationPacket.GetKey()); mutation = mutationFactory.FromBytes(mutationPacket.GetPayload()); result = mutation.Mutate(state, key, mutationPacket.GetRequester()); if (result.IsFailure()) { return(false); } if (result.IsSuccess()) { bool isUpdate = state.ContainsKey(key); state = state.CloneWith(key, result.GetFragment()); if (isUpdate) { SafeInvoker.Invoke(log, OnFragmentUpdatedCallback, result.GetFragment(), state, key, mutation); } else { SafeInvoker.Invoke(log, OnFragmentInsertedCallback, result.GetFragment(), state, key, mutation); } } else if (result.IsDelete()) { if (state.ContainsKey(key)) { state = state.CloneWithout(key); SafeInvoker.Invoke(log, OnFragmentDeletedCallback, state, key, mutation); } } SafeInvoker.Invoke(log, OnStateChangedCallback, state, key, mutation); return(true); }
public Guid Request(FragmentKey key, Mutation mutation) { if (!isAttached) { throw log.ExitError(new Exception("Cannot Request the mutation of a fragment if the Karmax container is no longer attached to the Server.")); } Guid mutationId = Guid.NewGuid(); byte[] keyBytes = fragmentKeyFactory.GetBytes(key); byte[] payload = mutationFactory.GetBytes(mutation); MutationPacket mutationPacket = new MutationPacket(mutationId, containerId, keyBytes, payload); Request(mutationPacket, mutation); return(mutationId); }
internal override sealed MutationResult Mutate(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester) { MutationResult result; if (state.TryGetValue(key, out Fragment fragment)) { if (!(fragment is T fragmentT)) { log.Warning($"Can not {GetType().Name} a {typeof(T).Name} at fragment[{key.AsString()}], because that fragment is of type {fragment.GetType().Name}."); return(MutationResult.FragmentTypeMismatchFailure); } result = Update(fragmentT, state, key, requester); if (result == null) { log.Warning($"{GetType().Name}.Update returned null, which is not allowed."); return(MutationResult.ResultNullFailure); } } else { result = Insert(state, key, requester); if (result == null) { log.Warning($"{GetType().Name}.Insert returned null, which is not allowed."); return(MutationResult.ResultNullFailure); } } return(result); }
protected abstract UpdateResult <T> Update(T fragment, IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester);
protected abstract InsertResult <T> Insert(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester);
protected override UpdateResult<Counter> Update(Counter fragment, IReadOnlyDictionary<FragmentKey, Fragment> state, FragmentKey key, Guid requester) { return UpdateResult<Counter>.Success(new Counter(fragment.GetValue() * product)); }
protected abstract DeleteResult Delete(T fragment, IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey fragmentId, Guid requester);
protected override DeleteResult Delete(Counter counter, IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester) { return(DeleteResult.Delete()); }
private void OnStateChanged(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Mutation mutation) { lastStateText = string.Join("\n", state.Select(kvp => $"<b>{kvp.Key.AsString()}</b>: {kvp.Value}").Reverse()); UpdateText(); }
internal override MutationResult Mutate(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester) { if (state.ContainsKey(key)) { log.Warning($"Can not {GetType().Name} a {typeof(T).Name} at fragment[{key.AsString()}], because that fragment already exists."); return(MutationResult.FragmentAlreadyExistsFailure); } InsertResult <T> result = Insert(state, key, requester); if (result == null) { log.Warning($"{GetType()}.Insert returned null, while this is not allowed."); return(MutationResult.ResultNullFailure); } return(result); }
protected override InsertResult <Counter> Insert(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester) { return(InsertResult <Counter> .Success(new Counter(amount))); }
internal abstract MutationResult Mutate(IReadOnlyDictionary <FragmentKey, Fragment> state, FragmentKey key, Guid requester);