public void Serialization() { var nodeOp1 = new NodeOperation( NodeOperation.OperationKind.Create, 10, "A", new ArraySegment <byte>(new byte[] { 1, 2, 3, })); var nodeOp2 = new NodeOperation( NodeOperation.OperationKind.Update, 11, "BB", new ArraySegment <byte>(new byte[] { 2, 3, 4, 5, })); var nodeOp3 = new NodeOperation( NodeOperation.OperationKind.Delete, 12, "CCC", default); var opData = NodeOperation.GetOperationData(new[] { nodeOp1, nodeOp2, nodeOp3, }); Assert.AreEqual(1, opData.Count); var ops = NodeOperation.GetNodeOperationFromBytes(opData.First()).ToArray(); Assert.AreEqual(3, ops.Length); Assert.AreEqual(NodeOperation.OperationKind.Create, ops[0].Operation); Assert.AreEqual("A", ops[0].Key); Assert.AreEqual(3, ops[0].Value.Count); Assert.AreEqual(NodeOperation.OperationKind.Update, ops[1].Operation); Assert.AreEqual("BB", ops[1].Key); Assert.AreEqual(4, ops[1].Value.Count); Assert.AreEqual(NodeOperation.OperationKind.Delete, ops[2].Operation); Assert.AreEqual("CCC", ops[2].Key); Assert.AreEqual(0, ops[2].Value.Count); Assert.IsNull(ops[2].Value.Array); Assert.IsNotNull(ops[0].ToString()); Assert.IsNotNull(ops[1].ToString()); Assert.IsNotNull(ops[2].ToString()); }
private async Task ProcessIncomingRequests() { CancellationToken cancellation = this.cancellationTokenSource.Token; var replicationTaskSem = new SemaphoreSlim(128, 128); try { while (!cancellation.IsCancellationRequested) { var ops = new List <PendingOperation>(); var op = this.pendingOperations.Take(cancellation); do { ops.Add(op); }while (this.pendingOperations.TryTake(out op)); var opData = NodeOperation.GetOperationData(ops.Select(o => o.Operation)); try { await replicationTaskSem.WaitAsync(cancellation).ConfigureAwait(false); var replicateTask = this.stateReplicator.ReplicateAsync(opData, cancellation, out long lsn); var unsed = replicateTask.ContinueWith( t => { replicationTaskSem.Release(); foreach (var operation in ops) { switch (operation.Operation.Operation) { case NodeOperation.OperationKind.Nop: // No operation, primary is telling its sequence number to secondaries. break; case NodeOperation.OperationKind.Create: case NodeOperation.OperationKind.Update: var data = new byte[operation.Operation.Value.Count]; Array.Copy(operation.Operation.Value.Array, operation.Operation.Value.Offset, data, 0, operation.Operation.Value.Count); this.kvsData.AddOrUpdate(operation.Operation.Key, operation.Operation.SequenceNumber, data); break; case NodeOperation.OperationKind.Delete: this.kvsData.TryRemove(operation.Operation.Key, operation.Operation.SequenceNumber); break; default: throw new InvalidOperationException(); } operation.OnCommit(); } }); // Writes to disk while the replication to secondaries is started. await this.operationLoggerPrimary.WriteOperations(lsn, opData); ServiceEventSource.Current.ServiceMessage(this.Context, $"Replicated and persisted on primary, SN={lsn}"); Interlocked.Exchange(ref this.lastSequenceNumber, lsn); } catch (Exception ex) when(!(ex is OperationCanceledException)) { foreach (var operation in ops) { operation.OnFailure(); } } } SpinWait.SpinUntil(() => replicationTaskSem.CurrentCount == 128); } catch (OperationCanceledException) { ServiceEventSource.Current.ServiceMessage(this.Context, "ProcessIncomingRequests operation cancelled."); } catch (Exception ex) { ServiceEventSource.Current.ServiceMessage(this.Context, "ProcessIncomingRequests unhandled exception: {0}", ex); } finally { ServiceEventSource.Current.ServiceMessage(this.Context, "ProcessIncomingRequests terminated."); } }