Пример #1
0
        /// <summary>
        /// Issue completion callback if needed, for the given context's prevCtx
        /// </summary>
        internal void IssueCompletionCallback <Input, Output, Context, FasterSession>(FasterExecutionContext <Input, Output, Context> ctx, FasterSession fasterSession)
            where FasterSession : IFasterSession
        {
            CommitPoint commitPoint = default;

            if (ctx.prevCtx.excludedSerialNos != null)
            {
                lock (ctx.prevCtx)
                {
                    if (ctx.prevCtx.serialNum != -1)
                    {
                        commitPoint = new CommitPoint
                        {
                            UntilSerialNo     = ctx.prevCtx.serialNum,
                            ExcludedSerialNos = ctx.prevCtx.excludedSerialNos
                        };
                        ctx.prevCtx.excludedSerialNos = null;
                    }
                }
                if (commitPoint.ExcludedSerialNos != null)
                {
                    fasterSession?.CheckpointCompletionCallback(ctx.guid, commitPoint);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Wait for commit of all operations completed until the current point in session.
        /// Does not itself issue checkpoint/commits.
        /// </summary>
        /// <returns></returns>
        public async ValueTask WaitForCommitAsync(CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();

            // Complete all pending operations on session
            await CompletePendingAsync(token : token);

            var         task             = fht.CheckpointTask;
            CommitPoint localCommitPoint = LatestCommitPoint;

            if (localCommitPoint.UntilSerialNo >= ctx.serialNum && localCommitPoint.ExcludedSerialNos?.Count == 0)
            {
                return;
            }

            while (true)
            {
                await task.WithCancellationAsync(token);

                Refresh();

                task             = fht.CheckpointTask;
                localCommitPoint = LatestCommitPoint;
                if (localCommitPoint.UntilSerialNo >= ctx.serialNum && localCommitPoint.ExcludedSerialNos?.Count == 0)
                {
                    break;
                }
            }
        }
Пример #3
0
        internal CommitPoint InternalContinue <Input, Output, Context>(string guid, out FasterExecutionContext <Input, Output, Context> ctx)
        {
            ctx = null;

            if (_recoveredSessions != null)
            {
                if (_recoveredSessions.TryGetValue(guid, out _))
                {
                    // We have recovered the corresponding session.
                    // Now obtain the session by first locking the rest phase
                    var currentState = SystemState.Copy(ref systemState);
                    if (currentState.phase == Phase.REST)
                    {
                        var intermediateState = SystemState.MakeIntermediate(currentState);
                        if (MakeTransition(currentState, intermediateState))
                        {
                            // No one can change from REST phase
                            if (_recoveredSessions.TryRemove(guid, out CommitPoint cp))
                            {
                                // We have atomically removed session details.
                                // No one else can continue this session
                                ctx = new FasterExecutionContext <Input, Output, Context>();
                                InitContext(ctx, guid);
                                ctx.prevCtx = new FasterExecutionContext <Input, Output, Context>();
                                InitContext(ctx.prevCtx, guid);
                                ctx.prevCtx.version--;
                                ctx.serialNum = cp.UntilSerialNo;
                            }
                            else
                            {
                                // Someone else continued this session
                                cp = new CommitPoint {
                                    UntilSerialNo = -1
                                };
                                Debug.WriteLine("Session already continued by another thread!");
                            }

                            MakeTransition(intermediateState, currentState);
                            return(cp);
                        }
                    }

                    // Need to try again when in REST
                    Debug.WriteLine("Can continue only in REST phase");
                    return(new CommitPoint {
                        UntilSerialNo = -1
                    });
                }
            }

            Debug.WriteLine("No recovered sessions!");
            return(new CommitPoint {
                UntilSerialNo = -1
            });
        }
Пример #4
0
 internal ClientSession(
     FasterKV<Key, Value, Input, Output, Context, Functions> fht,
     FasterKV<Key, Value, Input, Output, Context, Functions>.FasterExecutionContext ctx,
     bool supportAsync)
 {
     this.fht = fht;
     this.ctx = ctx;
     this.supportAsync = supportAsync;
     LatestCommitPoint = new CommitPoint { UntilSerialNo = -1, ExcludedSerialNos = null };
     // Session runs on a single thread
     if (!supportAsync)
         UnsafeResumeThread();
 }
Пример #5
0
        /// <inheritdoc />
        public virtual void OnThreadState <Key, Value, Input, Output, Context, FasterSession>(
            SystemState current,
            SystemState prev, FasterKV <Key, Value> faster,
            FasterKV <Key, Value> .FasterExecutionContext <Input, Output, Context> ctx,
            FasterSession fasterSession,
            List <ValueTask> valueTasks,
            CancellationToken token = default)
            where Key : new()
            where Value : new()
            where FasterSession : IFasterSession
        {
            if (current.phase != Phase.PERSISTENCE_CALLBACK)
            {
                return;
            }

            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
                        fasterSession?.CheckpointCompletionCallback(ctx.guid, commitPoint);

                        // Set to null to indicate already called (for re-entering sessions)
                        ctx.prevCtx.excludedSerialNos = null;
                    }

                    ctx.prevCtx.markers[EpochPhaseIdx.CheckpointCompletionCallback] = true;
                }

                faster.epoch.Mark(EpochPhaseIdx.CheckpointCompletionCallback, current.version);
            }

            if (faster.epoch.CheckIsComplete(EpochPhaseIdx.CheckpointCompletionCallback, current.version))
            {
                faster.GlobalStateMachineStep(current);
            }
        }
