/// <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); } } }
/// <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; } } }
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 }); }
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(); }
/// <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); } }
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(); } }
/// <inheritdoc/> public virtual void CheckpointCompletionCallback(int sessionID, string sessionName, CommitPoint commitPoint) { }
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) { }
/// <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); }
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(); } }
public void CheckpointCompletionCallback(string guid, CommitPoint commitPoint) { _clientSession.functions.CheckpointCompletionCallback(guid, commitPoint); _clientSession.LatestCommitPoint = commitPoint; }
/// <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)); }
/// <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)); }
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); }
/// <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))); }
/// <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)); }
/// <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); }
/// <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; }
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(); } }
public void CheckpointCompletionCallback(string guid, CommitPoint commitPoint) { _fasterKV._functions.CheckpointCompletionCallback(guid, commitPoint); }
/// <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)); }
/// <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)); }
/// <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);
/// <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)); }
/// <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)); }
/// <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)); }