コード例 #1
0
        private async ValueTask UnsafeAppendAsync <TEntry>(ILogEntryProducer <TEntry> supplier, long startIndex, bool skipCommitted, CancellationToken token)
            where TEntry : notnull, IRaftLogEntry
        {
            if (startIndex > state.LastIndex + 1)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex));
            }
            Partition?partition;

            for (partition = null; !token.IsCancellationRequested && await supplier.MoveNextAsync().ConfigureAwait(false); state.LastIndex = startIndex++)
            {
                if (supplier.Current.IsSnapshot)
                {
                    throw new InvalidOperationException(ExceptionMessages.SnapshotDetected);
                }

                if (startIndex > state.CommitIndex)
                {
                    await GetOrCreatePartitionAsync(startIndex, ref partition).ConfigureAwait(false);

                    await partition.WriteAsync(sessionManager.WriteSession, supplier.Current, startIndex).ConfigureAwait(false);
                }
                else if (!skipCommitted)
                {
                    throw new InvalidOperationException(ExceptionMessages.InvalidAppendIndex);
                }
            }

            await FlushAsync(partition).ConfigureAwait(false);

            // flush updated state
            state.Flush();
            token.ThrowIfCancellationRequested();
        }
コード例 #2
0
        private async ValueTask <long> AppendAsync <TEntry>(ILogEntryProducer <TEntry> entries, long?startIndex, bool skipCommitted, CancellationToken token)
            where TEntry : IRaftLogEntry
        {
            if (startIndex is null)
            {
                startIndex = log.LongLength;
            }
            else if (startIndex > log.LongLength)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex));
            }
            IRaftLogEntry[] appendingScope;
            if (skipCommitted)
            {
                appendingScope = await ReadAllAsync(entries, token).ConfigureAwait(false);

                var skipNum = Math.Max(0, GetLastIndex(true) - startIndex.Value + 1L);
                appendingScope = appendingScope.RemoveFirst(skipNum);
                startIndex    += skipNum;
            }
            else if (startIndex <= GetLastIndex(true))
            {
                throw new InvalidOperationException(ExceptionMessages.InvalidAppendIndex);
            }
            else
            {
                appendingScope = await ReadAllAsync(entries, token).ConfigureAwait(false);
            }
            Append(appendingScope, startIndex.Value);
            return(startIndex.Value);
        }
コード例 #3
0
 /// <inheritdoc/>
 async ValueTask <long> IAuditTrail <IRaftLogEntry> .AppendAsync <TEntry>(ILogEntryProducer <TEntry> entries, CancellationToken token)
 {
     if (entries.RemainingCount == 0L)
     {
         throw new ArgumentException(ExceptionMessages.EntrySetIsEmpty);
     }
     using (await syncRoot.AcquireWriteLockAsync(token).ConfigureAwait(false))
         return(await AppendAsync(entries, null, false, token).ConfigureAwait(false));
 }
コード例 #4
0
 /// <inheritdoc/>
 async ValueTask IAuditTrail <IRaftLogEntry> .AppendAsync <TEntryImpl>(ILogEntryProducer <TEntryImpl> entries, long startIndex, bool skipCommitted, CancellationToken token)
 {
     if (startIndex < 0L)
     {
         throw new ArgumentOutOfRangeException(nameof(startIndex));
     }
     using (await syncRoot.AcquireWriteLockAsync(token).ConfigureAwait(false))
         await AppendAsync(entries, startIndex, skipCommitted, token).ConfigureAwait(false);
 }
コード例 #5
0
 async ValueTask IAuditTrail <IRaftLogEntry> .AppendAsync <TEntry>(ILogEntryProducer <TEntry> entries, long startIndex, bool skipCommitted, CancellationToken token)
 {
     if (entries.RemainingCount == 0L)
     {
         return;
     }
     using (await syncRoot.AcquireWriteLockAsync(CancellationToken.None).ConfigureAwait(false))
         await AppendAsync(entries, startIndex, skipCommitted, token);
 }
コード例 #6
0
        private async ValueTask <long> AppendAsync <TEntryImpl>(ILogEntryProducer <TEntryImpl> entries, long?startIndex, bool skipCommitted, CancellationToken token)
            where TEntryImpl : notnull, IRaftLogEntry
        {
            long skip;

            if (startIndex is null)
            {
                startIndex = index + 1L;
            }
            else if (startIndex > index + 1L)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex));
            }
            if (skipCommitted)
            {
                skip        = Math.Max(0, commitIndex.VolatileRead() - startIndex.Value + 1L);
                startIndex += skip;
            }
            else if (startIndex <= commitIndex.VolatileRead())
            {
                throw new InvalidOperationException(ExceptionMessages.InvalidAppendIndex);
            }
            else
            {
                skip = 0L;
            }

            var count = entries.RemainingCount - skip;

            if (count > 0L)
            {
                // skip entries
                var newEntries = new long[count];
                for (; skip-- > 0; token.ThrowIfCancellationRequested())
                {
                    await entries.MoveNextAsync().ConfigureAwait(false);
                }

                // copy terms
                for (var i = 0; await entries.MoveNextAsync().ConfigureAwait(false) && i < newEntries.LongLength; i++, token.ThrowIfCancellationRequested())
                {
                    if (entries.Current.IsSnapshot)
                    {
                        throw new InvalidOperationException(ExceptionMessages.SnapshotDetected);
                    }
                    newEntries[i] = entries.Current.Term;
                }

                // now concat existing array of terms
                Append(newEntries, startIndex.Value);
            }

            return(startIndex.Value);
        }
