예제 #1
0
        /// <inheritdoc />
        public override SystemState NextState(SystemState start)
        {
            var result = SystemState.Copy(ref start);

            switch (start.Phase)
            {
            case Phase.REST:
                result.Phase = Phase.PREP_INDEX_CHECKPOINT;
                break;

            case Phase.PREP_INDEX_CHECKPOINT:
                result.Phase = Phase.WAIT_INDEX_ONLY_CHECKPOINT;
                break;

            case Phase.WAIT_INDEX_ONLY_CHECKPOINT:
                result.Phase = Phase.REST;
                break;

            default:
                throw new FasterException("Invalid Enum Argument");
            }

            return(result);
        }
예제 #2
0
        /// <inheritdoc />
        public override SystemState NextState(SystemState start)
        {
            var nextState = SystemState.Copy(ref start);

            switch (start.phase)
            {
            case Phase.REST:
                nextState.phase = Phase.PREPARE_GROW;
                break;

            case Phase.PREPARE_GROW:
                nextState.phase = Phase.IN_PROGRESS_GROW;
                break;

            case Phase.IN_PROGRESS_GROW:
                nextState.phase = Phase.REST;
                break;

            default:
                throw new FasterException("Invalid Enum Argument");
            }

            return(nextState);
        }
예제 #3
0
        private void HandleCheckpointingPhases()
        {
            var previousState = SystemState.Make(threadCtx.phase, threadCtx.version);
            var finalState    = SystemState.Copy(ref _systemState);

            // Don't play around when system state is being changed
            if (finalState.phase == Phase.INTERMEDIATE)
            {
                return;
            }

            // We need to move from previousState to finalState one step at a time
            do
            {
                var currentState = default(SystemState);
                if (previousState.word == finalState.word)
                {
                    currentState.word = previousState.word;
                }
                else
                {
                    currentState = GetNextState(previousState, _checkpointType);
                }

                switch (currentState.phase)
                {
                case Phase.PREP_INDEX_CHECKPOINT:
                {
                    if (!threadCtx.markers[EpochPhaseIdx.PrepareForIndexCheckpt])
                    {
                        if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.PrepareForIndexCheckpt, threadCtx.version))
                        {
                            GlobalMoveToNextCheckpointState(currentState);
                        }
                        threadCtx.markers[EpochPhaseIdx.PrepareForIndexCheckpt] = true;
                    }
                    break;
                }

                case Phase.INDEX_CHECKPOINT:
                {
                    if (_checkpointType == CheckpointType.INDEX_ONLY)
                    {
                        // Reseting the marker for a potential FULL or INDEX_ONLY checkpoint in the future
                        threadCtx.markers[EpochPhaseIdx.PrepareForIndexCheckpt] = false;
                    }

                    if (IsIndexFuzzyCheckpointCompleted())
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.PREPARE:
                {
                    if (!threadCtx.markers[EpochPhaseIdx.Prepare])
                    {
                        // Thread local action
                        AcquireSharedLatchesForAllPendingRequests();

                        var idx = Interlocked.Increment(ref _hybridLogCheckpoint.info.numThreads);
                        idx -= 1;

                        _hybridLogCheckpoint.info.guids[idx] = threadCtx.guid;

                        if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.Prepare, threadCtx.version))
                        {
                            GlobalMoveToNextCheckpointState(currentState);
                        }

                        threadCtx.markers[EpochPhaseIdx.Prepare] = true;
                    }
                    break;
                }

                case Phase.IN_PROGRESS:
                {
                    // Need to be very careful here as threadCtx is changing
                    FasterExecutionContext ctx;
                    if (previousState.phase == Phase.PREPARE)
                    {
                        ctx = threadCtx;
                    }
                    else
                    {
                        ctx = prevThreadCtx;
                    }

                    if (!ctx.markers[EpochPhaseIdx.InProgress])
                    {
                        prevThreadCtx = threadCtx;

                        InitLocalContext(ref threadCtx, prevThreadCtx.guid);

                        if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.InProgress, ctx.version))
                        {
                            GlobalMoveToNextCheckpointState(currentState);
                        }
                        prevThreadCtx.markers[EpochPhaseIdx.InProgress] = true;
                    }
                    break;
                }

                case Phase.WAIT_PENDING:
                {
                    if (!prevThreadCtx.markers[EpochPhaseIdx.WaitPending])
                    {
                        var notify = (prevThreadCtx.ioPendingRequests.Count == 0);
                        notify = notify && (prevThreadCtx.retryRequests.Count == 0);

                        if (notify)
                        {
                            if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.WaitPending, threadCtx.version))
                            {
                                GlobalMoveToNextCheckpointState(currentState);
                            }
                            prevThreadCtx.markers[EpochPhaseIdx.WaitPending] = true;
                        }
                    }
                    break;
                }

                case Phase.WAIT_FLUSH:
                {
                    if (!prevThreadCtx.markers[EpochPhaseIdx.WaitFlush])
                    {
                        var notify = false;
                        if (FoldOverSnapshot)
                        {
                            notify = (hlog.FlushedUntilAddress >= _hybridLogCheckpoint.info.finalLogicalAddress);
                        }
                        else
                        {
                            notify = (_hybridLogCheckpoint.flushed != null) && _hybridLogCheckpoint.flushed.IsSet;
                        }

                        if (_checkpointType == CheckpointType.FULL)
                        {
                            notify = notify && IsIndexFuzzyCheckpointCompleted();
                        }

                        if (notify)
                        {
                            WriteHybridLogContextInfo();

                            if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.WaitFlush, prevThreadCtx.version))
                            {
                                GlobalMoveToNextCheckpointState(currentState);
                            }

                            prevThreadCtx.markers[EpochPhaseIdx.WaitFlush] = true;
                        }
                    }
                    break;
                }

                case Phase.PERSISTENCE_CALLBACK:
                {
                    if (!prevThreadCtx.markers[EpochPhaseIdx.CheckpointCompletionCallback])
                    {
                        // Thread local action
                        functions.CheckpointCompletionCallback(threadCtx.guid, prevThreadCtx.serialNum);

                        if (epoch.MarkAndCheckIsComplete(EpochPhaseIdx.CheckpointCompletionCallback, prevThreadCtx.version))
                        {
                            GlobalMoveToNextCheckpointState(currentState);
                        }

                        prevThreadCtx.markers[EpochPhaseIdx.CheckpointCompletionCallback] = true;
                    }
                    break;
                }

                case Phase.REST:
                {
                    break;
                }

                default:
                    Debug.WriteLine("Error!");
                    break;
                }

                // update thread local variables
                threadCtx.phase   = currentState.phase;
                threadCtx.version = currentState.version;

                previousState.word = currentState.word;
            } while (previousState.word != finalState.word);
        }
