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(); } }
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(); } }
/// <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> /// Compact the log until specified address, moving active records to the tail of the log. BeginAddress is shifted, but the physical log /// is not deleted from disk. Caller is responsible for truncating the physical log on disk by taking a checkpoint or calling Log.Truncate /// </summary> /// <param name="functions">Functions used to manage key-values during compaction</param> /// <param name="cf">User provided compaction functions (see <see cref="ICompactionFunctions{Key, Value}"/>).</param> /// <param name="input">Input for SingleWriter</param> /// <param name="output">Output from SingleWriter; it will be called all records that are moved, before Compact() returns, so the user must supply buffering or process each output completely</param> /// <param name="untilAddress">Compact log until this address</param> /// <param name="compactionType">Compaction type (whether we lookup records or scan log for liveness checking)</param> /// <param name="sessionVariableLengthStructSettings">Session variable length struct settings</param> /// <returns>Address until which compaction was done</returns> internal long Compact <Input, Output, Context, Functions, CompactionFunctions>(Functions functions, CompactionFunctions cf, ref Input input, ref Output output, long untilAddress, CompactionType compactionType, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null) where Functions : IFunctions <Key, Value, Input, Output, Context> where CompactionFunctions : ICompactionFunctions <Key, Value> { return(compactionType switch { CompactionType.Scan => CompactScan <Input, Output, Context, Functions, CompactionFunctions>(functions, cf, ref input, ref output, untilAddress, sessionVariableLengthStructSettings), CompactionType.Lookup => CompactLookup <Input, Output, Context, Functions, CompactionFunctions>(functions, cf, ref input, ref output, untilAddress, sessionVariableLengthStructSettings), _ => throw new FasterException("Invalid compaction type"), });
/// <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="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 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; 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)); }
/// <summary> /// Start a new advanced client session with FASTER. /// </summary> /// <param name="functions">Callback functions</param> /// <param name="sessionId">ID/name of session (auto-generated if not provided)</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> NewAdvancedSession <Input, Output, Context, Functions>(Functions functions, string sessionId = null, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null) where Functions : IAdvancedFunctions <Key, Value, Input, Output, Context> => InternalNewSession <Input, Output, Context, Functions, AdvancedClientSession <Key, Value, Input, Output, Context, Functions> >(functions, sessionId, 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> /// Start a new advanced client session with FASTER. /// For performance reasons, please use FasterKV<Key, Value>.For(functions).NewSession<Functions>(...) instead of this overload. /// </summary> /// <param name="functions">Callback functions</param> /// <param name="sessionId">ID/name of session (auto-generated if not provided)</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> > NewSession <Input, Output, Context>(IAdvancedFunctions <Key, Value, Input, Output, Context> functions, string sessionId = null, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null) { return(NewAdvancedSession <Input, Output, Context, IAdvancedFunctions <Key, Value, Input, Output, Context> >(functions, sessionId, threadAffinitized, sessionVariableLengthStructSettings)); }
/// <summary> /// Start a new advanced client session with FASTER. /// </summary> /// <param name="sessionId">ID/name of session (auto-generated if not provided)</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, Functions> NewSession <Functions>(string sessionId = null, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null) where Functions : IAdvancedFunctions <Key, Value, Input, Output, Context> { if (_functions == null) { throw new FasterException("Functions not provided for session"); } return(_fasterKV.NewAdvancedSession <Input, Output, Context, Functions>((Functions)_functions, sessionId, threadAffinitized, sessionVariableLengthStructSettings)); }
/// <summary> /// Start a new advanced client session with FASTER. /// </summary> /// <param name="functions">Callback functions</param> /// <param name="sessionId">ID/name of session (auto-generated if not provided)</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, Functions> NewSession <Functions>(Functions functions, string sessionId = null, bool threadAffinitized = false, SessionVariableLengthStructSettings <Value, Input> sessionVariableLengthStructSettings = null) where Functions : IAdvancedFunctions <Key, Value, Input, Output, Context> { return(_fasterKV.NewAdvancedSession <Input, Output, Context, Functions>(functions, sessionId, 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> /// Start a new client session with FASTER. /// </summary> /// <param name="functions">Callback functions</param> /// <param name="sessionId">ID/name of session (auto-generated if not provided)</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> NewSession <Input, Output, Context, Functions>(Functions functions, string sessionId = null, 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(); } if (sessionId == null) { sessionId = Guid.NewGuid().ToString(); } var ctx = new FasterExecutionContext <Input, Output, Context>(); InitContext(ctx, sessionId); var prevCtx = new FasterExecutionContext <Input, Output, Context>(); InitContext(prevCtx, sessionId); prevCtx.version--; ctx.prevCtx = prevCtx; if (_activeSessions == null) { Interlocked.CompareExchange(ref _activeSessions, new Dictionary <string, IClientSession>(), null); } var session = new ClientSession <Key, Value, Input, Output, Context, Functions>(this, ctx, functions, !threadAffinitized, sessionVariableLengthStructSettings); lock (_activeSessions) _activeSessions.Add(sessionId, session); return(session); }