コード例 #7
0
        private static async ValueTask <IRaftLogEntry[]> ReadAllAsync <TEntry>(ILogEntryProducer <TEntry> entries, CancellationToken token)
            where TEntry : IRaftLogEntry
        {
            var bufferedEntries = new IRaftLogEntry[entries.RemainingCount];

            for (var i = 0L; await entries.MoveNextAsync().ConfigureAwait(false); i++)
            {
                bufferedEntries[i] = entries.Current.IsReusable ?
                                     (IRaftLogEntry)entries.Current :
                                     await BufferedLogEntry.CreateBufferedEntryAsync(entries.Current, token).ConfigureAwait(false);
            }
            return(bufferedEntries);
        }
コード例 #8
0
        /// <inheritdoc/>
        async ValueTask IAuditTrail <IRaftLogEntry> .AppendAsync <TEntry>(ILogEntryProducer <TEntry> entries, long startIndex, bool skipCommitted, CancellationToken token)
        {
            if (entries.RemainingCount == 0L)
            {
                return;
            }
            await syncRoot.AcquireAsync(true, CancellationToken.None).ConfigureAwait(false);

            try
            {
                await UnsafeAppendAsync(entries, startIndex, skipCommitted, token).ConfigureAwait(false);
            }
            finally
            {
                syncRoot.Release();
            }
        }
コード例 #9
0
        Task <Result <bool> > ILocalMember.ReceiveEntriesAsync <TEntry>(EndPoint sender, long senderTerm, ILogEntryProducer <TEntry> entries, long prevLogIndex, long prevLogTerm, long commitIndex, CancellationToken token)
        {
            var member = FindMember(MatchByEndPoint, sender);

            if (member is null)
            {
                return(Task.FromResult(new Result <bool>(Term, false)));
            }

            member.Touch();
            return(ReceiveEntriesAsync(member, senderTerm, entries, prevLogIndex, prevLogTerm, commitIndex, token));
        }
コード例 #10
0
        private async Task <Result <bool> > BufferizeReceivedEntriesAsync <TEntry>(RaftClusterMember sender, long senderTerm, ILogEntryProducer <TEntry> entries, long prevLogIndex, long prevLogTerm, long commitIndex, CancellationToken token)
            where TEntry : notnull, IRaftLogEntry
        {
            Debug.Assert(bufferingOptions is not null);
            using var buffered = await BufferedRaftLogEntryList.CopyAsync(entries, bufferingOptions, token).ConfigureAwait(false);

            return(await ReceiveEntriesAsync(sender, senderTerm, buffered.ToProducer(), prevLogIndex, prevLogTerm, commitIndex, token).ConfigureAwait(false));
        }
コード例 #11
0
            async Task <Result <bool> > ILocalMember.ReceiveEntriesAsync <TEntry>(EndPoint sender, long senderTerm, ILogEntryProducer <TEntry> entries, long prevLogIndex, long prevLogTerm, long commitIndex, CancellationToken token)
            {
                Equal(42L, senderTerm);
                Equal(1, prevLogIndex);
                Equal(56L, prevLogTerm);
                Equal(10, commitIndex);
                byte[] buffer;
                switch (Behavior)
                {
                case ReceiveEntriesBehavior.ReceiveAll:
                    while (await entries.MoveNextAsync())
                    {
                        True(entries.Current.Length.HasValue);
                        buffer = await entries.Current.ToByteArrayAsync(token);

                        ReceivedEntries.Add(new BufferedEntry(entries.Current.Term, entries.Current.Timestamp, entries.Current.IsSnapshot, buffer));
                    }
                    break;

                case ReceiveEntriesBehavior.DropAll:
                    break;

                case ReceiveEntriesBehavior.ReceiveFirst:
                    True(await entries.MoveNextAsync());
                    buffer = await entries.Current.ToByteArrayAsync(token);

                    ReceivedEntries.Add(new BufferedEntry(entries.Current.Term, entries.Current.Timestamp, entries.Current.IsSnapshot, buffer));
                    break;

                case ReceiveEntriesBehavior.DropFirst:
                    True(await entries.MoveNextAsync());
                    True(await entries.MoveNextAsync());
                    buffer = await entries.Current.ToByteArrayAsync(token);

                    ReceivedEntries.Add(new BufferedEntry(entries.Current.Term, entries.Current.Timestamp, entries.Current.IsSnapshot, buffer));
                    break;
                }

                return(new Result <bool>(43L, true));
            }