예제 #4
0
        private async ValueTask HandleCheckpointingPhasesAsync(FasterExecutionContext ctx, ClientSession <Key, Value, Input, Output, Context, Functions> clientSession, bool async = true, CancellationToken token = default)
        {
            if (async)
            {
                clientSession?.UnsafeResumeThread();
            }

            var finalState = SystemState.Copy(ref _systemState);

            while (finalState.phase == Phase.INTERMEDIATE)
            {
                finalState = SystemState.Copy(ref _systemState);
            }

            var previousState = ctx != null?SystemState.Make(ctx.phase, ctx.version) : finalState;

            // We need to move from previousState to finalState one step at a time
            var currentState = previousState;

            SystemState startState = GetStartState(finalState);

            if ((currentState.version < startState.version) ||
                (currentState.version == startState.version && currentState.phase < startState.phase))
            {
                // Fast-forward to beginning of current checkpoint cycle
                currentState = startState;
            }

            do
            {
                switch (currentState.phase)
                {
                case Phase.PREP_INDEX_CHECKPOINT:
                {
                    if (ctx != null)
                    {
                        if (!ctx.markers[EpochPhaseIdx.PrepareForIndexCheckpt])
                        {
                            ctx.markers[EpochPhaseIdx.PrepareForIndexCheckpt] = true;
                        }
                        epoch.Mark(EpochPhaseIdx.PrepareForIndexCheckpt, currentState.version);
                    }

                    if (epoch.CheckIsComplete(EpochPhaseIdx.PrepareForIndexCheckpt, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.INDEX_CHECKPOINT:
                {
                    if (_checkpointType == CheckpointType.INDEX_ONLY && ctx != null)
                    {
                        // Reseting the marker for a potential FULL or INDEX_ONLY checkpoint in the future
                        ctx.markers[EpochPhaseIdx.PrepareForIndexCheckpt] = false;
                    }

                    if (async && !IsIndexFuzzyCheckpointCompleted())
                    {
                        clientSession?.UnsafeSuspendThread();
                        await IsIndexFuzzyCheckpointCompletedAsync(token);

                        clientSession?.UnsafeResumeThread();
                    }
                    GlobalMoveToNextCheckpointState(currentState);

                    break;
                }

                case Phase.PREPARE:
                {
                    if (ctx != null)
                    {
                        if (!ctx.markers[EpochPhaseIdx.Prepare])
                        {
                            if (!RelaxedCPR)
                            {
                                AcquireSharedLatchesForAllPendingRequests(ctx);
                            }
                            ctx.markers[EpochPhaseIdx.Prepare] = true;
                        }
                        epoch.Mark(EpochPhaseIdx.Prepare, currentState.version);
                    }

                    if (epoch.CheckIsComplete(EpochPhaseIdx.Prepare, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }

                    break;
                }

                case Phase.IN_PROGRESS:
                {
                    if (ctx != null)
                    {
                        // Need to be very careful here as threadCtx is changing
                        FasterExecutionContext _ctx;
                        if (previousState.phase == Phase.IN_PROGRESS)
                        {
                            _ctx = ctx.prevCtx;
                        }
                        else
                        {
                            _ctx = ctx;
                        }

                        if (!_ctx.markers[EpochPhaseIdx.InProgress])
                        {
                            AtomicSwitch(ctx, ctx.prevCtx, _ctx.version);
                            InitContext(ctx, ctx.prevCtx.guid, ctx.prevCtx.serialNum);

                            // Has to be prevCtx, not ctx
                            ctx.prevCtx.markers[EpochPhaseIdx.InProgress] = true;
                        }

                        epoch.Mark(EpochPhaseIdx.InProgress, currentState.version);
                    }

                    // Has to be prevCtx, not ctx
                    if (epoch.CheckIsComplete(EpochPhaseIdx.InProgress, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.WAIT_PENDING:
                {
                    if (ctx != null)
                    {
                        if (!ctx.prevCtx.markers[EpochPhaseIdx.WaitPending])
                        {
                            var notify = (ctx.prevCtx.ioPendingRequests.Count == 0);
                            notify = notify && (ctx.prevCtx.retryRequests.Count == 0);

                            if (notify)
                            {
                                ctx.prevCtx.markers[EpochPhaseIdx.WaitPending] = true;
                            }
                            else
                            {
                                break;
                            }
                        }
                        epoch.Mark(EpochPhaseIdx.WaitPending, currentState.version);
                    }

                    if (epoch.CheckIsComplete(EpochPhaseIdx.WaitPending, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.WAIT_FLUSH:
                {
                    if (ctx == null || !ctx.prevCtx.markers[EpochPhaseIdx.WaitFlush])
                    {
                        bool notify;

                        if (FoldOverSnapshot)
                        {
                            notify = (hlog.FlushedUntilAddress >= _hybridLogCheckpoint.info.finalLogicalAddress);
                        }
                        else
                        {
                            notify = (_hybridLogCheckpoint.flushedSemaphore != null) && _hybridLogCheckpoint.flushedSemaphore.CurrentCount > 0;
                        }

                        if (async && !notify)
                        {
                            Debug.Assert(_hybridLogCheckpoint.flushedSemaphore != null);
                            clientSession?.UnsafeSuspendThread();
                            await _hybridLogCheckpoint.flushedSemaphore.WaitAsync(token);

                            clientSession?.UnsafeResumeThread();

                            _hybridLogCheckpoint.flushedSemaphore.Release();

                            notify = true;
                        }

                        if (_checkpointType == CheckpointType.FULL)
                        {
                            notify = notify && IsIndexFuzzyCheckpointCompleted();

                            if (async && !notify)
                            {
                                clientSession?.UnsafeSuspendThread();
                                await IsIndexFuzzyCheckpointCompletedAsync(token);

                                clientSession?.UnsafeResumeThread();

                                notify = true;
                            }
                        }

                        if (notify)
                        {
                            if (ctx != null)
                            {
                                ctx.prevCtx.markers[EpochPhaseIdx.WaitFlush] = true;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (ctx != null)
                    {
                        epoch.Mark(EpochPhaseIdx.WaitFlush, currentState.version);
                    }

                    if (epoch.CheckIsComplete(EpochPhaseIdx.WaitFlush, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.PERSISTENCE_CALLBACK:
                {
                    if (ctx != null)
                    {
                        if (!ctx.prevCtx.markers[EpochPhaseIdx.CheckpointCompletionCallback])
                        {
                            if (ctx.prevCtx.serialNum != -1)
                            {
                                var commitPoint = new CommitPoint
                                {
                                    UntilSerialNo     = ctx.prevCtx.serialNum,
                                    ExcludedSerialNos = ctx.prevCtx.excludedSerialNos
                                };

                                // Thread local action
                                functions.CheckpointCompletionCallback(ctx.guid, commitPoint);
                                if (clientSession != null)
                                {
                                    clientSession.LatestCommitPoint = commitPoint;
                                }
                            }
                            ctx.prevCtx.markers[EpochPhaseIdx.CheckpointCompletionCallback] = true;
                        }
                        epoch.Mark(EpochPhaseIdx.CheckpointCompletionCallback, currentState.version);
                    }
                    if (epoch.CheckIsComplete(EpochPhaseIdx.CheckpointCompletionCallback, currentState.version))
                    {
                        GlobalMoveToNextCheckpointState(currentState);
                    }
                    break;
                }

                case Phase.REST:
                {
                    break;
                }

                default:
                    throw new FasterException("Invalid state found during checkpointing");
                }

                if (ctx != null)
                {
                    // update thread local variables
                    ctx.phase   = currentState.phase;
                    ctx.version = currentState.version;
                }
                previousState.word = currentState.word;
                currentState       = GetNextState(currentState, _checkpointType);
            } while (previousState.word != finalState.word);

            if (async)
            {
                clientSession?.UnsafeSuspendThread();
            }
        }