Пример #6
0
        internal ClientSession(
            FasterKV <Key, Value> fht,
            FasterKV <Key, Value> .FasterExecutionContext <Input, Output, Context> ctx,
            Functions functions,
            bool supportAsync,
            SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
        {
            this.fht          = fht;
            this.ctx          = ctx;
            this.functions    = functions;
            SupportAsync      = supportAsync;
            LatestCommitPoint = new CommitPoint {
                UntilSerialNo = -1, ExcludedSerialNos = null
            };
            FasterSession = new AsyncFasterSession(this);

            this.variableLengthStruct = sessionVariableLengthStructSettings?.valueLength;
            if (this.variableLengthStruct == default)
            {
                if (fht.hlog is VariableLengthBlittableAllocator <Key, Value> allocator)
                {
                    Debug.WriteLine("Warning: Session did not specify Input-specific functions for variable-length values via IVariableLengthStruct<Value, Input>");
                    this.variableLengthStruct = new DefaultVariableLengthStruct <Value, Input>(allocator.ValueLength);
                }
            }
            else
            {
                if (!(fht.hlog is VariableLengthBlittableAllocator <Key, Value>))
                {
                    Debug.WriteLine("Warning: Session param of variableLengthStruct provided for non-varlen allocator");
                }
            }

            this.inputVariableLengthStruct = sessionVariableLengthStructSettings?.inputLength;

            // Session runs on a single thread
            if (!supportAsync)
            {
                UnsafeResumeThread();
            }
        }
Пример #7
0
 /// <inheritdoc/>
 public virtual void CheckpointCompletionCallback(int sessionID, string sessionName, CommitPoint commitPoint)
 {
 }
Пример #8
0
 public void CheckpointCompletionCallback(int sessionID, string sessionName, CommitPoint commitPoint)
 {
     _clientSession.functions.CheckpointCompletionCallback(sessionID, sessionName, commitPoint);
     _clientSession.LatestCommitPoint = commitPoint;
 }
 public void CheckpointCompletionCallback(string sessionId, CommitPoint commitPoint)
 {
 }
Пример #10
0
        /// <summary>
        /// Resume (continue) prior client session with FASTER, used during
        /// recovery from failure.
        /// </summary>
        /// <param name="sessionId">ID/name of previous session to resume</param>
        /// <param name="commitPoint">Prior commit point of durability for session</param>
        /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code. Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
        /// <returns>Session instance</returns>
        public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession(string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false)
        {
            if (!threadAffinitized)
            {
                UseRelaxedCPR();
            }

            commitPoint = InternalContinue(sessionId, out FasterExecutionContext ctx);
            if (commitPoint.UntilSerialNo == -1)
            {
                throw new Exception($"Unable to find session {sessionId} to recover");
            }

            var session = new ClientSession <Key, Value, Input, Output, Context, Functions>(this, ctx, !threadAffinitized);

            if (_activeSessions == null)
            {
                Interlocked.CompareExchange(ref _activeSessions, new Dictionary <string, ClientSession <Key, Value, Input, Output, Context, Functions> >(), null);
            }
            lock (_activeSessions)
                _activeSessions.Add(sessionId, session);
            return(session);
        }
Пример #11
0
        internal ClientSession(
            FasterKV <Key, Value> fht,
            FasterKV <Key, Value> .FasterExecutionContext <Input, Output, Context> ctx,
            Functions functions,
            bool supportAsync,
            SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
        {
            this.fht          = fht;
            this.ctx          = ctx;
            this.functions    = functions;
            SupportAsync      = supportAsync;
            LatestCommitPoint = new CommitPoint {
                UntilSerialNo = -1, ExcludedSerialNos = null
            };
            FasterSession = new AsyncFasterSession(this);

            this.variableLengthStruct = sessionVariableLengthStructSettings?.valueLength;
            if (this.variableLengthStruct == default)
            {
                UpdateVarlen(ref this.variableLengthStruct);

                if ((this.variableLengthStruct == default) && (fht.hlog is VariableLengthBlittableAllocator <Key, Value> allocator))
                {
                    Debug.WriteLine("Warning: Session did not specify Input-specific functions for variable-length values via IVariableLengthStruct<Value, Input>");
                    this.variableLengthStruct = new DefaultVariableLengthStruct <Value, Input>(allocator.ValueLength);
                }
            }
            else
            {
                if (!(fht.hlog is VariableLengthBlittableAllocator <Key, Value>))
                {
                    Debug.WriteLine("Warning: Session param of variableLengthStruct provided for non-varlen allocator");
                }
            }

            this.inputVariableLengthStruct = sessionVariableLengthStructSettings?.inputLength;

            if (inputVariableLengthStruct == default)
            {
                if (typeof(Input) == typeof(SpanByte))
                {
                    inputVariableLengthStruct = new SpanByteVarLenStruct() as IVariableLengthStruct <Input>;
                }
                else if (typeof(Input).IsGenericType && (typeof(Input).GetGenericTypeDefinition() == typeof(Memory <>)) && Utility.IsBlittableType(typeof(Input).GetGenericArguments()[0]))
                {
                    var    m = typeof(MemoryVarLenStruct <>).MakeGenericType(typeof(Input).GetGenericArguments());
                    object o = Activator.CreateInstance(m);
                    inputVariableLengthStruct = o as IVariableLengthStruct <Input>;
                }
                else if (typeof(Input).IsGenericType && (typeof(Input).GetGenericTypeDefinition() == typeof(ReadOnlyMemory <>)) && Utility.IsBlittableType(typeof(Input).GetGenericArguments()[0]))
                {
                    var    m = typeof(ReadOnlyMemoryVarLenStruct <>).MakeGenericType(typeof(Input).GetGenericArguments());
                    object o = Activator.CreateInstance(m);
                    inputVariableLengthStruct = o as IVariableLengthStruct <Input>;
                }
            }

            // Session runs on a single thread
            if (!supportAsync)
            {
                UnsafeResumeThread();
            }
        }
Пример #12
0
 public void CheckpointCompletionCallback(string guid, CommitPoint commitPoint)
 {
     _clientSession.functions.CheckpointCompletionCallback(guid, commitPoint);
     _clientSession.LatestCommitPoint = commitPoint;
 }
Пример #13
0
            /// <summary>
            /// Resume (continue) prior client session with FASTER, used during
            /// recovery from failure.
            /// </summary>
            /// <param name="sessionId">ID/name of previous session to resume</param>
            /// <param name="commitPoint">Prior commit point of durability for session</param>
            /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code.
            ///     Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
            /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
            /// <returns>Session instance</returns>
            public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Functions>(string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false,
                                                                                                           SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
                where Functions : IFunctions <Key, Value, Input, Output, Context>
            {
                if (_functions == null)
                {
                    throw new FasterException("Functions not provided for session");
                }

                return(_fasterKV.ResumeSession <Input, Output, Context, Functions>((Functions)_functions, sessionId, out commitPoint, threadAffinitized, sessionVariableLengthStructSettings));
            }
Пример #14
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER; used during recovery from failure.
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionId">ID/name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code.
 ///     Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
 /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
 /// <returns>Session instance</returns>
 public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Functions>(Functions functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false,
                                                                                                SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings     = null)
     where Functions : IFunctions <Key, Value, Input, Output, Context>
 {
     return(_fasterKV.ResumeSession <Input, Output, Context, Functions>(functions, sessionId, out commitPoint, threadAffinitized, sessionVariableLengthStructSettings));
 }
Пример #15
0
        private TSession InternalResumeSession <Input, Output, Context, Functions, TSession>(Functions functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized,
                                                                                             Func <FasterExecutionContext <Input, Output, Context>, TSession> sessionCreator)
            where TSession : IClientSession
        {
            if (functions == null)
            {
                throw new ArgumentNullException(nameof(functions));
            }

            if (!threadAffinitized)
            {
                UseRelaxedCPR();
            }

            commitPoint = InternalContinue <Input, Output, Context>(sessionId, out var ctx);
            if (commitPoint.UntilSerialNo == -1)
            {
                throw new Exception($"Unable to find session {sessionId} to recover");
            }

            var session = sessionCreator(ctx);

            if (_activeSessions == null)
            {
                Interlocked.CompareExchange(ref _activeSessions, new Dictionary <string, IClientSession>(), null);
            }
            lock (_activeSessions)
                _activeSessions.Add(sessionId, session);
            return(session);
        }
Пример #16
0
        /// <summary>
        /// Resume (continue) prior client session with FASTER using advanced functions; used during recovery from failure.
        /// </summary>
        /// <param name="functions">Callback functions</param>
        /// <param name="sessionId">ID/name of previous session to resume</param>
        /// <param name="commitPoint">Prior commit point of durability for session</param>
        /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code.
        ///     Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
        /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
        /// <returns>Session instance</returns>

        internal AdvancedClientSession <Key, Value, Input, Output, Context, Functions> ResumeAdvancedSession <Input, Output, Context, Functions>(Functions functions, string sessionId, out CommitPoint commitPoint,
                                                                                                                                                 bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
            where Functions : IAdvancedFunctions <Key, Value, Input, Output, Context>
        {
            return(InternalResumeSession <Input, Output, Context, Functions, AdvancedClientSession <Key, Value, Input, Output, Context, Functions> >(functions, sessionId, out commitPoint, threadAffinitized,
                                                                                                                                                     ctx => new AdvancedClientSession <Key, Value, Input, Output, Context, Functions>(this, ctx, functions, !threadAffinitized, sessionVariableLengthStructSettings)));
        }
Пример #17
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER using advanced functions; used during recovery from failure.
 /// For performance reasons this overload is not recommended if functions is value type (struct).
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionId">ID/name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code.
 ///     Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
 /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
 /// <returns>Session instance</returns>
 public AdvancedClientSession <Key, Value, Input, Output, Context, IAdvancedFunctions <Key, Value, Input, Output, Context> > ResumeSession <Input, Output, Context>(IAdvancedFunctions <Key, Value, Input, Output, Context> functions,
                                                                                                                                                                    string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
 {
     return(ResumeAdvancedSession <Input, Output, Context, IAdvancedFunctions <Key, Value, Input, Output, Context> >(functions, sessionId, out commitPoint, threadAffinitized, sessionVariableLengthStructSettings));
 }
Пример #18
0
        /// <summary>
        /// Resume (continue) prior client session with FASTER, used during
        /// recovery from failure.
        /// </summary>
        /// <param name="functions">Callback functions</param>
        /// <param name="sessionId">ID/name of previous session to resume</param>
        /// <param name="commitPoint">Prior commit point of durability for session</param>
        /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code. Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
        /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
        /// <returns>Session instance</returns>

        public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Input, Output, Context, Functions>(Functions functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null)
            where Functions : IFunctions <Key, Value, Input, Output, Context>
        {
            if (functions == null)
            {
                throw new ArgumentNullException(nameof(functions));
            }

            if (!threadAffinitized)
            {
                UseRelaxedCPR();
            }

            commitPoint = InternalContinue <Input, Output, Context>(sessionId, out var ctx);
            if (commitPoint.UntilSerialNo == -1)
            {
                throw new Exception($"Unable to find session {sessionId} to recover");
            }


            var session = new ClientSession <Key, Value, Input, Output, Context, Functions>(this, ctx, functions, !threadAffinitized, sessionVariableLengthStructSettings);

            if (_activeSessions == null)
            {
                Interlocked.CompareExchange(ref _activeSessions, new Dictionary <string, IClientSession>(), null);
            }
            lock (_activeSessions)
                _activeSessions.Add(sessionId, session);
            return(session);
        }
Пример #19
0
        /// <summary>
        /// Steps the thread's local state machine. Threads catch up to the current global state and performs
        /// necessary actions associated with the state as defined by the current state machine
        /// </summary>
        /// <param name="ctx">null if calling without a context (e.g. waiting on a checkpoint)</param>
        /// <param name="fasterSession">Faster session.</param>
        /// <param name="valueTasks">Return list of tasks that caller needs to await, to continue checkpointing</param>
        /// <param name="token">Cancellation token</param>
        /// <returns></returns>
        private void ThreadStateMachineStep <Input, Output, Context, FasterSession>(
            FasterExecutionContext <Input, Output, Context> ctx,
            FasterSession fasterSession,
            List <ValueTask> valueTasks,
            CancellationToken token = default)
            where FasterSession : IFasterSession
        {
            #region Capture current (non-intermediate) system state
            var currentTask = currentSyncStateMachine;
            var targetState = SystemState.Copy(ref systemState);
            SystemState.RemoveIntermediate(ref targetState);

            while (currentSyncStateMachine != currentTask)
            {
                currentTask = currentSyncStateMachine;
                targetState = SystemState.Copy(ref systemState);
                SystemState.RemoveIntermediate(ref targetState);
            }
            #endregion

            var currentState     = ctx == null ? targetState : SystemState.Make(ctx.phase, ctx.version);
            var targetStartState = StartOfCurrentCycle(targetState);

            #region Get returning thread to start of current cycle, issuing completion callbacks if needed
            if (ctx != null)
            {
                if (ctx.version < targetStartState.version)
                {
                    // Issue CPR callback for full session
                    if (ctx.serialNum != -1)
                    {
                        List <long> excludedSerialNos = new List <long>();
                        foreach (var v in ctx.ioPendingRequests.Values)
                        {
                            excludedSerialNos.Add(v.serialNum);
                        }
                        foreach (var v in ctx.retryRequests)
                        {
                            excludedSerialNos.Add(v.serialNum);
                        }

                        var commitPoint = new CommitPoint
                        {
                            UntilSerialNo     = ctx.serialNum,
                            ExcludedSerialNos = excludedSerialNos
                        };

                        // Thread local action
                        fasterSession?.CheckpointCompletionCallback(ctx.guid, commitPoint);
                    }
                }
                if ((ctx.version == targetStartState.version) && (ctx.phase < Phase.REST))
                {
                    IssueCompletionCallback(ctx, fasterSession);
                }
            }
            #endregion

            // No state machine associated with target, or target is in REST phase:
            // we can directly fast forward session to target state
            if (currentTask == null || targetState.phase == Phase.REST)
            {
                if (ctx != null)
                {
                    ctx.phase   = targetState.phase;
                    ctx.version = targetState.version;
                }
                return;
            }

            #region Jump on and execute current state machine
            // We start at either the start point or our previous position in the state machine.
            // If we are calling from somewhere other than an execution thread (e.g. waiting on
            // a checkpoint to complete on a client app thread), we start at current system state
            var threadState =
                ctx == null ? targetState :
                FastForwardToCurrentCycle(currentState, targetStartState);

            var previousState = threadState;
            do
            {
                Debug.Assert(
                    (threadState.version < targetState.version) ||
                    (threadState.version == targetState.version &&
                     (threadState.phase <= targetState.phase || currentTask is IndexSnapshotStateMachine)
                    ));

                currentTask.OnThreadEnteringState(threadState, previousState, this, ctx, fasterSession, valueTasks, token);

                if (ctx != null)
                {
                    ctx.phase   = threadState.phase;
                    ctx.version = threadState.version;
                }

                previousState.word = threadState.word;
                threadState        = currentTask.NextState(threadState);
                if (systemState.word != targetState.word)
                {
                    var tmp = SystemState.Copy(ref systemState);
                    if (currentSyncStateMachine == currentTask)
                    {
                        targetState = tmp;
                        SystemState.RemoveIntermediate(ref targetState);
                    }
                }
            } while (previousState.word != targetState.word);
            #endregion

            return;
        }
Пример #20
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();
            }
        }
Пример #21
0
 public void CheckpointCompletionCallback(string guid, CommitPoint commitPoint)
 {
     _fasterKV._functions.CheckpointCompletionCallback(guid, commitPoint);
 }
Пример #22
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER, used during
 /// recovery from failure.
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionId">ID/name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code. Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
 /// <returns>Session instance</returns>
 public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Functions>(Functions functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false)
     where Functions : IFunctions <Key, Value, Input, Output, Context>
 {
     return(_fasterKV.ResumeSession <Input, Output, Context, Functions>(functions, sessionId, out commitPoint, threadAffinitized));
 }
Пример #23
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER, used during
 /// recovery from failure.
 /// For performance reasons this overload is not recommended if functions is value type (struct).
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionId">ID/name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code. Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
 /// <param name="variableLengthStruct">Implementation of input-specific length computation for variable-length structs</param>
 /// <returns>Session instance</returns>
 public ClientSession <Key, Value, Input, Output, Context, IFunctions <Key, Value, Input, Output, Context> > ResumeSession <Input, Output, Context>(IFunctions <Key, Value, Input, Output, Context> functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false, IVariableLengthStruct <Value, Input> variableLengthStruct = null)
 {
     return(ResumeSession <Input, Output, Context, IFunctions <Key, Value, Input, Output, Context> >(functions, sessionId, out commitPoint, threadAffinitized, variableLengthStruct));
 }
Пример #24
0
 /// <inheritdoc />
 public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession(string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false)
 => _fasterKV.ResumeSession <Input, Output, Context, Functions>(_functions, sessionId, out commitPoint, threadAffinitized);
Пример #25
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER; used during recovery from failure.
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionName">Name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
 /// <param name="readFlags">ReadFlags for this session; override those specified at FasterKV level, and may be overridden on individual Read operations</param>
 /// <returns>Session instance</returns>
 public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Functions>(Functions functions, string sessionName, out CommitPoint commitPoint,
                                                                                                SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null, ReadFlags readFlags = ReadFlags.Default)
     where Functions : IFunctions <Key, Value, Input, Output, Context>
 {
     return(_fasterKV.ResumeSession <Input, Output, Context, Functions>(functions, sessionName, out commitPoint, sessionVariableLengthStructSettings, readFlags));
 }
Пример #26
0
            /// <summary>
            /// Resume (continue) prior client session with FASTER, used during
            /// recovery from failure.
            /// </summary>
            /// <param name="sessionName">Name of previous session to resume</param>
            /// <param name="commitPoint">Prior commit point of durability for session</param>
            /// <param name="sessionVariableLengthStructSettings">Session-specific variable-length struct settings</param>
            /// <param name="readFlags">ReadFlags for this session; override those specified at FasterKV level, and may be overridden on individual Read operations</param>
            /// <returns>Session instance</returns>
            public ClientSession <Key, Value, Input, Output, Context, Functions> ResumeSession <Functions>(string sessionName, out CommitPoint commitPoint,
                                                                                                           SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null, ReadFlags readFlags = ReadFlags.Default)
                where Functions : IFunctions <Key, Value, Input, Output, Context>
            {
                if (_functions == null)
                {
                    throw new FasterException("Functions not provided for session");
                }

                return(_fasterKV.ResumeSession <Input, Output, Context, Functions>((Functions)_functions, sessionName, out commitPoint, sessionVariableLengthStructSettings, readFlags));
            }
Пример #27
0
 /// <summary>
 /// Resume (continue) prior client session with FASTER, used during
 /// recovery from failure.
 /// For performance reasons this overload is not recommended if functions is value type (struct).
 /// </summary>
 /// <param name="functions">Callback functions</param>
 /// <param name="sessionId">ID/name of previous session to resume</param>
 /// <param name="commitPoint">Prior commit point of durability for session</param>
 /// <param name="threadAffinitized">For advanced users. Specifies whether session holds the thread epoch across calls. Do not use with async code. Ensure thread calls session Refresh periodically to move the system epoch forward.</param>
 /// <returns>Session instance</returns>
 public ClientSession <Key, Value, Input, Output, Context, IFunctions <Key, Value, Input, Output, Context> > ResumeSession <Input, Output, Context>(IFunctions <Key, Value, Input, Output, Context> functions, string sessionId, out CommitPoint commitPoint, bool threadAffinitized = false)
 {
     return(ResumeSession <Input, Output, Context, IFunctions <Key, Value, Input, Output, Context> >(functions, sessionId, out commitPoint, threadAffinitized));
 }