예제 #1
0
        private static async ValueTask <long> SlowEnqueueAsync(FasterLog @this, IReadOnlySpanBatch readOnlySpanBatch, CancellationToken token)
        {
            long logicalAddress;

            while (true)
            {
                var task = @this.CommitTask;
                if (@this.TryEnqueue(readOnlySpanBatch, out logicalAddress))
                {
                    break;
                }
                if (@this.NeedToWait(@this.CommittedUntilAddress, @this.TailAddress))
                {
                    // Wait for *some* commit - failure can be ignored except if the token was signaled (which the caller should handle correctly)
                    try
                    {
                        await task.WithCancellationAsync(token);
                    }
                    catch when(!token.IsCancellationRequested)
                    {
                    }
                }
            }

            return(logicalAddress);
        }
예제 #2
0
        /// <summary>
        /// Append batch of entries to log (async) - completes after batch is committed to storage.
        /// Does NOT itself issue flush!
        /// </summary>
        /// <param name="readOnlySpanBatch"></param>
        /// <param name="token">Cancellation token</param>
        /// <returns></returns>
        public async ValueTask <long> EnqueueAndWaitForCommitAsync(IReadOnlySpanBatch readOnlySpanBatch, CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();
            long logicalAddress;
            Task <LinkedCommitInfo> task;

            // Phase 1: wait for commit to memory
            while (true)
            {
                task = CommitTask;
                if (TryEnqueue(readOnlySpanBatch, out logicalAddress))
                {
                    break;
                }
                if (NeedToWait(CommittedUntilAddress, TailAddress))
                {
                    // Wait for *some* commit - failure can be ignored except if the token was signaled (which the caller should handle correctly)
                    try
                    {
                        await task.WithCancellationAsync(token);
                    }
                    catch when(!token.IsCancellationRequested)
                    {
                    }
                }
            }

            // since the task object was read before enqueueing, there is no need for the CommittedUntilAddress >= logicalAddress check like in WaitForCommit
            // Phase 2: wait for commit/flush to storage
            while (true)
            {
                LinkedCommitInfo linkedCommitInfo;
                try
                {
                    linkedCommitInfo = await task.WithCancellationAsync(token);
                }
                catch (CommitFailureException e)
                {
                    linkedCommitInfo = e.LinkedCommitInfo;
                    if (logicalAddress >= linkedCommitInfo.CommitInfo.FromAddress && logicalAddress < linkedCommitInfo.CommitInfo.UntilAddress)
                    {
                        throw;
                    }
                }
                if (linkedCommitInfo.CommitInfo.UntilAddress < logicalAddress + 1)
                {
                    task = linkedCommitInfo.NextTask;
                }
                else
                {
                    break;
                }
            }

            return(logicalAddress);
        }
예제 #3
0
        /// <summary>
        /// Enqueue batch of entries to log in memory (async) - completes after entry is
        /// appended to memory, NOT committed to storage.
        /// </summary>
        /// <param name="readOnlySpanBatch">Batch to enqueue</param>
        /// <param name="token">Cancellation token</param>
        /// <returns></returns>
        public ValueTask <long> EnqueueAsync(IReadOnlySpanBatch readOnlySpanBatch, CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();
            if (TryEnqueue(readOnlySpanBatch, out long address))
            {
                return(new ValueTask <long>(address));
            }

            return(SlowEnqueueAsync(this, readOnlySpanBatch, token));
        }
예제 #4
0
        /// <summary>
        /// Enqueue batch of entries to log (in memory) - no guarantee of flush/commit
        /// </summary>
        /// <param name="readOnlySpanBatch">Batch of entries to be enqueued to log</param>
        /// <returns>Logical address of added entry</returns>
        public long Enqueue(IReadOnlySpanBatch readOnlySpanBatch)
        {
            long logicalAddress;

            while (!TryEnqueue(readOnlySpanBatch, out logicalAddress))
            {
                ;
            }
            return(logicalAddress);
        }
        /// <summary>
        /// Append batch of entries to log (async) - completes after batch is committed to storage.
        /// Does NOT itself issue flush!
        /// </summary>
        /// <param name="readOnlySpanBatch"></param>
        /// <returns></returns>
        public async ValueTask <long> EnqueueAndWaitForCommitAsync(IReadOnlySpanBatch readOnlySpanBatch)
        {
            long logicalAddress;
            Task <LinkedCommitInfo> task;

            // Phase 1: wait for commit to memory
            while (true)
            {
                task = CommitTask;
                if (TryEnqueue(readOnlySpanBatch, out logicalAddress))
                {
                    break;
                }
                if (NeedToWait(CommittedUntilAddress, TailAddress))
                {
                    // Wait for *some* commit - failure can be ignored
                    try
                    {
                        await task;
                    }
                    catch { }
                }
            }

            // Phase 2: wait for commit/flush to storage
            while (true)
            {
                LinkedCommitInfo linkedCommitInfo;
                try
                {
                    linkedCommitInfo = await task;
                }
                catch (CommitFailureException e)
                {
                    linkedCommitInfo = e.LinkedCommitInfo;
                    if (logicalAddress >= linkedCommitInfo.CommitInfo.FromAddress && logicalAddress < linkedCommitInfo.CommitInfo.UntilAddress)
                    {
                        throw e;
                    }
                }
                if (linkedCommitInfo.CommitInfo.UntilAddress < logicalAddress + 1)
                {
                    task = linkedCommitInfo.NextTask;
                }
                else
                {
                    break;
                }
            }

            return(logicalAddress);
        }
예제 #6
0
        /// <summary>
        /// Append batch of entries to log - spin-waits until entry is committed to storage.
        /// Does NOT itself issue flush!
        /// </summary>
        /// <param name="readOnlySpanBatch"></param>
        /// <returns></returns>
        public long EnqueueAndWaitForCommit(IReadOnlySpanBatch readOnlySpanBatch)
        {
            long logicalAddress;

            while (!TryEnqueue(readOnlySpanBatch, out logicalAddress))
            {
                ;
            }
            while (CommittedUntilAddress < logicalAddress + 1)
            {
                ;
            }
            return(logicalAddress);
        }
        /// <summary>
        /// Enqueue batch of entries to log in memory (async) - completes after entry is
        /// appended to memory, NOT committed to storage.
        /// </summary>
        /// <param name="readOnlySpanBatch"></param>
        /// <returns></returns>
        public async ValueTask <long> EnqueueAsync(IReadOnlySpanBatch readOnlySpanBatch)
        {
            long logicalAddress;

            while (true)
            {
                var task = CommitTask;
                if (TryEnqueue(readOnlySpanBatch, out logicalAddress))
                {
                    break;
                }
                if (NeedToWait(CommittedUntilAddress, TailAddress))
                {
                    // Wait for *some* commit - failure can be ignored
                    try
                    {
                        await task;
                    }
                    catch { }
                }
            }

            return(logicalAddress);
        }
예제 #8
0
 /// <summary>
 /// Try to enqueue batch of entries as a single atomic unit (to memory). Entire
 /// batch needs to fit on one log page.
 /// </summary>
 /// <param name="readOnlySpanBatch">Batch to be appended to log</param>
 /// <param name="logicalAddress">Logical address of first added entry</param>
 /// <returns>Whether the append succeeded</returns>
 public bool TryEnqueue(IReadOnlySpanBatch readOnlySpanBatch, out long logicalAddress)
 {
     return(TryAppend(readOnlySpanBatch, out logicalAddress, out _));
 }